# Coding & Design Guidelines

These guidelines keep every service aligned. Keep changes focused. Mention any deviation in your pull request. Raise follow-up issues when you discover gaps.

## Contributor checklist

* Run the formatter and linter for the area you touched. Examples: `vp run format:webapp`, `vp run lint:java`.
* Smoke-test the critical scripts. `vp run build:webapp` must pass. If you changed migrations, run `vp run db:generate-erd-docs`.
* Update Chromatic snapshots when you change UI components.
* Regenerate clients and documentation when you change an API contract.
* Run the [local verification](/contributor/local-verification.md) appropriate to your changes.
* Document what you verified in the pull request template. Link failing checks to tickets if you must defer.

## Webapp (`/webapp`)

### Platform overview

* React 19 on Vite. Read the pinned versions from `webapp/package.json`. They move faster than this page.
* `webapp/vite.shared.ts` enables React Compiler. Every build of app source imports it. Leave it on.
* Routing uses TanStack Router file routes in `src/routes/**` with the generated `routeTree.gen.ts`.
* TanStack Query v5 initializes in `src/runtime/tanstack-query/root-provider.tsx`. OpenAPI helpers live in `src/api/@tanstack/react-query.gen.ts`.
* There is no global store: where each kind of state lives is the table in `webapp/AGENTS.md` § Data fetching.
* Tailwind CSS 4 supplies styles. Tokens live in `src/styles/theme-tokens.css`. The Chrome extension also imports this file. `src/styles.css` is the entry stylesheet. shadcn/ui primitives live in `src/components/ui/**`, a registry install over Base UI. Check a change there against upstream. Record a deliberate difference in the file, because a new vendor import overwrites it.
* Storybook, Chromatic, Vitest, oxlint, and oxfmt cover tooling.

### Building features

* Create routes with `createFileRoute`. Route modules handle auth gating (see `src/routes/_authenticated.tsx`), loader logic, and orchestration.
* Keep presentational components in `src/components/**`. They should take props, stay pure, and avoid side effects.
* Fetch data by spreading generated `...Options()` helpers into `useQuery` or `useMutation`. The helpers provide typing, query keys, and retry defaults. A hand-written query key is a lint error (`hephaestus/no-manual-query-key`), because it stops matching the generated one silently.
* Invalidate caches with the generated `...QueryKey()` helpers or the same keys passed to `useQuery`. Use optimistic updates only when the UI must respond instantly, such as mentor chat streaming.
* The React Compiler rules and the clock rules are `webapp/AGENTS.md` § React Compiler and § The time of day. Lint enforces both.
* Stay inside the `--color-*` token scale declared in `src/styles/theme-tokens.css` and, for provider colors, `src/styles.css`. Reach for shadcn/ui primitives before adding new component libraries. `@apply` lives in `styles.css` for base and wrapper rules, not in components.
* Co-locate `*.stories.tsx` files. Show the states the component can actually reach, with realistic data. Run `vp run --filter webapp chromatic:ci` whenever stories change.
* Defer analytics work to effects that run after paint.

### Onboarding and choice screens

