lifeos handbook
Reference

Conventions

Naming, layout, comments, and what the build actually enforces.

Naming

ThingConventionExample
Java packagecc.ringojr.lifeos.<app-or-platform>.<feature>cc.ringojr.lifeos.iam.credential.service
Gradle moduleshort, flat, no path:platform-core, :iam, :finloop
Gradle convention pluginlifeos.<kind>id("lifeos.spring-boot-app")
Config namespacelifeos.<area>lifeos.security.audience
App identityone lowercase word = app id = scope = audiencefinloop
OAuth2 client id<app-id>-webfinloop-web
Hostnames<app>.ringojr.cc, <app>-backend.ringojr.ccfinloop-backend.ringojr.cc
Liquibase changesetsNNN-kebab-name.yaml070-bill-settles-account.yaml
Frontend fileskebab-case, named exports, @/ aliasraise-transaction-form.tsx

Gradle project names are :finloop and :iamnot :apps:finloop:backend. The directory layout and the project name are mapped explicitly in settings.gradle.kts.

Backend

Package-by-feature, then by layer inside the feature: login/{controller,service,repository,model,dto,enums}. Top-level enums live in an enums package, and ArchUnit enforces it.

  • Controllers stay thin: validate, call a service, map output.
  • Constructor injection via Lombok @RequiredArgsConstructor. An @Autowired field fails the build.
  • Import types; never fully-qualify inline.
  • The response envelope is {success, message, payload}payload, not data.

Frontend

  • Feature modules: modules/<feature>/lib/{types,consts,service,hooks} plus components/.
  • Server state lives in TanStack Query. Zustand is for genuinely global client state, which in practice means auth and nothing else.
  • A screen gates on its query state with early returns, rendering one loading or error state — never half a page.
  • The React Compiler handles memoization. Do not hand-write useMemo, useCallback or memo.
  • Biome owns formatting: single quotes, no semicolons, no bracket spacing, 100 columns.

Comments

Default to zero. A comment earns its place only when it records something the code genuinely cannot say: a real gotcha, a non-obvious why, a workaround, or a business rule. Never restate the code, label structure, or echo a signature.

The one deliberate exception is an improvisation — where a wall was worked around, a short comment at the site is what makes it discoverable months later by someone reading the code rather than a report that has scrolled away.

The gates, and one rule about them

./gradlew build --rerun-tasks
bun run check
bunx tsc --noEmit
bunx vite build
bunx vitest run

Never claim green without pasting real output. "Should pass" is not a result, and BUILD SUCCESSFUL over a set of UP-TO-DATE tasks is a cache hit, not a verification.

On this page