Skip to main content

Frontend structure

App Router

Each app (apps/tracking, apps/portal) is a Next.js App Router project under src/app/:

  • page.tsx — login gate.
  • layout.tsx — root layout. Imports globals.css, mounts the prefetch <XLoader/> components from @enode/core, and runs a boot script that adds class="ios" to <html> on the Capacitor iOS build.
  • Feature routes — composed from co-located use-* hooks and presentational files.

Styling & design tokens

Tailwind v4 with the Enode design system in packages/ui/src/styles/design-system.css. Each app's globals.css composes it:

@import "tailwindcss";
@import "@enode/ui/styles/design-system.css";
  • Use semantic colour utilities (bg-surface-base, text-foreground-muted, border-surface-stroke, bg-foreground-red-orange, …) and type-style classes (heading-hero, body-normal, stat-large-digits, …).
  • Never raw gray/orange/emerald utilities. Tokens carry light + dark values and flip via prefers-color-scheme, so don't add dark: variants.
  • Destructive states still use raw red-* — the design system has no danger token (a known gap).
  • ios: is a custom variant scoped to the Capacitor iOS build.

Conventions

  • State resets adjust state during render (the prev-value pattern), not via setState in useEffect — ESLint enforces this.
  • Local entity ids are crypto.randomUUID().
  • Reusable presentational components belong in @enode/ui; shared non-UI logic in @enode/core. App-specific views stay in the app.

See Components for the reusable component layer and Storybook.