Simpaisa Frontend Standards & Microfrontend Architecture¶
Date: 2026-04-03 Owner: CDO Scope: All web assets, portals, sites, and pages across Simpaisa
1. Design Tokens (Single Source of Truth)¶
All web properties MUST consume tokens from @simpaisa/design-tokens. No hardcoded colours, fonts, or spacing values in any project.
Brand Colours (derived from simpaisa.com production site)¶
/* Primary — Simpaisa Blue (from website gradient and CTAs) */
--sp-primary: #0156FC; /* Primary brand blue — buttons, links, accents */
--sp-primary-dark: #243E90; /* Gradient start, header backgrounds */
--sp-primary-bright: #1F6BFF; /* Highlights, underlines, focus rings */
/* Gradient — used for header bar, primary buttons, hero sections */
--sp-gradient: linear-gradient(90deg, #243E90 0%, #0156FC 100%);
/* Text */
--sp-text: #3A3A3A; /* Primary body text */
--sp-text-secondary: #5B5B5B; /* Secondary/description text */
/* Semantic */
--sp-success: #10b981; /* Completed, active, healthy */
--sp-warning: #f59e0b; /* Pending, on_hold, degraded */
--sp-danger: #FD4A51; /* Failed, error, critical (from website) */
--sp-info: #0156FC; /* Information, processing (same as primary) */
/* Neutral */
--sp-grey-50: #FBFCFC; /* Page background (from website body) */
--sp-grey-100: #F6F6F6; /* Section backgrounds */
--sp-grey-200: #EAEAEA; /* Borders, dividers (from website) */
--sp-grey-300: #DDDDDD; /* Secondary borders */
--sp-grey-400: #8591A9; /* Form focus state (from website) */
--sp-grey-500: #5B5B5B; /* Secondary text */
--sp-grey-600: #4b5563;
--sp-grey-700: #374151;
--sp-grey-800: #1f2937;
--sp-grey-900: #3A3A3A; /* Primary text (from website) */
/* Surface */
--sp-surface: #FBFCFC; /* Page background (website body bg) */
--sp-surface-raised: #FFFFFF; /* Cards, panels */
--sp-surface-overlay: rgba(0,0,0,0.5); /* Modal backdrops */
--sp-border: #EAEAEA; /* Borders, dividers */
Typography (from simpaisa.com — Poppins)¶
/* Font family — Poppins is the Simpaisa brand font */
--sp-font-sans: 'Poppins', system-ui, -apple-system, sans-serif;
--sp-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
/* NOTE: Only load weights 400, 500, 600, 700 (website loads all 9 — wasteful) */
/* Scale */
--sp-text-xs: 0.75rem; /* 12px — captions, badges */
--sp-text-sm: 0.875rem; /* 14px — secondary text, table cells */
--sp-text-base: 1rem; /* 16px — body text */
--sp-text-lg: 1.125rem; /* 18px — lead text */
--sp-text-xl: 1.25rem; /* 20px — section headers */
--sp-text-2xl: 1.5rem; /* 24px — page titles */
--sp-text-3xl: 1.875rem; /* 30px — hero titles */
--sp-text-4xl: 2.25rem; /* 36px — landing page hero */
/* Weight */
--sp-font-normal: 400;
--sp-font-medium: 500;
--sp-font-semibold: 600;
--sp-font-bold: 700;
/* Line height */
--sp-leading-tight: 1.25;
--sp-leading-normal: 1.5;
--sp-leading-relaxed: 1.75;
Spacing Scale¶
/* 4px base unit */
--sp-space-1: 0.25rem; /* 4px */
--sp-space-2: 0.5rem; /* 8px */
--sp-space-3: 0.75rem; /* 12px */
--sp-space-4: 1rem; /* 16px */
--sp-space-5: 1.25rem; /* 20px */
--sp-space-6: 1.5rem; /* 24px */
--sp-space-8: 2rem; /* 32px */
--sp-space-10: 2.5rem; /* 40px */
--sp-space-12: 3rem; /* 48px */
--sp-space-16: 4rem; /* 64px */
Shadows¶
--sp-shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--sp-shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1);
--sp-shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1);
--sp-shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.1);
Border Radius¶
--sp-radius-sm: 0.25rem; /* 4px — badges, chips */
--sp-radius-md: 0.375rem; /* 6px — buttons, inputs */
--sp-radius-lg: 0.5rem; /* 8px — cards, panels */
--sp-radius-xl: 0.75rem; /* 12px — modals, large cards */
--sp-radius-full: 9999px; /* Circles, pills */
2. Component Library (@simpaisa/ui)¶
Architecture: Web Components + Astro Wrappers¶
Components are built as framework-agnostic Web Components (using Lit or vanilla custom elements) with thin Astro wrappers for the portal. This ensures:
- Same components work in Astro portals, Cloudflare Workers, static marketing pages, and any future framework
- No framework lock-in
- Native browser support, no hydration cost for simple components
- Astro islands for interactive components (forms, tables, charts)
Component Tiers¶
Tier 1 — Atoms (no state, pure presentation)
- sp-button — primary, secondary, danger, ghost, outline, link variants. Sizes: sm, md, lg
- sp-badge — status indicators with semantic colour mapping
- sp-icon — SVG icon wrapper from Simpaisa icon set
- sp-avatar — user/merchant avatar with fallback initials
- sp-spinner — loading indicator
- sp-tag — removable label/chip
- sp-divider — horizontal/vertical separator
Tier 2 — Molecules (minimal state)
- sp-input — text, email, password, number, search with label, error, helper text
- sp-select — dropdown with search, multi-select support
- sp-textarea — multiline input
- sp-checkbox, sp-radio, sp-toggle — boolean/choice inputs
- sp-date-picker — date and date-range selection
- sp-file-upload — drag-and-drop file upload
- sp-toast — notification toast (success, error, warning, info)
- sp-tooltip — hover/focus information
- sp-breadcrumbs — navigation trail
- sp-pagination — cursor-based page controls
- sp-stat-card — metric with label, value, trend
Tier 3 — Organisms (stateful, interactive)
- sp-data-table — sortable, filterable, paginated table with row actions
- sp-form — validated form with submit handling
- sp-modal — dialog overlay with focus trap
- sp-sidebar — collapsible navigation sidebar
- sp-command-palette — Cmd+K search/action palette
- sp-chart — line, bar, pie (wrapper around lightweight chart lib)
- sp-code-block — syntax-highlighted code with copy button
- sp-timeline — event/audit trail display
Tier 4 — Templates (page layouts)
- sp-dashboard-layout — sidebar + header + content + footer
- sp-public-layout — header + content (no sidebar)
- sp-auth-layout — centred card for login/register
- sp-docs-layout — sidebar TOC + content + on-page nav
Component API Contract¶
Every component MUST:
1. Accept design tokens via CSS custom properties (not hardcoded values)
2. Support dark class on a parent element for dark mode
3. Be keyboard accessible (WCAG 2.1 AA)
4. Have a data-testid attribute for testing
5. Emit standard DOM events (not framework-specific)
6. Work without JavaScript for core content (progressive enhancement)
3. Microfrontend Architecture¶
Composition Model: Build-Time Integration¶
Phoenix uses build-time composition via Astro, not runtime module federation. Each portal is a separate Astro project that imports from the shared package:
@simpaisa/design-tokens → CSS custom properties, Tailwind preset
@simpaisa/ui → Web Components + Astro wrappers
@simpaisa/api-client → Typed Phoenix API client (shared lib/api.ts)
@simpaisa/auth → Shared auth utilities (shared lib/auth.ts)
Why Build-Time Over Runtime¶
- Simpler: No module federation, no shared runtime, no version conflicts
- Faster: Static assets from Cloudflare Pages CDN, no runtime loading
- Safer: Each portal is independently deployable and testable
- Astro: Islands architecture handles interactive sections without full SPA overhead
Portal Projects (separate Astro apps, shared packages)¶
phoenix/
├── packages/
│ ├── design-tokens/ # CSS variables, Tailwind preset
│ ├── ui/ # Web Components + Astro wrappers
│ ├── api-client/ # Typed Phoenix API client
│ └── auth/ # Shared auth utilities
├── portal/ # Staff/Admin + Merchant portal (current)
├── portal-developers/ # Developer portal (public, mostly static)
└── portal-marketing/ # Marketing site (future, fully static)
Shared Tailwind Preset¶
All portals import the same Tailwind preset so utility classes produce identical output:
// packages/design-tokens/tailwind-preset.mjs
// Derived from simpaisa.com production website
export default {
theme: {
extend: {
colors: {
primary: { DEFAULT: '#0156FC', dark: '#243E90', bright: '#1F6BFF' },
surface: { DEFAULT: '#FBFCFC', raised: '#FFFFFF', muted: '#F6F6F6' },
border: { DEFAULT: '#EAEAEA', light: '#DDDDDD', focus: '#8591A9' },
text: { DEFAULT: '#3A3A3A', secondary: '#5B5B5B' },
danger: '#FD4A51',
success: '#10b981',
warning: '#f59e0b',
},
fontFamily: {
sans: ['Poppins', 'system-ui', 'sans-serif'], // Simpaisa brand font
mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
},
borderRadius: { sm: '6px', DEFAULT: '8px', lg: '12px' },
boxShadow: {
card: '0px 7.17px 30.75px 0px rgba(9,14,24,0.1)',
header: '0px 2px 44px 0px rgba(12,18,35,0.06)',
},
container: { center: true, padding: '20px', screens: { xl: '1320px' } },
},
},
plugins: [require('@tailwindcss/forms')],
}
Each portal's tailwind.config.mjs:
import simpaisaPreset from '@simpaisa/design-tokens/tailwind-preset.mjs'
export default { presets: [simpaisaPreset], content: ['./src/**/*.{astro,ts}'] }
4. Coding Standards¶
File Naming¶
- Components:
PascalCase.astro(Astro),sp-kebab-case.ts(Web Components) - Pages:
kebab-case.astroor[param].astrofor dynamic routes - Utilities:
camelCase.ts - Tests:
*.test.ts
TypeScript¶
- Strict mode always (
"strict": true) - No
any— useunknownand narrow - Interface over type for object shapes
- Enum for fixed sets (status codes, operator types)
CSS / Tailwind¶
- Use design tokens (never hardcode colours/spacing)
- Prefer Tailwind utilities over custom CSS
- Custom CSS only for animations or complex layouts
- Dark mode via
dark:prefix (class strategy) - No
!important— ever
Accessibility¶
- All interactive elements: keyboard navigable
- All images:
alttext - All forms:
<label>associations - Colour contrast: WCAG 2.1 AA minimum (4.5:1 for text)
- Focus indicators: visible and consistent (
--sp-tealring) - ARIA attributes where semantic HTML is insufficient
Performance¶
- No JavaScript for content that doesn't need it (Astro default)
- Images: WebP/AVIF with
<picture>fallbacks - Fonts:
font-display: swap, subset Inter to Latin - Bundle: <100KB JS per page (excluding charts)
- Lighthouse target: >90 on all categories
Testing¶
- Components: visual regression (Playwright screenshots)
- Integration: Playwright for critical flows (login, transaction search)
- Accessibility: axe-core automated checks
5. Status Badge Colour Mapping (Global Standard)¶
All portals MUST use the same colour for the same status:
| Status | Colour | Token | Used In |
|---|---|---|---|
active, completed, disbursed, delivered, healthy |
Green | --sp-success |
All |
initiated, created, pending, open |
Blue | --sp-info |
All |
processing, awaiting_authorisation, awaiting_3ds |
Blue (pulse) | --sp-info + animation |
All |
on_hold, in_review, degraded, warning |
Amber | --sp-warning |
All |
failed, rejected, dead_letter, critical, error |
Red | --sp-danger |
All |
cancelled, deactivated, suspended, voided |
Grey | --sp-grey-400 |
All |
reversed, refunded, partially_refunded |
Purple | #8b5cf6 |
Transactions |
6. URL Structure Convention¶
All portals follow the same URL hierarchy:
/ → Landing / redirect
/login → Authentication
/dashboard → Overview / home
/dashboard/transactions → Transaction list
/dashboard/transactions/:id → Transaction detail
/dashboard/merchants → Merchant list (admin only)
/dashboard/merchants/:id → Merchant detail
/dashboard/operators → Operator management
/dashboard/webhooks → Webhook deliveries
/dashboard/config → Feature flags & config
/dashboard/settings → User/system settings
/developers → Developer portal (public)
/developers/docs → API reference
/developers/sandbox → Test environment
/api/auth/* → Auth API routes (server-side)
7. Dark Mode¶
All portals MUST support dark mode:
- Toggled via class on
<html>element (class="dark") - User preference stored in cookie (persists across sessions)
- Respects
prefers-color-schemeon first visit - All components use
dark:Tailwind variants - Charts and data visualisations adapt to dark mode
- No white flashes on page load (inline script sets class before render)
8. Internationalisation (i18n) — Future Ready¶
Not required for launch, but design for it:
- All user-facing strings in a separate locale file (not inline in components)
- Date/time formatting via
Intl.DateTimeFormat(never manual formatting) - Number formatting via
Intl.NumberFormat(respects locale) - Currency display via
Intl.NumberFormatwithstyle: 'currency' - RTL support via
dirattribute (for future Arabic/Urdu markets) - No string concatenation for sentences — use template interpolation
9. Deployment Standard¶
All portals deploy to Cloudflare Pages:
Production: portal.simpaisa.com (staff + merchant dashboard)
Staging: staging.portal.simpaisa.com
Preview: {branch}.portal.pages.dev (automatic per PR)
Developer: developers.simpaisa.com (public, static)
Marketing: www.simpaisa.com (future)
Each portal has its own wrangler.toml with:
- Cloudflare Pages project name
- Environment variables (PHOENIX_API_URL)
- Build command and output directory
- Custom headers (CSP, HSTS, X-Frame-Options)