Skip to main content

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 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 and GOV.UK 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.
  • 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. The current behavior and data boundaries belong in the user privacy guide, 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, 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.

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 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.
  • 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.