|
| 1 | +# Repository Guidelines |
| 2 | + |
| 3 | +## Project Structure & Module Organization |
| 4 | +- `backend/`: Go service. `cmd/server` is the entrypoint, `internal/` contains handlers/services/repositories/server wiring, `ent/` holds Ent schemas and generated ORM code, `migrations/` stores DB migrations, and `internal/web/dist/` is the embedded frontend build output. |
| 5 | +- `frontend/`: Vue 3 + TypeScript app. Main folders are `src/api`, `src/components`, `src/views`, `src/stores`, `src/composables`, `src/utils`, and test files in `src/**/__tests__`. |
| 6 | +- `deploy/`: Docker and deployment assets (`docker-compose*.yml`, `.env.example`, `config.example.yaml`). |
| 7 | +- `openspec/`: Spec-driven change docs (`changes/<id>/{proposal,design,tasks}.md`). |
| 8 | +- `tools/`: Utility scripts (security/perf checks). |
| 9 | + |
| 10 | +## Build, Test, and Development Commands |
| 11 | +```bash |
| 12 | +make build # Build backend + frontend |
| 13 | +make test # Backend tests + frontend lint/typecheck |
| 14 | +cd backend && make build # Build backend binary |
| 15 | +cd backend && make test-unit # Go unit tests |
| 16 | +cd backend && make test-integration # Go integration tests |
| 17 | +cd backend && make test # go test ./... + golangci-lint |
| 18 | +cd frontend && pnpm install --frozen-lockfile |
| 19 | +cd frontend && pnpm dev # Vite dev server |
| 20 | +cd frontend && pnpm build # Type-check + production build |
| 21 | +cd frontend && pnpm test:run # Vitest run |
| 22 | +cd frontend && pnpm test:coverage # Vitest + coverage report |
| 23 | +python3 tools/secret_scan.py # Secret scan |
| 24 | +``` |
| 25 | + |
| 26 | +## Coding Style & Naming Conventions |
| 27 | +- Go: format with `gofmt`; lint with `golangci-lint` (`backend/.golangci.yml`). |
| 28 | +- Respect layering: `internal/service` and `internal/handler` must not import `internal/repository`, `gorm`, or `redis` directly (enforced by depguard). |
| 29 | +- Frontend: Vue SFC + TypeScript, 2-space indentation, ESLint rules from `frontend/.eslintrc.cjs`. |
| 30 | +- Naming: components use `PascalCase.vue`, composables use `useXxx.ts`, Go tests use `*_test.go`, frontend tests use `*.spec.ts`. |
| 31 | + |
| 32 | +## Go & Frontend Development Standards |
| 33 | +- Control branch complexity: `if` nesting must not exceed 3 levels. Refactor with guard clauses, early returns, helper functions, or strategy maps when deeper logic appears. |
| 34 | +- JSON hot-path rule: for read-only/partial-field extraction, prefer `gjson` over full `encoding/json` struct unmarshal to reduce allocations and improve latency. |
| 35 | +- Exception rule: if full schema validation or typed writes are required, `encoding/json` is allowed, but PR must explain why `gjson` is not suitable. |
| 36 | + |
| 37 | +### Go Performance Rules |
| 38 | +- Optimization workflow rule: benchmark/profile first, then optimize. Use `go test -bench`, `go tool pprof`, and runtime diagnostics before changing hot-path code. |
| 39 | +- For hot functions, run escape analysis (`go build -gcflags=all='-m -m'`) and prioritize stack allocation where reasonable. |
| 40 | +- Every external I/O path must use `context.Context` with explicit timeout/cancel. |
| 41 | +- When creating derived contexts (`WithTimeout` / `WithDeadline`), always `defer cancel()` to release resources. |
| 42 | +- Preallocate slices/maps when size can be estimated (`make([]T, 0, n)`, `make(map[K]V, n)`). |
| 43 | +- Avoid unnecessary allocations in loops; reuse buffers and prefer `strings.Builder`/`bytes.Buffer`. |
| 44 | +- Prohibit N+1 query patterns; batch DB/Redis operations and verify indexes for new query paths. |
| 45 | +- For hot-path changes, include benchmark or latency comparison evidence (e.g., `go test -bench` before/after). |
| 46 | +- Keep goroutine growth bounded (worker pool/semaphore), and avoid unbounded fan-out. |
| 47 | +- 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. |
| 48 | +- When locks are unavoidable, keep critical sections minimal, avoid nested locks, and document why lock-free alternatives are not feasible. |
| 49 | +- Follow `sync` guidance: prefer channels for higher-level synchronization; use low-level mutex primitives only where necessary. |
| 50 | +- Avoid reflection and `interface{}`-heavy conversions in hot paths; use typed structs/functions. |
| 51 | +- Use `sync.Pool` only when benchmark proves allocation reduction; remove if no measurable gain. |
| 52 | +- Avoid repeated `time.Now()`/`fmt.Sprintf` in tight loops; hoist or cache when possible. |
| 53 | +- For stable high-traffic binaries, maintain representative `default.pgo` profiles and keep `go build -pgo=auto` enabled. |
| 54 | + |
| 55 | +### Data Access & Cache Rules |
| 56 | +- Every new/changed SQL query must be checked with `EXPLAIN` (or `EXPLAIN ANALYZE` in staging) and include index rationale in PR. |
| 57 | +- Default to keyset pagination for large tables; avoid deep `OFFSET` scans on hot endpoints. |
| 58 | +- Query only required columns; prohibit broad `SELECT *` in latency-sensitive paths. |
| 59 | +- Keep transactions short; never perform external RPC/network calls inside DB transactions. |
| 60 | +- Connection pool must be explicitly tuned and observed via `DB.Stats` (`SetMaxOpenConns`, `SetMaxIdleConns`, `SetConnMaxIdleTime`, `SetConnMaxLifetime`). |
| 61 | +- Avoid overly small `MaxOpenConns` that can turn DB access into lock/semaphore bottlenecks. |
| 62 | +- Cache keys must be versioned (e.g., `user_usage:v2:{id}`) and TTL should include jitter to avoid thundering herd. |
| 63 | +- Use request coalescing (`singleflight` or equivalent) for high-concurrency cache miss paths. |
| 64 | + |
| 65 | +### Frontend Performance Rules |
| 66 | +- Route-level and heavy-module code splitting is required; lazy-load non-critical views/components. |
| 67 | +- API requests must support cancellation and deduplication; use debounce/throttle for search-like inputs. |
| 68 | +- Minimize unnecessary reactivity: avoid deep watch chains when computed/cache can solve it. |
| 69 | +- Prefer stable props and selective rendering controls (`v-once`, `v-memo`) for expensive subtrees when data is static or keyed. |
| 70 | +- Large data rendering must use pagination or virtualization (especially tables/lists >200 rows). |
| 71 | +- Move expensive CPU work off the main thread (Web Worker) or chunk tasks to avoid UI blocking. |
| 72 | +- Keep bundle growth controlled; avoid adding heavy dependencies without clear ROI and alternatives review. |
| 73 | +- Avoid expensive inline computations in templates; move to cached `computed` selectors. |
| 74 | +- Keep state normalized; avoid duplicated derived state across multiple stores/components. |
| 75 | +- Load charts/editors/export libraries on demand only (`dynamic import`) instead of app-entry import. |
| 76 | +- Core Web Vitals targets (p75): `LCP <= 2.5s`, `INP <= 200ms`, `CLS <= 0.1`. |
| 77 | +- Main-thread task budget: keep individual tasks below ~50ms; split long tasks and yield between chunks. |
| 78 | +- Enforce frontend budgets in CI (Lighthouse CI with `budget.json`) for critical routes. |
| 79 | + |
| 80 | +### Performance Budget & PR Evidence |
| 81 | +- Performance budget is mandatory for hot-path PRs: backend p95/p99 latency and CPU/memory must not regress by more than 5% versus baseline. |
| 82 | +- Frontend budget: new route-level JS should not increase by more than 30KB gzip without explicit approval. |
| 83 | +- For any gateway/protocol hot path, attach a reproducible benchmark command and results (input size, concurrency, before/after table). |
| 84 | +- Profiling evidence is required for major optimizations (`pprof`, flamegraph, browser performance trace, or bundle analyzer output). |
| 85 | + |
| 86 | +### Quality Gate |
| 87 | +- Any changed code must include new or updated unit tests. |
| 88 | +- Coverage must stay above 85% (global frontend threshold and no regressions for touched backend modules). |
| 89 | +- If any rule is intentionally violated, document reason, risk, and mitigation in the PR description. |
| 90 | + |
| 91 | +## Testing Guidelines |
| 92 | +- Backend suites: `go test -tags=unit ./...`, `go test -tags=integration ./...`, and e2e where relevant. |
| 93 | +- Frontend uses Vitest (`jsdom`); keep tests near modules (`__tests__`) or as `*.spec.ts`. |
| 94 | +- Enforce unit-test and coverage rules defined in `Quality Gate`. |
| 95 | +- Before opening a PR, run `make test` plus targeted tests for touched areas. |
| 96 | + |
| 97 | +## Commit & Pull Request Guidelines |
| 98 | +- Follow Conventional Commits: `feat(scope): ...`, `fix(scope): ...`, `chore(scope): ...`, `docs(scope): ...`. |
| 99 | +- PRs should include a clear summary, linked issue/spec, commands run for verification, and screenshots/GIFs for UI changes. |
| 100 | +- For behavior/API changes, add or update `openspec/changes/...` artifacts. |
| 101 | +- If dependencies change, commit `frontend/pnpm-lock.yaml` in the same PR. |
| 102 | + |
| 103 | +## Security & Configuration Tips |
| 104 | +- Use `deploy/.env.example` and `deploy/config.example.yaml` as templates; do not commit real credentials. |
| 105 | +- Set stable `JWT_SECRET`, `TOTP_ENCRYPTION_KEY`, and strong database passwords outside local dev. |
0 commit comments