Code Conventions
These conventions keep the codebase consistent and CI green. Match the style of the surrounding code, and follow the rules below.
Spec-first backend
Section titled “Spec-first backend”backend/openapi.yaml — bundled from paths/ + schemas/ — is the single
source of truth for the API. You change the API by changing the spec, not by
hand-writing handlers.
The following are generated and committed, and must never be hand-edited:
- the oapi-codegen strict-server bindings,
- the Wire dependency-injection graph (
internal/container/wire_gen.go), - the mocks (
mock_*.go).
Regenerate them with make, never by editing the generated files directly:
make backend-generate-openapi-server # regenerate server bindings from the specmake backend-wire-gen # regenerate the Wire DI graphmake backend-mock-generate # regenerate mocksGenerated files must stay gofmt -s clean, and CI fails a PR when generated
code is stale relative to the spec (for example, backend-wire-check fails if
wire_gen.go drifts). See
Code Generation for the full set of
commands.
API change flow
Section titled “API change flow”A change that touches the API contract flows through three repos in order:
- Update
backend/openapi.yaml(viapaths/+schemas/) and regenerate the server bindings. - Merge to
main. Both generated clients (@vibexp/api-clienton npm,github.com/vibexp/api-client-goGo module) publish automatically with an auto-minor bump, dispatched bypublish-api-client.yml. Do not hand-publish or hand-tag either client: publishing by hand races the automation and can duplicate a version. - Bump the
@vibexp/api-clientdependency in the frontend and build against it.
Deployment-agnostic frontend
Section titled “Deployment-agnostic frontend”The frontend never hardcodes a backend origin. It is built with a relative base URL:
VITE_API_BASE_URL=/api/v1In production, the backend serves the SPA from the same origin as the API
(the combined image), so relative requests just work. Keep API calls relative so
the same build runs against any deployment. Likewise, deploy-time frontend
values (branding, MCP endpoint, analytics) are injected at runtime via the
backend-rendered /config.js (window.__VIBEXP_ENV__) — never baked into the
bundle.
No precaching service worker
Section titled “No precaching service worker”VibeXP does not ship a PWA/precaching service worker, and web push
(Firebase) was removed in v0.9.0. src/utils/serviceWorker.ts and
public/{sw,dev-sw}.js exist solely to evict legacy workers from returning
browsers. Do not reintroduce a precaching service worker without a cleanup
story.
Secrets and environment
Section titled “Secrets and environment”.envis gitignored — never commit it.- Only
.env.exampleis tracked, and it uses neutral placeholder values (e.g.example.com) because the repository is public and self-hosted. - On the backend, read configuration through the config package, not
os.Getenv(a pre-commit hook blocksos.Getenv).
Match the conventions of the code around your change. The linters
(golangci-lint on the backend, ESLint + tsc on the frontend) are the
authority — run them locally before committing. See
Pre-commit & CI for the full
list of gated checks.