Frontend
The frontend is a Next.js 16 / React 19 app (frontend/public-page) using
the App Router, Tailwind CSS v4, next-intl for localisation, and a small
design-system of shared primitives. It serves the public landing page, the
authentication flows, the authenticated console, and these docs.
App Router structure
app/
├── layout.tsx root layout — fonts, i18n provider, auth providers
├── page.tsx landing
├── login/ register/ forgot-password/ reset-password/ verify-email/
├── dashboard/ authenticated console (own layout: sidebar + topbar)
│ ├── layout.tsx
│ ├── page.tsx overview
│ ├── account/ admin/
├── docs/ this documentation (MDX)
└── shared/
├── ui/ design-system primitives
├── components/ larger pieces (e.g. architecture diagram)
└── auth/ ProtectedRoute, providers
The root layout wires the global providers once — next-intl, tooltip, Google OAuth, auth and user contexts, and toast notifications — so every route inherits them. The dashboard layout adds the authenticated chrome (sidebar + topbar).
Design tokens & theming
Styling is driven entirely by CSS custom properties defined in
app/globals.css and exposed to Tailwind v4 via @theme. The palette is the
"Molten Forge" identity — dark forged-steel surfaces with a molten-orange accent:
--base: #0c0a09; /* forged-steel background */
--ink: #f0e9e2; /* primary text */
--ink-dim: #a3978c; /* secondary text */
--line: rgba(255,180,120,0.09); /* hairline borders */
--phosphor: #ff5a1f; /* primary accent (molten orange) */
--amber: #ffb429; /* spark / warning */
Because everything reads from these tokens, re-theming is a token change —
adjust --phosphor and the accent cascades across buttons, links, charts,
diagram connectors and the docs. Components reference Tailwind classes mapped to
the tokens (text-ink, border-line, text-primary, …), never hard-coded
colours.
Fonts are loaded with next/font: Geist for body (--font-sans) and
JetBrains Mono for code and labels (--font-mono).
UI primitives
The app/shared/ui/ folder is the component vocabulary. A selection:
| Primitive | Purpose |
|---|---|
Button | CVA variants (primary, outline, ghost, destructive, …) and sizes |
Card | Card + CardHeader/Title/Description/Content/Footer |
Badge | status pills (live, warn, down, accent) |
Input / Label / PasswordInput | form controls |
Dialog / DropdownMenu / Tooltip | Radix-based overlays |
Table, StatTile, StatusDot, Skeleton | data display |
Wordmark | the brand mark (with rising embers) |
EmberField | the animated forge-ember background |
Compose with the cn() helper (clsx + tailwind-merge) so class overrides
merge predictably:
import { cn } from '@/lib/utils';
<div className={cn('rounded-lg border border-line', active && 'border-primary')} />
Internationalisation
Localisation uses next-intl. Locale is cookie-based (NEXT_LOCALE) —
there's no [locale] segment in the URL — with the browser's Accept-Language
as a fallback and en as the default. Eight locales ship: en, es, pt,
de, fr, nl, pl, th.
Translations live in messages/<locale>.json, organised by namespace, and
components consume them through useTranslations:
const t = useTranslations('fmf.landing');
return <h1>{t('headline')}</h1>;
Keep all locale files in sync when you add a key. (These docs are an exception — they're authored in English MDX rather than the translation catalogues.)
The console
app/dashboard is the authenticated area, guarded client-side by
ProtectedRoute and server-validated by the backend's JwtAuthGuard. It reads
live system data — health and event throughput — from the backend's
JWT-protected /dashboard endpoints and renders it with the shared primitives
(stat tiles, status dots, tables). Admins additionally get user management and a
message-of-the-day editor.
The docs (this section)
These pages are MDX. next.config.mjs enables MDX via @next/mdx
(pageExtensions includes mdx), and mdx-components.tsx maps MDX output onto
the design tokens so prose, code blocks, tables and callouts all match the rest
of the app. The sidebar/prev-next come from a single nav config
(app/docs/nav.ts), so adding a page is: create the .mdx file and add one
entry to the nav.
Next: Databases.