Microfrontends Framework¶
| Field | Value |
|---|---|
| Status | Draft |
| Owner | Frontend Engineering |
| Last Updated | 2026-04-03 |
| Applies To | Merchant Portal, Admin Portal |
1. Overview¶
Simpaisa's merchant-facing portal is built as a microfrontend (MFE) architecture using Astro as the composition shell and Preact for interactive islands. Each MFE is independently deployable to Cloudflare Pages, enabling product squads to ship UI changes without coordinating releases across the entire frontend.
2. Technology Stack¶
| Layer | Technology | Purpose |
|---|---|---|
| Composition Shell | Astro 5.x | Server-rendered layout, routing |
| Interactive Islands | Preact 10.x | Lightweight reactive components |
| Styling | Design system tokens (CSS) | Consistent visual language |
| Authentication | ControlPlane.com OIDC | SSO, RBAC, session management |
| Hosting | Cloudflare Pages | Edge-deployed, per-MFE pipelines |
| Analytics | PostHog | Product analytics, feature flags |
| Language | TypeScript (strict mode) | Type safety across all MFEs |
3. Microfrontend Inventory¶
| MFE | Route Prefix | Responsibility | Squad |
|---|---|---|---|
dashboard-mfe |
/ |
Overview metrics, transaction volume, health status | Product |
apikeys-mfe |
/api-keys |
API key generation, rotation, scoping | Platform |
webhooks-mfe |
/webhooks |
Webhook endpoint CRUD, delivery logs, retry | Platform |
transactions-mfe |
/transactions |
Transaction search, detail view, export | Product |
reports-mfe |
/reports |
Settlement reports, reconciliation, downloads | Finance |
team-mfe |
/team |
User management, role assignment, audit log | Platform |
admin-mfe |
/admin |
Merchant config, channel toggling, rate management | Operations |
4. Composition Architecture¶
graph TB
subgraph "Cloudflare Edge"
CDN[Cloudflare CDN/WAF]
end
subgraph "Astro Shell"
Shell[Astro Composition Shell]
Shell --> Nav[Shared Navigation]
Shell --> Auth[Auth Provider]
Shell --> ErrorBoundary[Error Boundary]
end
subgraph "Preact Islands"
Dashboard[dashboard-mfe]
APIKeys[apikeys-mfe]
Webhooks[webhooks-mfe]
Transactions[transactions-mfe]
Reports[reports-mfe]
Team[team-mfe]
Admin[admin-mfe]
end
CDN --> Shell
Shell --> Dashboard
Shell --> APIKeys
Shell --> Webhooks
Shell --> Transactions
Shell --> Reports
Shell --> Team
Shell --> Admin
5. Shared Concerns¶
5.1 Design System Tokens¶
All MFEs consume a shared @simpaisa/design-tokens package published to the private npm registry. Tokens define:
- Colour palette (brand blue
#0052CC, success green, error red). - Typography scale (Inter font, 8 pt grid).
- Spacing, border radius, shadow elevation.
- Component primitives (Button, Input, Card, Table, Modal).
No MFE may define its own colour values or override token defaults.
5.2 Authentication — ControlPlane.com¶
Authentication is handled at the shell level. The Astro shell initiates an OIDC flow with ControlPlane.com on first load. The resulting JWT is stored in an HttpOnly cookie and passed to the BFF on every request.
- Token refresh: Silent refresh via iframe before expiry.
- RBAC: Roles (
admin,finance,developer,viewer) are embedded in the JWT claims. Each MFE checks permissions before rendering protected routes.
5.3 Routing¶
Astro file-based routing owns top-level paths. Each MFE is mounted at its route prefix and handles sub-routing internally using Preact Router.
/ → dashboard-mfe
/api-keys → apikeys-mfe
/api-keys/:id → apikeys-mfe (internal route)
/transactions → transactions-mfe
/transactions/:txnId → transactions-mfe (internal route)
5.4 Error Boundary¶
A global error boundary in the Astro shell catches rendering failures in any MFE and displays a fallback UI. The failing MFE is isolated — other MFEs continue functioning.
6. Communication Between MFEs¶
MFEs communicate via Custom Events on the window object. There is no shared state store.
// Publishing (from transactions-mfe)
window.dispatchEvent(
new CustomEvent('simpaisa:txn:selected', {
detail: { txnId: 'txn_abc123' },
})
);
// Subscribing (in dashboard-mfe)
window.addEventListener('simpaisa:txn:selected', (e: CustomEvent) => {
navigateToDetail(e.detail.txnId);
});
Rules:
- Event names must be prefixed with simpaisa:.
- Each MFE owns its own data — no MFE reads another MFE's internal state.
- Events carry minimal payloads (IDs, not full objects).
7. Independent Deployment¶
Each MFE has its own Bitbucket Pipeline and deploys independently to Cloudflare Pages.
graph LR
subgraph "Bitbucket Pipelines"
PR[Pull Request] --> Lint[ESLint + tsc]
Lint --> Test[Vitest]
Test --> Build[Astro Build]
Build --> Preview[Cloudflare Preview]
Preview --> Merge[Merge to main]
Merge --> Prod[Cloudflare Pages Prod]
end
Deployment rules:
- Each MFE is a separate Cloudflare Pages project.
- The Astro shell fetches MFE bundles at the edge via Cloudflare Workers.
- Rollback is per-MFE — a broken reports-mfe deploy does not require rolling back dashboard-mfe.
- Feature flags (PostHog) gate new MFE versions for progressive rollout.
8. TypeScript Strict Mode¶
All MFEs enforce strict: true in tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"exactOptionalPropertyTypes": true
}
}
9. Performance Budget¶
| Metric | Target |
|---|---|
| First Contentful Paint | < 1.2 s |
| Largest Contentful Paint | < 2.5 s |
| Total bundle per MFE | < 80 KB gz |
| Preact island hydration | < 200 ms |
Cloudflare edge caching and Astro's zero-JS-by-default approach keep payloads minimal. Only interactive islands ship JavaScript to the client.
10. Local Development¶
# Start the full portal locally
pnpm dev
# Start a single MFE in isolation
cd packages/transactions-mfe && pnpm dev
Each MFE can run standalone with mock data or connect to the sandbox BFF.
11. Architectural Decision Records¶
Changes to this framework require an ADR in /Standards/ADR/. See ADR/ADR-TEMPLATE.md.