docs: token actor, connection deleted_at and CSRF decisions; follow-ups
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5f7d54b805
commit
0b34ede62e
@@ -26,9 +26,11 @@ user layer or files a Changes-inbox event.
|
||||
HTTP request (`apps/server`):
|
||||
1. `Bun.serve` routes `/api/*` and `/ingest/*` to `app.fetch`; everything else gets the web app (HTML import).
|
||||
2. `apiHandler` matches method + path in the route table, applies the per-IP rate limit (login/register), authenticates
|
||||
(`session` cookie `stt_session`, Bearer app token with a scope, or either), checks `X-Requested-With: sttracker` on
|
||||
cookie-authenticated writes, reads the body (JSON ≤ 1 MB, multipart ≤ 50 MB) and validates it with zod.
|
||||
3. The handler calls one core function with the caller's `userId` and actor `"user"`. Core enforces ownership
|
||||
(`session` cookie `stt_session`, Bearer app token with a scope, or either), requires `X-Requested-With: sttracker` on
|
||||
every non-Bearer write (login included), reads the body (JSON ≤ 1 MB with `Content-Type: application/json`,
|
||||
multipart ≤ 50 MB) and validates it with zod.
|
||||
3. The handler calls one core function with the caller's `userId` and actor (`token:<name>` for Bearer, else `"user"`;
|
||||
`field_sources` stores both as `"user"`). Core enforces ownership
|
||||
(`NotFoundError` → 404). Errors become `{ error: { code, message } }`; unknown errors are logged and return 500 `internal`.
|
||||
4. `POST sources/:id/run|import` only enqueue a `sync` job (lockKey `sync:<id>`, 409 when held); the worker runs it.
|
||||
|
||||
|
||||
@@ -4,6 +4,24 @@ Append-only. Never edit or delete an entry. Supersede it with a new one that lin
|
||||
One entry per decision a future maintainer would otherwise have to reverse-engineer.
|
||||
No index: `grep -n '^## ' docs/DECISIONS.md` lists every entry (date, title, line number).
|
||||
|
||||
## 2026-10-30: Token actor in history, connection deleted_at, CSRF on every browser write
|
||||
**Status:** accepted. Supersedes the **Actor**, **CSRF** and **Deleted connections** bullets of
|
||||
"HTTP API: auth modes, CSRF header, error mapping, actor" below.
|
||||
**Context:** Task 16 fix round 1 (controller rulings).
|
||||
**Decision:**
|
||||
- **Actor vs. owner.** API writes pass actor `token:<name>` for Bearer requests and `"user"` for sessions, so history
|
||||
shows which script changed what (spec §6.9). `field_sources` stores `fieldOwner(actor)`: every actor that does not start
|
||||
with `plugin:` is stored as `"user"`. A token edit is the user's edit, and syncs file a pending change instead of
|
||||
overwriting it. List ownership, which is read from history, applies the same mapping.
|
||||
- **CSRF.** `X-Requested-With: sttracker` is required on every non-GET request that has no Bearer token, including the
|
||||
`auth: "none"` routes login and register (login CSRF). JSON-body routes also require `Content-Type: application/json`
|
||||
(415 `unsupported_media_type` otherwise), so a cross-site simple form post cannot pass as JSON.
|
||||
- **Deleted connections** carry `source_connections.deleted_at` (migration 0003). `deleteConnection` sets it and still pauses
|
||||
the connection and wipes its credentials. Listing, lookups, updates, the scheduler and the sync handler ignore deleted rows.
|
||||
A user-paused connection without credentials is a normal, visible, resumable connection.
|
||||
- **Dev mode** (`Bun.serve({ development })`) is on only with `NODE_ENV=development` or `bun --hot` (detected through
|
||||
`process.execArgv`; `Bun.argv` does not carry runtime flags). Everything else runs in production mode.
|
||||
|
||||
## 2026-10-30: HTTP API: auth modes, CSRF header, error mapping, actor
|
||||
**Status:** accepted
|
||||
**Context:** Task 16 (`apps/server`).
|
||||
|
||||
+2
-1
@@ -11,10 +11,11 @@ Small, specific, independently actionable. Remove only when actually done.
|
||||
|
||||
## Next
|
||||
- [ ] API: response schemas in the OpenAPI document (requests only today).
|
||||
- [ ] Deployment docs (Task 19): the server runs `Bun.serve` in production mode unless `NODE_ENV=development` or `bun --hot`, so Docker needs no `NODE_ENV`. Document `NODE_ENV=development` for local debugging.
|
||||
- [ ] API: `restoreVersion`, `acceptSuggestion` and `resolveChange` take no actor, so history records `"user"` for them even when an app token calls them. Thread the actor through if script provenance matters there.
|
||||
- [ ] API: login/register rate limit is per process and keyed on the socket IP; behind a reverse proxy every client shares one key. Add a trusted-proxy setting for `X-Forwarded-For`.
|
||||
- [ ] API: file imports are base64 in the `jobs.payload` row (up to ~67 MB of text). Move uploads to `DATA_DIR/uploads/` and pass a path.
|
||||
- [ ] API: `PATCH list-items/:id` only moves items; editing an item's note needs a core function.
|
||||
- [ ] Connections: a user-paused connection that never had credentials looks deleted (`paused` + no credentials) and disappears from `GET sources`. Add an explicit `deleted_at`.
|
||||
- [ ] Phase 2 and Phase 3 plans (spec §12).
|
||||
- [ ] Generate image thumbnails for attachments (Phase 1 sizes images with CSS).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user