Conventions
File-size limits, structural conformity, conventional commits, i18n string naming, and error handling.
File size limits
CI enforces file size limits to keep code maintainable. These are hard limits — the pipeline fails if they are exceeded.
| File type | Limit | Scope |
|---|---|---|
| Go files | 400 lines | Excludes generated files (internal/db/gen/) and test files |
| Svelte components | 250 lines | All .svelte files |
If a file approaches the limit, split it. Every file should have a single responsibility. The goal is a codebase where any file can be read and understood without scrolling.
Structural conformity
Before writing any new code, find an existing example of the same pattern and follow it exactly. Never introduce a pattern that has no precedent in the codebase.
| What you're building | Where to look |
|---|---|
| New API endpoint | internal/api/cards.go — huma.Register pattern |
| New sqlc query | internal/db/queries/cards.sql — query style |
| New job type | internal/jobs/handlers_track_edit.go — Register + handler pattern |
| New Svelte component | An existing component of similar size and purpose |
| New API client function | frontend/src/lib/api/client.ts — existing function style |
| Error handling in Go | Err(ctx, status, msg, err) — never raw errors |
| Error handling in Svelte | const { data, error } = await client.X() — never raw fetch |
| Icons | Phosphor duotone only — import X from 'phosphor-svelte/lib/X' |
Conventional commits
All commits follow the
Conventional Commits
specification. The type prefix is required.
Type When to use featA new feature fixA bug fix docsDocumentation only changes refactorCode change that neither fixes a bug nor adds a feature testAdding or correcting tests choreTooling, deps, CI changes
Example: fix(cards): return 404 when card slug not found
Internationalization (i18n)
All user-facing strings live in frontend/messages/en.json and are accessed
via Paraglide JS.
CI fails on hardcoded English strings in Svelte files.
Key naming convention: area_context_description.
Prefix Area nav_Sidebar / navigation cards_Card grid, selectors tracks_Track list, detail editor publish_Publish matrix, progress icons_Icon generation, editor settings_Settings page admin_Admin panel common_Shared labels (Cancel, Save, Close, etc.) aria_Accessibility labels
Error handling
Go handlers must use named error constants from internal/api/errors.go
— never invent error strings inline:
// Correct — pick from the catalog
return nil, ErrCardNotFound
// Wrong — inventing a string
return nil, huma.Error404NotFound("card not found")
The Err(logger, status, msg, err) helper in internal/api/helpers.go
logs the error and returns a huma error response in one call. Use it for all error paths
that are not covered by a named constant.
Package READMEs
Every internal/ package has a README.md explaining its purpose,
dependencies, and dependents. Read it before modifying a package. Keep it current
when adding new dependencies or changing the package's scope.