Documentation source
Tech Debt Pass 5
Tighten import/chat route enforcement, remove inbound email scan fallback from the hot path, and simplify high-churn chat service helpers.
## Problem Current `origin/dev` still has a few high-value cleanup gaps that widen bug surface even after the March 27 tech-debt pass: 1. `POST /api/entities/import` accepts writes without explicit route auth/permission checks and then uses an admin-client import path. 2. CSV import reimplements entity creation instead of reusing the shared keyed entity services, which means tenant-scoped entity type resolution and shared side effects can drift. 3. Chat REST endpoints still rely on downstream failures and duplicated ownership filters instead of one explicit route/service contract. 4. Inbound email routing still depends on a membership scan when the lookup table misses, which is the wrong scaling behavior for a webhook hot path. 5. Conversation-list shaping logic lives inline inside the oversized inbox server-action module, which keeps a high-churn file harder to reason about and test. These are all "small surface, high leverage" problems: they do not add product value, but they create failure modes in core write paths. ## Goals - Fail closed on the CSV import route. - Reuse the canonical entity creation path for imports. - Make chat route auth explicit and centralize owned-chat verification in the service layer. - Remove the inbound email O(n) scan from the default routing path. - Extract pure inbox conversation-shaping helpers out of the inbox server-action module. - Add regression tests that cover both route-level enforcement and service-level ownership behavior. ## Scope ### In scope - CSV import route auth + permission enforcement - CSV import service consolidation onto keyed entity creation - Chat route auth tightening for list/update/messages/feedback endpoints - Shared owned-chat verification in persistence/feedback actions - Signed, self-describing inbound email addresses with legacy lookup-only compatibility - Inbox conversation query/helper extraction - Regression tests for the affected routes and services ### Out of scope - Full route-helper migration across `app/api` - Large-file decomposition in views/entities/admin modules - Full decomposition of inbox/responses/view hot-path server modules - Workflow/extraction/runtime architecture changes ## Planned changes ### 1. Secure CSV import at the route boundary - Add explicit route-level auth to `POST /api/entities/import`. - Require entity-create permission rather than depending on downstream failures. - Use the shared API-route helper to standardize parsing/error handling where it improves clarity. ### 2. Collapse CSV import onto shared entity services - Replace the direct admin-client insert loop in `batchCreateEntities()` with the keyed entity creation service. - Use tenant-scoped entity-type resolution instead of assuming system/global-only types. - Preserve import summary reporting while letting the canonical create path own activity/event side effects. ### 3. Remove implicit chat ownership drift - Add explicit route auth to chat REST handlers. - Centralize the owned-chat filter pattern inside chat server code. - Reuse that helper for message reads/writes and feedback reads/writes so ownership checks do not diverge across endpoints. ### 4. Remove inbound email routing scans - Switch newly generated inbound addresses to a signed, self-describing format. - Resolve signed addresses directly in the webhook route without touching the database. - Keep hash-only addresses as a lookup-table compatibility path and add a one-shot backfill script for older deployments. ### 5. Simplify inbox conversation shaping - Extract pure helper logic for participant grouping, last-message selection, and unread-count shaping. - Reuse the extracted helpers in `getConversations()` and `getUnreadCount()` so the inbox server-action module owns less inline transformation logic. ## Success criteria - Unauthenticated or unauthorized CSV import attempts fail before any write path runs. - CSV import can create records for tenant-scoped entity types through the shared service path. - Chat routes require authentication at the route boundary and owned-chat checks are centralized in server code. - Inbound email routing no longer scans `user_tenants` on lookup-table misses. - Inbox conversation shaping logic is covered by direct helper tests instead of only indirect server-action tests. - Targeted route/service regression tests cover the new enforcement paths. ## Outcome - `POST /api/entities/import` now uses the shared route handler with explicit `entities.team.create` enforcement. - Batch import creates records through `createEntityKeyed(...)` and tenant context instead of the previous admin-client insert loop. - Chat list/detail/messages/feedback routes now require auth explicitly, and persistence/feedback code reuses a shared owned-chat helper instead of ad hoc filters. - New inbound email addresses are signed and self-describing, so the webhook resolves them directly without a membership scan; legacy hash-only addresses now rely on lookup rows or the included backfill script. - Inbox conversation shaping now lives in a dedicated helper module with direct regression coverage, reducing the hot chat service file surface. - Targeted regressions, full test suite, typecheck, lint, and production build all pass on `tech-debt-pass-5`.