Skip to content

Front-end conventions

Angular product UI under Quinoa

Status: Locked for bootstrap Version: 0.2 Date: 2026-08-12

The product UI lives at backend/kovent-server/src/main/webui (Angular 22 + Tailwind 4 + Quinoa). The Next.js tree under design/ui/ is design velocity only — tokens and patterns flow into Angular; React does not ship.

Layout

Organise by engine, not by BCE layer names:

src/app/
  core/           # shell (sidebar + top bar), auth, config
  shared/         # tiny cross-engine primitives only
  registry/
    data/         # HTTP client + DTOs for this engine
    pages/        # routed screens
e2e/              # app-wide Playwright (sibling of src/)
  fixtures/
  pages/          # page objects
  specs/

Shell mirrors the supervision prototype and client-sphere: collapsible sidebar (workspace + grouped nav + user footer), sticky top bar (title, search, notifications), scrollable main.

Folder Job
pages/ Owns a URL; loads data; orchestrates actions
ui/ Presentational only — extract on reuse, do not invent a zoo on day one
data/ Typed API access for that engine

Flatten first. Prefer party-dossier.page.ts under registry/pages/ until something is shared.

Templates and styles

  • Strict HTML / TS split: templateUrl, no inline templates for screens.
  • Tailwind in templates. No component CSS sprawl unless a host binding needs it.
  • No logic in HTML beyond control flow (@if, @for) and bindings.
  • Icons: Lucide only via @lucide/angular (LucideBuilding2, etc.).

Reactivity

  • Signals, input() / output(), resource / httpResource for remote reads.
  • New forms: Angular Signal Forms (@angular/forms/signals).
  • Use platform helpers (debounced(), forms debounce) — do not invent debounce plumbing.

Auth

Keycloak via keycloak-angular — same pattern as client-sphere / Radarats:

  • check-sso + PKCE + silent-check-sso.html
  • Bearer token interceptor on /api/*
  • SPA client id kovent-ui (public + PKCE) on the fordsworth realm

Deliberately not doing

Skip Why
Component UI kits (Material, PrimeNG, …) KADLS + Tailwind is enough
NgRx Local signals + HTTP until cross-engine state forces it
Invented session cookies Keycloak / OIDC only
Unit-test piles Prefer integration and a few app-wide E2E journeys

Testing

Kind Where Stance
Rare unit Next to pure mappers under src/ Algorithm only
E2E e2e/ + playwright.config.ts at webui root Few whole-app journeys

Selectors: role and accessible name first; scarce data-testid. Prefer Playwright fill / getByRole. Seed via API fixtures (seedFirmViaApi), then assert a short UI path (openPartyDossier). No dispatchEvent value hacks.

Named fixtures: loginAsSupervisor, seedFirmViaApi, openPartyDossier.

Design tokens

Light-first KADLS tokens in src/styles.css (gold accent, cool neutrals, Plus Jakarta Sans, mono only for identifiers). See Design language.