vibe-backend
EN繁

Source: docs/best-practices/README.md

#Best Practices

This directory collects best-practice patterns for writing Markdown-driven backend definitions. Every page is written strictly against docs/spec-v1.7.md, the current finalized spec. Section references such as "§7.2" or "Decision 48" point to that spec. The older docs/spec-v1.5.md is kept for historical reference only.

Spec version note: these pages were revised for spec v1.7 (issue #17). Main changes from the v1.5 edition: optimistic locking uses ETag/If-Match with 428/412 (Decision 48); public registration takes no password and always returns 202 (Decisions 56, 67); login requires a verified email (Decision 55); admin user creation is an invite flow (Decision 69); API-key, JWT, rate-limit, refresh-token and LLM-provider settings follow the values v1.7 now specifies (Decisions 43–45, 57–59, 61, 62, 65, 72). If a page and the spec disagree, the spec wins.

Each page has the same structure:

  1. Purpose – what the pattern is for and when to use it.
  2. Natural-language source example – the .md file a human writes (§2.2).
  3. Compiled lock md example – the {name}.lock.md the compiler produces (§2A). Lock files are generated by the compiler and must never be hand-written or hand-edited; the examples here are illustrative only.
  4. Security considerations – the rules the deterministic validator enforces (§10) and what reviewers must check (§2A.5).
  5. Spec gaps – anything v1.7 leaves unspecified or states inconsistently. Where the spec does not define something, these pages say so instead of guessing.

The spec itself is written in Cantonese; source examples here are in English. Natural-language source can be written in any language; only the compiled lock is authoritative at runtime (§2.1).

#Conventions used in examples

  • Approver names (jack@example, mei@example), PR numbers (pr#121 …) and commit ids in lock frontmatter are fictional, copied in style from the spec examples.
  • Hashes, signatures and commit ids are shortened placeholders (sha256:9a1c...e2, MEUCIQ...), exactly as in the spec examples.
  • When a lock is shown as an excerpt ("sections only"), the frontmatter follows §2A.1 exactly; api locks additionally carry scope: (§2A.3).
  • Sections not used by a lock are written as (none) (§2A.2).

#Index

Topic Page
Auth pipeline – JWT (and admin invite via create-user) auth-jwt.md
Auth pipeline – API key auth-api-key.md
CRUD – offset pagination crud-offset-pagination.md
CRUD – optimistic locking (ETag/If-Match) crud-optimistic-locking.md
CRUD – soft delete crud-soft-delete.md
Registration (user.self-register, user.complete-verification, admin user.register) user-register.md
user.login user-login.md
sign-token (token issuance capability) sign-token.md
Refresh token rotation refresh-token-rotation.md
Rate limiting rate-limit.md
Public writes public-writes.md
Privacy deletion (crypto-shredding + anonymization) privacy-deletion.md
LLM provider setup (compiler endpoint) llm-provider-setup.md

#Cross-cutting rules (apply to every page)

  • Runtime never interprets natural language; only approved, signed locks (via the signed manifest) are executed (§2.1, §9).
  • Every endpoint goes through auth by default; removing it (-auth) requires public: true (§3, §4).
  • No DELETE or TRUNCATE SQL in any lock, and no DDL outside kind: migration locks; every UPDATE needs a WHERE plus scope: pk | rls (§2A.4, §2B, Decisions 27, 51).
  • SQL is parameterized ($1, $2 + params), single-statement (§2A.2, §2A.4).
  • Natural-language locks and any lock touching a security item need manual approval; high-risk items need two non-author owners/maintainers; max 5 security items per PR across all its locks (§2A.5, Decisions 19, 33, 34).
  • Row-level ownership inside a tenant uses owner-key (Decision 70, §12.6a); RLS alone only isolates tenants.
  • Secrets (DB connections, JWT keys, LLM keys) appear only as references, never in source, lock, manifest or logs (§2A.8.5, §9B). Audit never records plaintext email (Decision 68).