Zum Inhalt springen
Docs

Befehlspalette

Zu einer Seite oder Ansicht springen oder ein Todo per Name finden.

Änderungen

Conventions

Use the existing owners and enforce boundaries in code and tooling.

Markdown

Hooks and components

Hooks coordinate asynchronous state, mutations, subscriptions, error presentation and navigation. Components render that state and compose primitives. A small static component does not need an artificial hook; a screen should not own a second session authority.

Module boundaries

Backend rules (feature shape, errors, Effect, tenancy, configuration, logging) are on Backend conventions, and the rules for apps/web/src (routes, features and platform, the .server suffix, hooks versus components) are on Web conventions, each with its reason and enforcement. Before opening a pull request, use the review checklist.

  • No new barrels on server-capable modules. Use safe leaves for values needed by clients.
  • No dynamic import() in new implementation. Use static imports and framework-supported build splitting.
  • Enumerate cross-package exports deliberately.
  • Do not use window.confirm; use the shared accessible confirmation dialog.
  • Validate external payloads once at their boundary with Zod. Keep internal state typed.
  • Preserve Organization scope, current authorization and transactional audit requirements.

UI and language

Read apps/web/PRODUCT.md before UI work. shadcn is the visual authority; neutral semantic tokens make rebranding inexpensive. Use existing Base UI primitives and the component catalog. Authenticated screens follow the product’s operating interface; marketing has separate design guidance. Design patterns lists which source, kit and agent skill each job uses.

Add chrome strings to English, German and French catalogs together. Preserve keyboard navigation, visible focus, reduced-motion preferences and meaningful labels. Use semantic links for destinations and buttons for actions.

Code is written in English

Rule. Everything that is code or about code is English, whatever language the domain, the team or the conversation uses: identifiers (variables, functions, types, files, folders, routes, database tables and columns, env vars, flag keys), comments, test names (describe/it), developer log and error messages, error codes, commit messages, branch names, pull request titles and bodies, developer docs and ADRs.

User-facing text is the only exception. It goes through the i18n catalogs, never hard-coded: apps/web/src/locales, apps/mobile/src/locales, packages/errors/src/locales and packages/email/src/locales, with the packages/intl runtime (see UI and language and the Locales rules).

A domain word from another language gets one English name, recorded once in CONTEXT.md under the English term. Code uses only that name; an identifier never mixes two languages. A proper noun or a legal term with no translation appears only in user-facing strings or in its glossary entry. Asking an agent in Portuguese or German changes the chat, not the code.

Why. Projects built from this template are read by people and agents who do not share the domain's language. One language keeps names searchable (a search for invoice finds every invoice, not also fatura and rechnung), keeps the glossary the single source of a term, and lets anyone guess the name of the next function. A name in two languages is the worst case: neither reader can predict it. User-facing text is different: it has to be translated, so it lives in catalogs whose locales are checked against each other.

Example. A German-speaking team adds delivery notes. The glossary records the term once:

**Delivery Note**:
The document that travels with a shipped order (German: _Lieferschein_).
_Avoid_: Shipping slip

The code uses only the English term, and the German word reaches users through the catalog:

// A delivery note is created once, when the order ships.
export function createDeliveryNote(order: ShippedOrder): DeliveryNote { … }

describe("createDeliveryNote", () => {
  it("copies the shipped items from the order", () => { … });
});

// apps/web/src/locales/de.ts
DELIVERY_NOTE_TITLE: "Lieferschein",

Anti-pattern. createLieferschein(order) or gerarNotaDeEntrega(pedido); type ResultadoEnvio; describe("envio do pedido") or a comment written in Portuguese because the ticket or the chat was; log.warn("Lieferschein fehlt") for developers; <Button>Speichern</Button> with the label hard-coded instead of in the catalogs.

Enforcement. [test] scripts/code-language.test.mjs (in pnpm test) fails on a short list of Portuguese and German words in identifiers, comments and describe/it/test titles under apps/*/src, packages/*/src, their scripts/ folders and the root scripts/. It does not read string literals, JSX text, quoted words and URLs in comments, or the locales, fixtures and content folders. It is a word list, not a language detector, so other languages, log messages, commits, branches, pull requests and docs are [convention].

Changes and evidence

Use logical Conventional Commits. Keep generated migration SQL and relevant tests with their feature. Record measurements for runtime or bundle changes, including exact commands and limitations. Read the relevant ADR before altering an established boundary; historical measurements describe their captured revision, not a guarantee about the current tree.

Key files

Auf GitHub bearbeitenDie Dokumentation ist auf Englisch.