golid / rules
golid-ai/golid/.cursor/rules/codebase-standards.mdc
Core codebase standards — applies to every conversation.
Cursor rule40 starsChanged 4 months ago
- Reads credentials
---
description: Core codebase standards — applies to every conversation.
alwaysApply: true
---
# Codebase Standards
> **Thesis:** Universal guardrails that apply regardless of which file you're
> editing — the principles that every other rule assumes you follow.
## Core Guardrails
One-line reminders of the highest-consequence rules. Domain-specific rules
(go-service, solidjs-pages, etc.) have full explanations and examples.
- **Module spec mapping** — before modifying a module, read its spec at `docs/modules/{module}/spec.md`. Folders: `auth`, `users`, `feature`. Multi-file auth: `auth_password`, `auth_verify` → `auth` spec.
- **Parameterized queries only** — never `fmt.Sprintf` with values into SQL. Use `$N` placeholders for values; write literal SQL per call site for identifiers.
- **`apperror` for all errors** — never `echo.NewHTTPError`. Use `apperror.BadRequest`, `.Forbidden`, `.NotFound`, `.Validation`, `.Internal`.
- **`batch()` signal updates after every `await`** — put user-visible state like `setLoading(false)` inside both `try` and `catch`, wrapped in `batch()`. `finally` is only okay for independent re-entry locks that do not need to batch with success/error UI.
- **`Switch/Match` for content states** — never nested `<Show>` for loading/error/empty/data states.
- **`onMount` + signals for data fetching** — never `createResource`. Use `alive` guard and `loadRequestID` for param refetches. See `solidjs-data-fetching`.
- **Never early-return route components before reactive setup** — move auth/access guards into JSX with `<Show when={...} fallback={...}>`.
- **Never discard errors** — no `_ = fn()`. Log with `logger.Error` at minimum.
- **Resource membership, not just role** — verify the specific user belongs to the specific resource, not just `userType`.
- **Config over hardcoded values** — if you'd change it per environment, it belongs in `Config` or named constants.
- **Request body size limit** — `middleware.BodyLimit("1M")` is configured in `stack.go`.
- **SSE uses one-time ticket auth (not JWT in URL)** — see `handler/sse.go` and `service/sse/sse.go`.
- **Command lookup before shell work** — before running nontrivial local, test, deploy, GCP, Git, or contract-validation commands, read `common-commands` / `docs/cli-reference.md`, use known-good repo commands, and diagnose the first concrete failure instead of probing equivalent tools.
## Security
- Two-layer auth: handler calls `requireUserID` (authn), service calls `verifyResourceAccess` or equivalent (authz).
- **Selector/verifier pattern** for security tokens — never store tokens as plaintext. See `service/auth/auth_password.go` and `service/auth/auth_verify.go`.
- Webhook endpoints verify signatures (HMAC-SHA256). Never trust unverified webhooks.
## Opt-In Modules
- **`IsConfigured()` for opt-in modules** — queue, rate limiting, email, and tracing use `IsConfigured()` gates (`REDIS_URL`, `MAILGUN_API_KEY`, `OTEL_ENDPOINT`). When not configured, fall back gracefully. Both paths must be tested.
- **Never check `service != nil`** — use `service.IsConfigured()`. Opt-in services are always instantiated (never nil).
- **Dual-path pattern for queue** — `if h.queue.IsConfigured() { enqueue } else { go func() { Retry(...) }() }`.
- **Redis fail-open** — rate limiting and queue degrade when Redis is unreachable. Log the degradation.
## Operations
- **Shutdown order** — `e.Shutdown()` first (drain HTTP), then `sseHub.Shutdown()` (close SSE), then `defer db.Close()` (pool cleanup last via defer LIFO).
## Git Discipline
See `git-commits` rule for full conventions. Key points:
- **One logical change per commit** — don't bundle unrelated changes.
- **Spec drift before commit** — run `scripts/check_spec_drift.sh <base-ref>` before committing module-owned code changes; fix drift or include the required skip marker.
- **Branch naming** — `type/short-description` (e.g., `feat/notes-crud`, `fix/token-expiry`).
## Keep Rules and Docs In Sync
When a code change invalidates or reveals a gap in a rule or doc, update it in the same pass. Stale rules actively mislead.
- **Changed a convention or pattern?** Update the relevant `.cursor/rules/` file.
- **Changed a module's behavior?** Update `docs/modules/{module}/spec.md`.
- **Added/removed a component?** Update `frontend/src/components/index.ts`.
- **Changed deploy scripts or env vars?** Update `docs/` and `config/.env.example`.
- **Added a new route?** Add to `PRIVATE_ROUTES` in `frontend/src/lib/constants.ts`.
- **Found a bug pattern worth codifying?** Add to `audit-bugs.mdc` and the relevant domain rule.
- **Added or changed an API endpoint?** Update `backend/openapi.yaml`.
If unsure whether a rule is affected, grep `.cursor/rules/` for the pattern you changed.
## Keep Tests In Sync
When making code changes, update or add tests in the same pass. Don't ship code without corresponding tests.
- **Added a new API route?** Add handler tests: success, not-found, validation error, unauthorized.
- **Changed a service function?** Update tests to cover new/changed branches.
- **Added a new page/route?** Add a render test (loading state, loaded state with mocked API).
- **Changed a function signature?** Update all test call sites.
- **Removed code?** Remove or update tests for the removed behavior.
## Working Principles
- **Minimal impact** — changes should only touch what's necessary.
- **Stop and re-plan when stuck** — if a fix takes more than 2 attempts, stop and re-plan.
- **Verify before marking done** — run tests, typecheck, and build after every change.
- **Never run `-tags=integration` against the dev DB** — verify `TEST_DATABASE_URL` first. Full warning lives in `write-tests-planning`.
- **Change sizing** — keep each commit to one logical change, ideally under ~100 lines of diff. See `git-commits`.
- **Pre-merge audit gate** — before declaring a feature/card "done", run `audit-bugs` (module-scoped) or `audit-codebase` (cross-cutting).
## Anti-Rationalization
Workflow rules own their specific "don't skip the step" counters. When a task
touches tests, commits, audits, or spec sync, read the nearest active rule's
Anti-Rationalization section instead of relying on a generic reminder here.
## Rule Index
Non-globbed files (`cmd/server/main.go`, `internal/wire/*.go`, `internal/db/*.go`, `frontend/src/app.tsx`) use Core Guardrails as primary guidance — intentional, not a gap.
Domain rules fire automatically via file globs. For workflow tasks, invoke by name:
- **Workflow routing:** `workflow-routing` (classify T0–T3 before choosing plan, slice, audit, or review depth)
- **Common commands:** `common-commands` (known-good local/dev/test/deploy commands)
- **Git conventions:** `git-commits` (commit messages, branch naming, change sizing)
- **Any repo plan:** `planning-standards` (quality bar for `docs/plans/**/*.md`)
- **Plan a new feature:** `plan-feature` → `plan-feature-execution` → `slice-and-ship` / `plan-execution-loop` → domain rules → `write-tests` / `write-tests-planning` → `audit-bugs`
- **Plan infra/deploy/env work:** `plan-infra` → `deploy-infra` → `ci-workflow` as needed
- **Implement a planned feature:** `slice-and-ship` (implement → test → sync → audit → commit, one criterion at a time)
- **Document a module:** `document-module` → `audit-codebase` (verify)
- **Audit for bugs:** `audit-bugs` (single module) or `audit-codebase` (full system)
- **Spec drift check:** `scripts/check_spec_drift.sh` + `check_citation_freshness.sh` + `check_rule_health.sh` (see `ci-workflow`)
- **Refactor a large file:** `refactor-large-files`
- **Form/error patterns:** `frontend-forms`
- **Create or maintain a rule:** `write-rules`
- **Dynamic image endpoints:** `dynamic-image-endpoints` (renderer + ETag) → `dynamic-image-http` (cache posture, render budget, max bytes)
- **Frontend tests:** `write-tests-frontend` → `write-tests-frontend-workflow`; **E2E:** `write-tests-e2e`; **backend tests:** `write-tests` → `write-tests-planning`
- **Module specs:** `docs/modules/{module}/spec.md` — auth, users, feature
- **Frontend routing:** `solidstart-routing` — `(private)` / `(public)` groups and `PRIVATE_ROUTES`
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

