You're building the kind of portal that starts as a "public informational site" and quietly evolves into an ecosystem: content publishing, space booking, events, ticketing, tenders, publications, internal dashboards, and eventually user accounts with personalised services. The typical mistake is pretending this is "just a website" until it becomes a small country with its own borders, passports, contraband, and corruption.
This post is a map of the decisions that actually matter when you want a modern, headless, React-based portal with multiple modules and multiple backoffice teams maintaining different parts of it. The scenario is deliberately anonymised, but it's very real: a mid-sized organisation (30–50 staff) planning a phased rollout of a portal with multiple services and future integrations.
1. The One Architectural Decision That Shapes Everything: One Frontend, Many Services
Yes, it makes sense to have a central frontend (single portal UI) with each module as a separate backend service, often in separate containers, behind a single domain.
But here's the nuance people miss:
Option A: Microservices From Day One
Separate services from the start (content, booking, events, tenders, etc.). Fast parallel development once the plumbing exists. Also fast parallel chaos if you don't lock down identity, contracts, and observability early.
Option B: Modular Monolith First, Split Later
One backend codebase, clean internal modules, strict boundaries. Easier to ship Phase 1 quickly without building a platform team on day three. Later you peel off modules into services when load, ownership, or risk demands it.
The Pragmatic Approach That Usually Wins
Start with a platform skeleton that supports service separation, even if you don't fully use it immediately:
- Central frontend
- One "core API" service initially (or two: content API + forms/workflows API)
- A real Identity Provider (IdP) from day one
- A gateway/reverse proxy layer and clean routing
Then split services when a module becomes "its own product".
This matches the phased reality of most large portal projects: foundation and design system first, then core pages, then interactive modules like spaces, museums, and events, and only later e-shop and advanced features.
2. Decide These Early or Pay the Tax Forever
These are the decisions you do not want to "figure out later".
2.1 Identity Model: Who Are Users, Really?
You will have at least these user worlds:
- Public visitors (no login)
- Staff editors (content maintenance)
- Operational staff (approve requests, manage schedules, publish tenders)
- Future customers (ticket buyers, event registrants, donors)
- External partners (speakers, vendors, suppliers)
If you don't model this cleanly, you end up with "everyone is an admin because deadlines".
2.2 Tenant Boundaries: Single Org Now, Multi-Tenant Later?
Even if you are not multi-tenant today, decide whether you might be later. Because it impacts:
- User and role scoping
- Data separation
- URL structure
- Permission design
You can build "single-tenant with org-like structure" and still be upgradeable.
2.3 Authorisation Model: RBAC Is Not Enough by Itself
You want RBAC (roles) plus resource scoping:
"Content Editor" is not a permission. It's a role. The real question is: editor of what?
- Only Museums?
- Only Tenders?
- Only a specific Museum?
So you need something like:
- Roles: Editor, Publisher, Reviewer, Approver, Finance, Admin
- Scopes: module-level (Museums, Spaces, Tenders)
- Resource ownership rules: per museum, per location, per activity type
You can implement scoping in your API layer even if the IdP is role-based.
2.4 Content Modelling: What Is "Content" vs "Transaction"?
This is where systems go to die.
- Content: pages, announcements, museum entries, tender posts, publication entries
- Transactional: bookings, registrations, ticket sales, applications, approvals, payments
Content belongs in a CMS. Transactions belong in services with databases and workflows.
Mixing both is normal early on, but your architecture must keep them separate.
3. Open-Source Identity and Access: Production-Grade, No Forced SaaS
The Default Serious Answer: Keycloak
- Mature, widely deployed, well understood
- OIDC and SAML support
- Good admin UI, realms, clients, roles, groups, MFA, federation options
- Runs cleanly in Docker Compose
For most use cases, Keycloak is the "boring and correct" choice.
Strong Alternatives
- Authentik: friendlier UX, good for SSO and app integrations, solid option
- Ory (Kratos/Hydra): very powerful, very composable, but more engineering work. Great if you want to build a custom auth platform
- Zitadel: strong product, but check licensing — what is fully OSS versus "source-available" depends on edition
If your priority is "get reliable auth done and move on with your life", pick Keycloak.
4. Headless CMS: Directus, and Why It Fits
Directus gives you:
- Content collections and relationships
- Role and permission system for backoffice editors
- Admin UI for non-developers
- API (REST + GraphQL) out of the box
- Easy container deployment
Most importantly: it allows you to get the "content-heavy public portal" online quickly, while your transactional services mature behind it.
The Architectural Sweet Spot
Directus as the content brain. Separate services for:
- Booking requests and approvals
- Event registrations
- Ticketing integration
- Tender submissions or vendor workflows
- Future e-shop
So the portal ships early as "rich content", and you progressively add services.
5. Next.js, Tailwind, and Component Libraries
There's a myth that "Next.js doesn't have Tailwind". Next.js doesn't include Tailwind, but it supports it perfectly. You install it in minutes.
A sane frontend stack:
- Next.js (App Router)
- Tailwind CSS
- A component system: shadcn/ui (common, flexible) or Material UI for heavyweight enterprise UI
- Design tokens (colours, spacing, typography) defined once
Design System Governance
You will have multiple people maintaining pages and modules. If you do not enforce:
- Tokenised colours
- Typography scale
- Spacing scale
- Button and form standards
- Layout primitives
…you will get a portal that looks like it was assembled from unrelated websites during a storm.
6. Docker Compose: Yes, but Be Intentional
Docker Compose is perfect for local development, early staging, and single VPS deployment. But make it "future migration friendly":
- One network
- Clean environment variables
- Proper secrets handling (not in git)
- Healthchecks
- Structured logs
A typical early deployment layout:
- frontend (Next.js)
- directus
- db (Postgres)
- redis (cache, queues later)
- keycloak
- reverse-proxy (Nginx)
- optional: api-gateway later (Kong, etc.)
7. API Strategy: Contracts First, Code Second
With multiple services, you must decide:
- REST vs GraphQL vs mixed
- How versioning works
- How errors look
- How auth is enforced
Even if you are a one-person team now, future-you will not remember why endpoint A returns 200 with an error field.
A Practical Pattern
- Directus serves content API
- Your services expose REST endpoints
- Frontend uses a BFF layer (Backend For Frontend) when needed to merge responses cleanly
- API gateway later if and when you need centralised policy enforcement
8. Security Baseline: Lock It Early
Even for a "public portal", you will handle:
- PII via forms (contact, booking, applications)
- Authentication sessions
- Potentially payments later
- Vendor data for tenders
Baseline decisions that must exist from day one:
- TLS everywhere
- Content Security Policy (CSP)
- Rate limiting on forms
- WAF/CDN posture (Cloudflare works well as an early choice)
- Logging and audit trails for admin actions
- Strict separation: content vs transactional databases
9. What You Can Safely Build Later
E-Shop
150 products is not "hard", it's "easy to ruin with payments and refunds". Defer it if the portal launch is content-first and you can keep existing e-commerce running temporarily.
When you come back to it, you can decide: headless commerce, a dedicated commerce backend, or integration with ERP and payments.
Deep Workflow Automation
Internal workflows are where projects disappear into meetings and never return. Start with: CMS roles, submissions storage, basic admin views, approval statuses. Then expand when real users start producing real friction.
Advanced Personalisation Dashboards
User accounts and dashboards are a later evolution. Useful, but not needed to launch an excellent public portal.
10. Why WordPress Is "Easy", and Why It's Also a Risk Magnet
WordPress is not evil. It's just the wrong shape for what you're building.
Why It Feels Easy
- Content editing is immediate
- Tons of plugins
- Page builders make pages quickly
- Everybody knows someone who "can do WordPress"
Why It Becomes Risky at Scale
Security surface explodes. Plugins, themes, dependencies, admin endpoints. The portal becomes a patch management job masquerading as a website.
Coupling. Content, presentation, and business logic blend. You end up with "the database is the API" and regret.
Performance unpredictability. Plugin conflicts, query bloat, caching games. Under load, it becomes whack-a-mole.
Authorisation complexity. Fine-grained permissions across modules are awkward. You end up with either too many admins or too many hacks.
Integration pain. External systems (ERP, ticketing, IoT, procurement platforms) want clean APIs and controlled workflows. WordPress can do it, but it's rarely clean — and "rarely clean" is how you get haunted.
So yes, WordPress can ship a website quickly. But your target is not a website. It's a modular platform with multiple backoffice operators. WordPress is a shortcut that converts time savings today into fragility tomorrow.
11. A Phased Roadmap That Actually Matches Reality
If you want this to succeed, the first milestone is not "implement everything". It's:
Phase 0: Platform Foundation
- Next.js portal + design system
- Directus content model + roles
- Keycloak auth foundation (even if login is only for staff initially)
- Nginx + security headers + logging
Phase 1: Public Portal Content
- Homepage, service pages, directories, announcements
- Forms and submissions, with basic admin handling
Phase 2: First Transactional Module
Pick one:
- Space booking requests
- Events directory + registrations
- Tenders listing
Deliver one end-to-end workflow and learn from it. Then iterate.
Closing Thought
The real product here is not "a portal". The product is governance: identity, permissions, content ownership, workflow boundaries, and a design system that survives multiple hands touching it.
Everything else is implementation detail and caffeine.