From 0440d32742095812ac20e4d218b3fb5d352482cd Mon Sep 17 00:00:00 2001 From: fen Date: Wed, 9 Sep 2026 19:15:44 -0500 Subject: [PATCH] Docs accuracy fixes from #110: slug 400s, fetch limit 100, visibility field, PALETTE_DB, e2e design table/sections/links --- API.md | 6 +++--- design-attachments-storage.md | 2 +- design-e2e-encryption.md | 14 ++++++-------- performance-notes.md | 14 +++++++------- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/API.md b/API.md index a5aaa85..1897e44 100644 --- a/API.md +++ b/API.md @@ -38,9 +38,9 @@ machine-readable `code` the web UI maps to plain-language guidance (#105): | Code | Status | Meaning | |---|---|---| | `content_empty` | 400 | content is required | -| `slug_invalid` | 400/409 | custom slug malformed | -| `slug_taken` | 409 | custom slug already in use | -| `slug_reserved` | 409 | custom slug is reserved | +| `slug_invalid` | 400 | custom slug malformed | +| `slug_taken` | 400 | custom slug already in use | +| `slug_reserved` | 400 | custom slug is reserved | | `expiry_invalid` | 400 | expires_in out of 1 minute – 1 year range | | `content_too_large` | 413 | content or body exceeds the size cap | | `rate_limited` | 429 | too many requests; see `Retry-After` | diff --git a/design-attachments-storage.md b/design-attachments-storage.md index 8ffd61d..d9cb0ce 100644 --- a/design-attachments-storage.md +++ b/design-attachments-storage.md @@ -66,7 +66,7 @@ Specifically: - DB file > ~5-10 GB, or - a concrete user request for a Postgres-backed image. 4. When a trigger fires, port `internal/store` to Postgres behind an interface extracted *then* — the refactor is mechanical against a real need, instead of speculative complexity now. -5. For the docker image: `PALETTE_DB_PATH` env already implies the deployment choice; no extra backend knob needed. +5. For the docker image: `PALETTE_DB` env already implies the deployment choice; no extra backend knob needed. ## Summary diff --git a/design-e2e-encryption.md b/design-e2e-encryption.md index d1c76cc..d2cedff 100644 --- a/design-e2e-encryption.md +++ b/design-e2e-encryption.md @@ -2,7 +2,7 @@ - **Issue:** #39 - **Status:** Design (no implementation in this PR) -- **Related docs:** [docs/API.md](../API.md) +- **Related docs:** [the wiki `API` page](https://git.archfox.org/poslop/palette/wiki/API) ## 1. Goals and non-goals @@ -94,7 +94,7 @@ The full envelope can also just live inside `content` (server-opaque); the `encr ### 3.2 Create response -Unchanged shape: `id`, `url`, `raw_url`, `api_url`, and the one-time `deletion_token` documented in docs/API.md. +Unchanged shape: `id`, `url`, `raw_url`, `api_url`, and the one-time `deletion_token` documented in the wiki `API` page. ### 3.3 Get response @@ -149,11 +149,9 @@ Delete, redeem, rate limits, expiry, sweeper, deletion tokens, visibility, slugs - **Existing /api/mine, /api/public list shapes gain a flag** (additive, non-breaking). - **Copy-to-clipboard of decrypted text stays client-side**, fine. "Copy raw" on an encrypted paste copies the envelope — label it clearly. -## 5. UX for key sharing -### 5.1 Three sharing modes +## 6. UX for key sharing +### 6.1 Three sharing modes -| Mode | What's shared | Security level | Use case | -|---|---| malformed JSON / wrong key | | | | Mode | What's shared | Strength | Use case | |---|---|---|---| | **Passphrase** (default) | URL + passphrase out-of-band (Signal etc.) | Good — two channels | Team snippets, sensitive configs | @@ -162,13 +160,13 @@ Delete, redeem, rate limits, expiry, sweeper, deletion tokens, visibility, slugs Browsers never transmit `#` fragments to servers; still set `Referrer-Policy: no-referrer` site-wide and offer separate copy buttons for URL and key. Key-in-fragment ships with a warning and stays opt-in. -### 5.2 Create page (`/new`) UX +### 6.2 Create page (`/new`) UX - "Encrypt content" toggle → reveals passphrase field + strength meter + generate-random-key button. - When encrypting, hide the server-side language dropdown; the client detects language after decryption. - Two separate inputs with distinct labels: "Access password (checked by the server, 401 gate)" and "Encryption passphrase (never leaves your browser)". If both hold the same value, warn. -### 6.2 View page (`/{id}`) UX +### 6.3 View page (`/{id}`) UX - If `encryption.kdf` is present → show key entry UI (after the access-password 401 gate, if that also applies). - After decrypt: normal render pipeline, language detected client-side. diff --git a/performance-notes.md b/performance-notes.md index cee739b..4e6ae91 100644 --- a/performance-notes.md +++ b/performance-notes.md @@ -1,26 +1,26 @@ # Performance notes (#32) Background: history and saved pages filter client-side. Each load fetches the -most recent rows from the list endpoint (`limit=500` per query is the current +most recent rows from the list endpoint (`limit=100` per query is the current client cap in `static/table.js`) and filters/sorts in the browser. This note records current behavior, measured latency, and the design for a future server-side search endpoint. Measurements only — no implementation in #4/#32. ## Current behavior -- `/api/public?limit=500&offset=0` and `/api/mine?limit=500&offset=0` return up - to 500 rows (id, title, language, created_at, view_count, size, +- `/api/public?limit=100&offset=0` and `/api/mine?limit=100&offset=0` return up + to 100 rows (the server clamps list `limit` at 100) (id, title, language, created_at, view_count, size, visibility, custom_slug, is_can). Content is NOT included — only `LENGTH(content)`. - The browser applies the search-box filter (title/language/id substring) and column sorting locally over the fetched window. -- Consequence: search only covers the fetched window (500 most recent rows). +- Consequence: search only covers the fetched window (100 most recent rows). Older rows are invisible to search until paginated through, and each query ships ~4 KB of row metadata regardless of how few rows the user will look at. ## Measured latency (synthetic rows, scratch SQLite DB) Rows are synthetic pastes (~200 B content each, indexed like production: -`idx_pastes_visibility_created`). Queried `GET /api/public?limit=500` +`idx_pastes_visibility_created`). Queried `GET /api/public?limit=100` (modernc.org/sqlite, WAL, single connection — same as production). | Rows in table | Bulk insert | First query | Avg query (10 runs) | Payload | @@ -32,8 +32,8 @@ Rows are synthetic pastes (~200 B content each, indexed like production: Interpretation: - The list query itself is cheap (< 2 ms at 10k rows); latency users perceive - comes from network + browser rendering of 500 rows, not SQL. -- The current design scales fine to ~10k pastes. Beyond that, shipping 500 + comes from network + browser rendering of 100 rows, not SQL. +- The current design scales fine to ~10k pastes. Beyond that, shipping 100 rows per keystroke-refresh cycle is wasteful and search coverage stays capped at the window.