Monorepo: apps/web (the application), apps/landing (marketing site),
packages/* (the bricks — feature packages, see REPOSITORY.md and the
lint-enforced boundaries in eslint.config.js), pipelines/ (the
compositions — product verticals; may import bricks, never the reverse),
services/* (foreign runtimes). pnpm workspaces.
- UI primitives come from
~/components/ui/<name>. If one is missing, add it withnpx shadcn@latest add <name>(run in apps/web) — never hand-roll a button, input, table, or overlay. Modals use~/components/ui/dialog. cncomes from~/lib/utils. There is exactly one copy.- Colors are design tokens:
var(--…)frompackages/design-tokens/tokens.cssor semantic Tailwind classes (bg-panel,text-ink-2,border-line,bg-brand,text-danger). Never hex literals, never new inlinestylecolors, never the raw Tailwind palette (purple-600,slate-800) in new code. - The shadcn color names (
bg-background,text-muted-foreground, …) are a deprecated compat layer (apps/web/src/styles/compat.css). Don't extend it. - Dark mode:
data-theme="dark"on<html>. Usedark:variants or[data-theme="dark"]CSS; never branch onresolvedThemein JS for colors. - Icons:
lucide-reactin both apps; brand marks from~/components/icons/brand(lucide's brand glyphs and other icon libraries are lint errors). - Fonts: Inter (
var(--font-sans)) for all UI, headings included (displayclass); JetBrains Mono (var(--font-mono)) for code. Loaded once per app insrc/app/fonts.ts; never name a family (enforced byapps/web/__tests__/brand/typography.test.ts). - Words on screen come from message catalogues (next-intl, English and
Simplified Chinese):
useTranslations/getTranslations, never a user-visible English literal in a component. Add the key to bothsrc/i18n/messages/enandzh-CN;npx jest src/i18nchecks they match. Seeapps/web/src/i18n/README.md. - Never import across route areas (
app/employer/**↔app/employee/**). Shared pieces go in~/componentsor~/lib. - Touch-it-migrate-it: when editing existing UI for feature work, convert the region you touch to kit + tokens; never launch a bulk rewrite.
- Full conventions:
apps/web/README.md. - The Mindmap editor (
app/employer/documents/_mindmap) has its own README and one deliberate exception: shape colours are literal OKLCH values stored in the document, not tokens — a token would repaint when the viewer switches theme and change someone else's diagram. Its chrome uses tokens normally.
- Format with
pnpm format:write(Prettier owns style incl. Tailwind class order); lint warnings from the design-system guardrails are a ratchet — the count may only go down. public/templates/*.docxare live production data resolved at runtime viaprocess.cwd()— do not move them.- Deploys are container images (
.github/workflows/docker.yml→ GHCR) and Compose. There is no Vercel pipeline; nothing in the repo builds one.