docs(phase-14): gather context for multi-signer schema phase
This commit is contained in:
0
.planning/phases/14-multi-signer-schema/.gitkeep
Normal file
0
.planning/phases/14-multi-signer-schema/.gitkeep
Normal file
94
.planning/phases/14-multi-signer-schema/14-CONTEXT.md
Normal file
94
.planning/phases/14-multi-signer-schema/14-CONTEXT.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Phase 14: Multi-Signer Schema - Context
|
||||
|
||||
**Gathered:** 2026-04-03
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Additive DB migration only — no backend logic changes, no UI changes. Add three new nullable columns to existing tables and extend the `SignatureFieldData` TypeScript interface with an optional `signerEmail` field. Every new column is nullable so all existing single-signer documents continue to work without any backfill or code changes. Phase 14 is schema-only; the sign handler rewrite and completion detection logic belong in Phase 15.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### Schema Shape
|
||||
|
||||
- **D-01:** `documents.signers` JSONB shape is `{ email: string; color: string }[]` — not a plain `string[]`. Color is stored alongside email so Phase 16 can retrieve consistent per-signer colors from the DB without recalculating by index. Example: `[{ email: "buyer@x.com", color: "#6366f1" }]`.
|
||||
- **D-02:** `signingTokens.signerEmail` is a nullable `TEXT` column. NULL means legacy single-signer token (existing behavior unchanged).
|
||||
- **D-03:** `documents.completionTriggeredAt` is a nullable `TIMESTAMP` column. Used as an atomic completion guard in Phase 15: `UPDATE documents SET completionTriggeredAt = NOW() WHERE id = $1 AND completionTriggeredAt IS NULL RETURNING id`. Only Phase 15 writes to it.
|
||||
- **D-04:** `SignatureFieldData` interface gets an optional `signerEmail?: string` field — the same additive-nullable pattern already used for `type?: SignatureFieldType`.
|
||||
|
||||
### Status Tracking
|
||||
|
||||
- **D-05:** No `Partially Signed` value added to `documentStatusEnum`. Partial-signed state is computed dynamically in Phase 16 by counting `signingTokens WHERE usedAt IS NOT NULL` vs total tokens for the document. Avoids `ALTER TYPE` migration complexity.
|
||||
|
||||
### Bug Fix Scope
|
||||
|
||||
- **D-06:** The first-signer-wins bug (sign handler unconditionally sets `status='Signed'` on any submission) is **NOT fixed in Phase 14**. Phase 14 is schema-only. Phase 15 owns the full sign handler rewrite including this fix.
|
||||
|
||||
### Migration Approach
|
||||
|
||||
- **D-07:** Use existing pattern: edit `schema.ts`, run `drizzle-kit generate` to produce `drizzle/0010_*.sql`, commit both, run `drizzle-kit migrate` against Neon in deployment. Migration must be additive-only (no column removals, no type changes, no backfills).
|
||||
|
||||
### Claude's Discretion
|
||||
- Migration file naming and exact SQL details — Drizzle generates these automatically from schema.ts changes.
|
||||
- Order of changes within the migration (columns vs interface) — planner decides.
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Schema
|
||||
- `teressa-copeland-homes/src/lib/db/schema.ts` — Current schema; all new columns and interface changes go here
|
||||
- `teressa-copeland-homes/drizzle/` — Existing migration files (0000–0009); new migration is 0010
|
||||
|
||||
### Drizzle Config
|
||||
- `teressa-copeland-homes/drizzle.config.ts` — Migration output dir and DB credentials config
|
||||
|
||||
### Research
|
||||
- `.planning/research/ARCHITECTURE.md` — Multi-signer schema design section (additive-only pattern, advisory lock approach, migration strategy)
|
||||
- `.planning/research/PITFALLS.md` — First-signer-wins bug description (Phase 14 adds the column Phase 15 needs to fix it)
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- `getFieldType(field)` in `schema.ts` — Pattern for safe nullable field reads with fallback; `signerEmail` should follow the same additive-nullable pattern
|
||||
- `isClientVisibleField(field)` in `schema.ts` — Already filters by field type; Phase 15 will add signer filtering here or alongside it
|
||||
|
||||
### Established Patterns
|
||||
- **Additive nullable columns**: Prior migrations (0006–0009) show the pattern: add nullable columns to schema.ts, generate migration, migrate. No backfills needed.
|
||||
- **JSONB typed columns**: `signatureFields`, `textFillData`, `emailAddresses` all use `jsonb().$type<T>()` — `documents.signers` follows the same pattern with `$type<{ email: string; color: string }[]>()`
|
||||
- **`drizzle-kit generate` + `drizzle-kit migrate`**: The project has 10 migrations already. Always generate, never hand-write SQL.
|
||||
|
||||
### Integration Points
|
||||
- `signingTokens` table: new `signerEmail` column is nullable; existing token creation code in `POST /api/documents/[id]/send` does not need to change in Phase 14
|
||||
- `SignatureFieldData` interface: adding `signerEmail?: string` is backwards-compatible — all existing field JSONB rows silently get `undefined` for this field
|
||||
|
||||
</code_context>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- The `{ email, color }` shape for `documents.signers` was chosen over `string[]` so Phase 16's PreparePanel can display the signer list with consistent colors without needing to recalculate or store colors elsewhere.
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope.
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 14-multi-signer-schema*
|
||||
*Context gathered: 2026-04-03*
|
||||
Reference in New Issue
Block a user