138 lines
4.6 KiB
Markdown
138 lines
4.6 KiB
Markdown
# Debug Protocol (Repo)
|
||
|
||
> You are debugging an issue in this repo. Do **not** implement features unless required to fix the bug.
|
||
|
||
## 0) Non-negotiables
|
||
|
||
- **Source of truth:** `PROJECT_INSTRUCTIONS.md` (repo root). If anything conflicts, follow it.
|
||
- **No assumptions:** First scan the repo for existing patterns, locations, scripts, helpers, and conventions. Don’t invent missing files/endpoints unless truly necessary—and if needed, add minimally and consistently.
|
||
- **External DB:** `DATABASE_URL` points to on-prem Postgres (**not** a container). Dev/Prod share schema via migrations in `packages/db/migrations`.
|
||
- **Security:** Never log secrets, full invite codes, or receipt bytes. Invite codes in logs/audit: **last4 only**.
|
||
- **No cron/worker jobs:** Any fix must work without background tasks.
|
||
- **Server-side RBAC only:** Client checks are UX only.
|
||
|
||
---
|
||
|
||
## 1) Restate the bug precisely
|
||
|
||
Start by writing a 4–6 line **Bug Definition**:
|
||
|
||
- **Expected behavior**
|
||
- **Actual behavior**
|
||
- **Where it happens** (page / route / service)
|
||
- **Impact** (blocker? regression? edge case?)
|
||
|
||
If any of these are missing, ask for them explicitly.
|
||
|
||
---
|
||
|
||
## 2) Collect an evidence bundle before changing code
|
||
|
||
Before editing anything, request/locate:
|
||
|
||
### A) Runtime signals
|
||
- Exact error text + stack trace (server + browser console)
|
||
- Network capture: request URL, method, status, response body
|
||
- Any `request_id` returned by the API for failing calls
|
||
|
||
### B) Repo + environment
|
||
- Current branch/commit
|
||
- How app is started (`docker-compose` + which file)
|
||
- Node version + package manager used
|
||
- Relevant env vars (sanitized): `DATABASE_URL` **host/port/dbname only** (no password)
|
||
|
||
### C) Involved code paths
|
||
Identify actual files by searching the repo:
|
||
- The page/component triggering the request
|
||
- The hook used (`hooks/use-*.ts`)
|
||
- The client wrapper (`lib/client/*`)
|
||
- The API route (`app/api/**/route.ts`)
|
||
- The server service (`lib/server/*.ts`)
|
||
|
||
**Do not guess file names. Use repo search.**
|
||
|
||
---
|
||
|
||
## 3) Determine failure class (choose ONE primary)
|
||
|
||
Pick the most likely bucket and focus there first:
|
||
|
||
- DB connectivity / docker networking
|
||
- Migrations/schema mismatch
|
||
- Auth/session cookie flow (HttpOnly cookies, session table, logout)
|
||
- RBAC / group membership / active group
|
||
- Request validation / parsing (route boundary)
|
||
- Client fetch wrapper / hook state
|
||
- UI behavior / event handling / mobile UX
|
||
- Playwright test failure (timing, selectors, baseURL, auth state)
|
||
|
||
Write a **3–5 bullet** hypothesis list ordered by likelihood.
|
||
|
||
---
|
||
|
||
## 4) Reproduce locally with the smallest surface area
|
||
|
||
Prefer reproducing via:
|
||
1) A single API call (`curl` / minimal `fetch`) before full UI if possible
|
||
2) Then UI repro
|
||
3) Then Playwright repro (if it’s a test failure)
|
||
|
||
If scripts are needed, inspect `package.json` for actual script names (**don’t assume**). Common ones may exist (`lint`, `test`, `db:migrate`) but confirm.
|
||
|
||
---
|
||
|
||
## 5) Add targeted observability (minimal + removable)
|
||
|
||
If evidence is insufficient, add temporary, minimal logs in **server services** (not in UI):
|
||
|
||
- Always include `request_id`
|
||
- Log only safe metadata (`user_id`, `group_id`, route name, timing)
|
||
- Never log secrets/full invite code/receipt bytes/passwords/tokens
|
||
- If touching invite logic: log **last4 only**
|
||
|
||
Prefer:
|
||
- One log line at service entry (inputs summary)
|
||
- One log line at decision points (auth fail / membership fail / db row missing)
|
||
- One log line at service exit (success + timing)
|
||
|
||
Remove or downgrade noisy logs before final PR unless clearly valuable.
|
||
|
||
---
|
||
|
||
## 6) Fix strategy rules
|
||
|
||
- Make the smallest change that resolves the bug.
|
||
- Respect layering:
|
||
- **Route:** parse + validate shape
|
||
- **Server service:** DB + authz + business rules
|
||
- **Client wrapper:** typed fetch + error normalization
|
||
- **Hook:** UI-facing API layer
|
||
- Don’t introduce new dependencies unless absolutely necessary.
|
||
- Keep touched files free of TS warnings and lint errors.
|
||
|
||
---
|
||
|
||
## 7) Verification checklist (must do)
|
||
|
||
After the fix:
|
||
- Re-run the minimal repro (API and/or UI)
|
||
- Run relevant tests (unit + Playwright if applicable)
|
||
- Add/adjust tests for the bug:
|
||
- At least **1 positive** + **2 negatives** (unauthorized, not-a-member, invalid input)
|
||
- Confirm contracts:
|
||
- Spendings list never includes receipt bytes
|
||
- Sessions are HttpOnly + DB-backed
|
||
- Audit logs include `request_id` and never store full invite code
|
||
|
||
---
|
||
|
||
## 8) Next.js route params checklist (required)
|
||
|
||
For `app/api/**/[param]/route.ts`:
|
||
- Treat `context.params` as **async** and `await` it before reading properties.
|
||
- If you see errors about sync dynamic APIs, update handlers to unwrap params:
|
||
|
||
Example:
|
||
```ts
|
||
const { id } = await context.params;
|