8.3 KiB
8.3 KiB
Repository Guidelines
Project Structure & Module Organization
backend/: Go service.cmd/serveris the entrypoint,internal/contains handlers/services/repositories/server wiring,ent/holds Ent schemas and generated ORM code,migrations/stores DB migrations, andinternal/web/dist/is the embedded frontend build output.frontend/: Vue 3 + TypeScript app. Main folders aresrc/api,src/components,src/views,src/stores,src/composables,src/utils, and test files insrc/**/__tests__.deploy/: Docker and deployment assets (docker-compose*.yml,.env.example,config.example.yaml).openspec/: Spec-driven change docs (changes/<id>/{proposal,design,tasks}.md).tools/: Utility scripts (security/perf checks).
Build, Test, and Development Commands
make build # Build backend + frontend
make test # Backend tests + frontend lint/typecheck
cd backend && make build # Build backend binary
cd backend && make test-unit # Go unit tests
cd backend && make test-integration # Go integration tests
cd backend && make test # go test ./... + golangci-lint
cd frontend && pnpm install --frozen-lockfile
cd frontend && pnpm dev # Vite dev server
cd frontend && pnpm build # Type-check + production build
cd frontend && pnpm test:run # Vitest run
cd frontend && pnpm test:coverage # Vitest + coverage report
python3 tools/secret_scan.py # Secret scan
Coding Style & Naming Conventions
- Go: format with
gofmt; lint withgolangci-lint(backend/.golangci.yml). - Respect layering:
internal/serviceandinternal/handlermust not importinternal/repository,gorm, orredisdirectly (enforced by depguard). - Frontend: Vue SFC + TypeScript, 2-space indentation, ESLint rules from
frontend/.eslintrc.cjs. - Naming: components use
PascalCase.vue, composables useuseXxx.ts, Go tests use*_test.go, frontend tests use*.spec.ts.
Go & Frontend Development Standards
- Control branch complexity:
ifnesting must not exceed 3 levels. Refactor with guard clauses, early returns, helper functions, or strategy maps when deeper logic appears. - JSON hot-path rule: for read-only/partial-field extraction, prefer
gjsonover fullencoding/jsonstruct unmarshal to reduce allocations and improve latency. - Exception rule: if full schema validation or typed writes are required,
encoding/jsonis allowed, but PR must explain whygjsonis not suitable.
Go Performance Rules
- Optimization workflow rule: benchmark/profile first, then optimize. Use
go test -bench,go tool pprof, and runtime diagnostics before changing hot-path code. - For hot functions, run escape analysis (
go build -gcflags=all='-m -m') and prioritize stack allocation where reasonable. - Every external I/O path must use
context.Contextwith explicit timeout/cancel. - When creating derived contexts (
WithTimeout/WithDeadline), alwaysdefer cancel()to release resources. - Preallocate slices/maps when size can be estimated (
make([]T, 0, n),make(map[K]V, n)). - Avoid unnecessary allocations in loops; reuse buffers and prefer
strings.Builder/bytes.Buffer. - Prohibit N+1 query patterns; batch DB/Redis operations and verify indexes for new query paths.
- For hot-path changes, include benchmark or latency comparison evidence (e.g.,
go test -benchbefore/after). - Keep goroutine growth bounded (worker pool/semaphore), and avoid unbounded fan-out.
- Lock minimization rule: if a lock can be avoided, do not use a lock. Prefer ownership transfer (channel), sharding, immutable snapshots, copy-on-write, or atomic operations to reduce contention.
- When locks are unavoidable, keep critical sections minimal, avoid nested locks, and document why lock-free alternatives are not feasible.
- Follow
syncguidance: prefer channels for higher-level synchronization; use low-level mutex primitives only where necessary. - Avoid reflection and
interface{}-heavy conversions in hot paths; use typed structs/functions. - Use
sync.Poolonly when benchmark proves allocation reduction; remove if no measurable gain. - Avoid repeated
time.Now()/fmt.Sprintfin tight loops; hoist or cache when possible. - For stable high-traffic binaries, maintain representative
default.pgoprofiles and keepgo build -pgo=autoenabled.
Data Access & Cache Rules
- Every new/changed SQL query must be checked with
EXPLAIN(orEXPLAIN ANALYZEin staging) and include index rationale in PR. - Default to keyset pagination for large tables; avoid deep
OFFSETscans on hot endpoints. - Query only required columns; prohibit broad
SELECT *in latency-sensitive paths. - Keep transactions short; never perform external RPC/network calls inside DB transactions.
- Connection pool must be explicitly tuned and observed via
DB.Stats(SetMaxOpenConns,SetMaxIdleConns,SetConnMaxIdleTime,SetConnMaxLifetime). - Avoid overly small
MaxOpenConnsthat can turn DB access into lock/semaphore bottlenecks. - Cache keys must be versioned (e.g.,
user_usage:v2:{id}) and TTL should include jitter to avoid thundering herd. - Use request coalescing (
singleflightor equivalent) for high-concurrency cache miss paths.
Frontend Performance Rules
- Route-level and heavy-module code splitting is required; lazy-load non-critical views/components.
- API requests must support cancellation and deduplication; use debounce/throttle for search-like inputs.
- Minimize unnecessary reactivity: avoid deep watch chains when computed/cache can solve it.
- Prefer stable props and selective rendering controls (
v-once,v-memo) for expensive subtrees when data is static or keyed. - Large data rendering must use pagination or virtualization (especially tables/lists >200 rows).
- Move expensive CPU work off the main thread (Web Worker) or chunk tasks to avoid UI blocking.
- Keep bundle growth controlled; avoid adding heavy dependencies without clear ROI and alternatives review.
- Avoid expensive inline computations in templates; move to cached
computedselectors. - Keep state normalized; avoid duplicated derived state across multiple stores/components.
- Load charts/editors/export libraries on demand only (
dynamic import) instead of app-entry import. - Core Web Vitals targets (p75):
LCP <= 2.5s,INP <= 200ms,CLS <= 0.1. - Main-thread task budget: keep individual tasks below ~50ms; split long tasks and yield between chunks.
- Enforce frontend budgets in CI (Lighthouse CI with
budget.json) for critical routes.
Performance Budget & PR Evidence
- Performance budget is mandatory for hot-path PRs: backend p95/p99 latency and CPU/memory must not regress by more than 5% versus baseline.
- Frontend budget: new route-level JS should not increase by more than 30KB gzip without explicit approval.
- For any gateway/protocol hot path, attach a reproducible benchmark command and results (input size, concurrency, before/after table).
- Profiling evidence is required for major optimizations (
pprof, flamegraph, browser performance trace, or bundle analyzer output).
Quality Gate
- Any changed code must include new or updated unit tests.
- Coverage must stay above 85% (global frontend threshold and no regressions for touched backend modules).
- If any rule is intentionally violated, document reason, risk, and mitigation in the PR description.
Testing Guidelines
- Backend suites:
go test -tags=unit ./...,go test -tags=integration ./..., and e2e where relevant. - Frontend uses Vitest (
jsdom); keep tests near modules (__tests__) or as*.spec.ts. - Enforce unit-test and coverage rules defined in
Quality Gate. - Before opening a PR, run
make testplus targeted tests for touched areas.
Commit & Pull Request Guidelines
- Follow Conventional Commits:
feat(scope): ...,fix(scope): ...,chore(scope): ...,docs(scope): .... - PRs should include a clear summary, linked issue/spec, commands run for verification, and screenshots/GIFs for UI changes.
- For behavior/API changes, add or update
openspec/changes/...artifacts. - If dependencies change, commit
frontend/pnpm-lock.yamlin the same PR.
Security & Configuration Tips
- Use
deploy/.env.exampleanddeploy/config.example.yamlas templates; do not commit real credentials. - Set stable
JWT_SECRET,TOTP_ENCRYPTION_KEY, and strong database passwords outside local dev.