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:webappmust pass. If you changed migrations, runvp 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.tsenables React Compiler. Every build of app source imports it. Leave it on.- Routing uses TanStack Router file routes in
src/routes/**with the generatedrouteTree.gen.ts. - TanStack Query v5 initializes in
src/runtime/tanstack-query/root-provider.tsx. OpenAPI helpers live insrc/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.cssis the entry stylesheet. shadcn/ui primitives live insrc/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 (seesrc/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 intouseQueryoruseMutation. 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 touseQuery. 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 insrc/styles/theme-tokens.cssand, for provider colors,src/styles.css. Reach for shadcn/ui primitives before adding new component libraries.@applylives instyles.cssfor base and wrapper rules, not in components. - Co-locate
*.stories.tsxfiles. Show the states the component can actually reach, with realistic data. Runvp run --filter webapp chromatic:ciwhenever 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 installat the repo root so optional binaries resolve. - Run
vp run check:webappandvp run build:webappbefore 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:devwhen 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 inconfig/andcore/. Cross-cutting integration traits (webhook ingress, oauth ingress, SPI, registry) live underintegration/directly.lsthe package root rather than trusting a list here. - Controllers return DTOs located near the controller.
ActivitySummaryDTOinactivity/overview/dto/is the reference example. - Repositories return
Optional<T>instead ofnull. - Services take their collaborators through the constructor, over
private finalfields. 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
Optionalas a signal for missing data. Avoid returningnullfrom repository methods.
Null safety
server/AGENTS.md§ Null-safety owns the NullAway policy. On API DTOs, use explicit@NonNullfor components that must berequiredin OpenAPI.- Run
vp run gate:java-nullnessfor the policy check andcd server && ./gradlew :application:testClassesfor compiler analysis.
Safe workflows
- Configuration overrides stay in
application-*.yml. Do not commitapplication-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, orAbstractWorkspaceIntegrationTestfor 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/andintegration/scm/gitlab/webhook/. JUnit unit tests exercise all of them, plus parameterized tests over captured fixtures inserver/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 installand runvp run docs:devfrom the repository root to preview. - Keep the front matter
idandtitleunique, and add every new page tosidebars.*.ts— the sidebars are explicit. - Use MDX components from
docs/src/components/**to keep styling consistent. - Run
vp run docs:buildbefore committing structural changes to confirm the static export succeeds.
Database and migrations
- Liquibase
<changeSet>s (schema deltas — not release changesets) live inserver/application/src/main/resources/db/changelog/. A schema change also needs a release changeset —.changeset/README.md. - Prefer
renameColumnormodifyDataTypewhen 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.nameand add typed fields withaddKeyValue. 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
.envor the respectiveapplication-*.ymlfiles. 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.