* Use the shared questionnaire and native fieldset so one question has one accessible answer group. Do not pre-select a first answer. A saved answer may appear checked when the member returns. See [W3C grouping controls](https://www.w3.org/WAI/tutorials/forms/grouping/) and [GOV.UK radios](https://design-system.service.gov.uk/components/radios/).
* Give the three AI answers equal prominence. State each consequence before the member chooses. Do not make a logo stand in for a data-handling promise. A workspace may name a model it has configured, but the account-wide answer is not a model picker. See [EDPB guidance on deceptive design](https://www.edpb.europa.eu/system/files/documents/2023-02/edpb_03-2022_guidelines_on_deceptive_design_patterns_in_social_media_platform_interfaces_v2_en_0.pdf).
* Keep account linking separate from the AI answer. A member can save either without the other. An answer not set up in this workspace remains selectable, with a clear consequence. Give disabled actions a visible reason. Test narrow screens and keyboard use.
* Use the product terms in [practice-feedback language](/contributor/practice-feedback-language.md#member-onboarding-and-ai-choices). The current behavior and data boundaries belong in the [user privacy guide](/user/privacy.md#your-ai-choice), not in a second screen-by-screen specification here.

### Quality gates

* Install dependencies with `vp install` at the repo root so optional binaries resolve.
* Run `vp run check:webapp` and `vp run build:webapp` before opening a pull request.
* Execute Vitest suites with `vp run test:webapp`. Add unit tests beside the feature you touched.
* Keep Storybook stories in sync with design. Launch `vp run --filter webapp storybook:dev` when pairing with design reviews.
* Validate bundle impact by checking the Vite build stats when you add large libraries.

## Spring Boot application server (`/server`)

### Structure

* Feature packages sit directly under `de.tum.cit.aet.hephaestus` — `practices/`, `evidence/`, `agent/`, `integration/`, `mentor/`, `workspace/`, `activity/` and the rest. Shared wiring sits in `config/` and `core/`. Cross-cutting integration traits (webhook ingress, oauth ingress, SPI, registry) live under `integration/` directly. `ls` the package root rather than trusting a list here.
* Controllers return DTOs located near the controller. `ActivitySummaryDTO` in `activity/overview/dto/` is the reference example.
* Repositories return `Optional<T>` instead of `null`.
* Services take their collaborators through the constructor, over `private final` fields. Do not use field injection with `@Autowired`. If a service depends on many collaborators, split the responsibility.
* Set up loggers with `LoggerFactory.getLogger`. Use structured log messages.
* Annotate the smallest unit of write work with `@Transactional`.

### Coding conventions

* Use Java 21 features where they simplify code. Records, pattern matching, and sealed hierarchies improve readability.
* Keep controllers thin. Push orchestration into services and prefer constructor helpers over static util classes.
* Expose dedicated DTO mappers in the package instead of sprinkling conversion logic across layers.
* Treat `Optional` as a signal for missing data. Avoid returning `null` from repository methods.

### Null safety

* `server/AGENTS.md` § Null-safety owns the NullAway policy. On API DTOs, use explicit `@NonNull` for components that must be `required` in OpenAPI.
* Run `vp run gate:java-nullness` for the policy check and `cd server && ./gradlew :application:testClasses` for compiler analysis.

### Safe workflows

* Configuration overrides stay in `application-*.yml`. Do not commit `application-local.yml`.
* Share long-lived infrastructure in tests. Lean on Testcontainers and GitHub fixtures where possible.
* After updating Liquibase migrations, run `vp run db:generate-erd-docs`. Regenerate OpenAPI and the REST client only when the HTTP API contract changes.
* Run the affected [test tiers](/contributor/testing.md#gradle-recipes), including architecture checks when changing module boundaries.
* Prefer integration tests that extend `BaseIntegrationTest`, or `AbstractWorkspaceIntegrationTest` for anything workspace-scoped, when you touch persistence logic. See [Testing](/contributor/testing.md).

## Webhook receiver (`server/.../integration/core/webhook/`)

* `server/AGENTS.md` § Webhook receiver owns the layout, the role gate, the subject grammar, the ArchUnit guards and the JaCoCo floors.
* The provider-specific verifiers and subject parsers are Spring-free and live with their provider, under `integration/scm/github/webhook/` and `integration/scm/gitlab/webhook/`. JUnit unit tests exercise all of them, plus parameterized tests over captured fixtures in `server/application/src/test/resources/{github,gitlab}/`.
* HMAC verification uses `MessageDigest.isEqual` (constant-time, length-tolerant).

## Docs site (`/docs`)

* Docusaurus 3 powers the documentation. Install dependencies with `vp install` and run `vp run docs:dev` from the repository root to preview.
* Keep the front matter `id` and `title` unique, and add every new page to `sidebars.*.ts` — the sidebars are explicit.
* Use MDX components from `docs/src/components/**` to keep styling consistent.
* Run `vp run docs:build` before committing structural changes to confirm the static export succeeds.

## Database and migrations

* Liquibase `<changeSet>`s (schema deltas — not release changesets) live in `server/application/src/main/resources/db/changelog/`. A schema change also needs a release changeset — `.changeset/README.md`.
* Prefer `renameColumn` or `modifyDataType` when evolving schemas so data survives deployments.
* Add indexes before backfilling large tables. Profile long migrations locally.
* After schema updates, regenerate the ERD and run server tests that touch the affected tables.

## Observability and security

* Log through SLF4J. Name a structured event with `event.name` and add typed fields with `addKeyValue`. [Observability](/admin/observability.md#reading-log-records) owns the record shape.
* Logs are not redacted. Do not write an exception's message or `toString()` into a log message. It can quote SQL values, a request URL, a provider response or model output. Write its class. To keep its frames, pass the exception as the last argument. The formatter prints classes and frames, not messages.
* Store shared secrets in LastPass and load them through `.env` or the respective `application-*.yml` files. Never commit real secrets.
* Rotate API keys when you onboard new external services. Document the process in the [secret custody guide](/admin/secret-custody.md).
* Sanitise logged user data. Log IDs rather than emails.

## Performance reminders

* Batch network calls and paginate large results.
* Cache expensive computations when you reuse them. TanStack Query handles client caching. Use memoized services or projections on the server.
* Measure before tuning. Add logging or metrics when you touch critical latency paths.
* Profile React work with the DevTools profiler and Chrome Performance panel. Profile Java code with JFR and async-profiler.

## When unsure

Record trade-offs in your pull request. Ask for a second review on risky work. Suggest improvements to this page when you find a better pattern.
