docs(planning): archivia v2.1/v2.2/v2.3 e documenta v2.4
.planning/ documentava in dettaglio cio che era vecchio e per niente cio
che e in produzione: le fasi 11-22 (v2.1 e v2.2, chiuse a giugno) erano
ancora in phases/ mentre v1.0 e v2.0 stavano gia in milestones/, e il
lavoro degli ultimi due mesi - gate OTP e ciclo di vita dei retainer, cioe
quello che gira su hub.iamcavalli.net - non aveva nessuna cartella.
- phases/{11,12,14} -> milestones/v2.1-phases/, phases/{18..22} ->
milestones/v2.2-phases/. Ora phases/ contiene solo la milestone in
corso, che e quello che state.cjs conta per il progresso
- v2.1-ROADMAP.md ricostruito: era l'unica milestone senza archivio,
interrotta dal reset del 19/06 e mai chiusa formalmente
- v2.3-ROADMAP.md + v2.3-REQUIREMENTS.md: v2.3 e stata eseguita fuori dal
ciclo GSD, non esistono PLAN/SUMMARY per fase. L'archivio E la doc
- REQUIREMENTS.md riscritto per v2.4 con il backlog reale
- phases/13 e phases/26: SUMMARY ricostruiti da commit, migration e
STATUS.md. 26 e il primo numero libero
- research/: cancellate 4 varianti dello stesso PITFALLS e FEATURES/
SUMMARY, superati da PROJECT.md. Diverse anti-feature erano ormai
contraddette dai fatti (il Kanban e stato costruito in Phase 19,
l'email in v2.3, il time tracking esiste)
- cancellati UI-RULES.md e DESIGN-SYSTEM.md (CLAUDE.md li dichiara
superseded: impongono l'inverso della regola attuale) e HANDOFF.md,
fermo al 13/06
- SECURITY-*.md -> security/: audit chiuso, ma i report restano la doc di
cosa e stato ruotato e perche
- PROJECT.md/MILESTONES.md/ROADMAP.md allineati: milestone corrente v2.4,
sessione OTP 90gg non 30, migrazioni fino alla 0016
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
---
|
||||
phase: 14-crm-attio-style-fix
|
||||
plan: 01
|
||||
subsystem: database
|
||||
tags: [drizzle, postgres, server-actions, leads, tags, crm]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 11-catalog-database-view
|
||||
provides: "Polymorphic `tags` table + getAllServices/getCatalogFieldOptions left-join + Map-reduce pattern, requireAdmin() convention in catalog/actions.ts"
|
||||
provides:
|
||||
- "LeadWithTags type + getLeadsWithTags() — leads augmented with tags:string[] from polymorphic tags table (entity_type='leads')"
|
||||
- "LeadFieldOptions type + getLeadFieldOptions() — fixed LEAD_STAGES for status, distinct sorted lead tag names for tags"
|
||||
- "updateLeadField server action — allowlisted inline-edit for name/email/phone/company/status/next_action, server-side LEAD_STAGES validation"
|
||||
- "addLeadTag/removeLeadTag/renameLeadTag server actions — polymorphic tags CRUD scoped to entity_type='leads'"
|
||||
affects: [14-02-leadtable-rewrite]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Left-join + Map-reduce pattern for polymorphic tags table (reused from Phase 11 getAllServices/getCatalogFieldOptions)"
|
||||
- "requireAdmin() session guard as first statement in every new server action (reused from Phase 11 catalog/actions.ts)"
|
||||
- "EDITABLE_FIELDS allowlist gating which columns a generic field-update action can write"
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- src/lib/admin-queries.ts
|
||||
- src/app/admin/leads/actions.ts
|
||||
|
||||
key-decisions:
|
||||
- "Logged 2 pre-existing lint issues (Record<string, any> in updateLead, 4 unused imports in admin-queries.ts) to deferred-items.md per Scope Boundary rule rather than fixing — both predate this plan and are unrelated to the new code added"
|
||||
|
||||
patterns-established:
|
||||
- "Lead tag mutations always scope tags table queries with eq(tags.entity_type, LEADS_TAG_ENTITY) to prevent cross-entity pollution with entity_type='services' rows"
|
||||
|
||||
requirements-completed: [CRM-08, CRM-09]
|
||||
|
||||
# Metrics
|
||||
duration: 12min
|
||||
completed: 2026-06-14
|
||||
---
|
||||
|
||||
# Phase 14 Plan 01: Lead Data-Layer Foundation Summary
|
||||
|
||||
**Added `getLeadsWithTags()`/`getLeadFieldOptions()` query functions and `updateLeadField`/`addLeadTag`/`removeLeadTag`/`renameLeadTag` server actions, mirroring Phase 11's catalog database-view pattern for the polymorphic `tags` table scoped to `entity_type="leads"`.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 12 min
|
||||
- **Started:** 2026-06-14T10:30:00Z
|
||||
- **Completed:** 2026-06-14T10:42:03Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 2
|
||||
|
||||
## Accomplishments
|
||||
- `LeadWithTags` type + `getLeadsWithTags()` left-joins `leads` with `tags` (scoped to `entity_type="leads"`), returning every lead row with a `tags: string[]` array, ordered `desc(leads.updated_at), asc(tags.name)`
|
||||
- `LeadFieldOptions` type + `getLeadFieldOptions()` returns the fixed `LEAD_STAGES` list for `status` and the distinct sorted set of lead tag names for `tags`
|
||||
- `updateLeadField(leadId, fieldName, value)` — allowlisted inline-edit action (`name`, `email`, `phone`, `company`, `status`, `next_action`), with server-side `LEAD_STAGES.includes()` validation for `status` and trim/null-clear handling for nullable text fields
|
||||
- `addLeadTag`/`removeLeadTag`/`renameLeadTag` — polymorphic `tags` table CRUD scoped to `LEADS_TAG_ENTITY = "leads"`, never touching `entity_type="services"` rows
|
||||
- All four new actions guarded by `requireAdmin()` as the first statement, throwing `"Non autorizzato"` before any DB access
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Extend admin-queries.ts with LeadWithTags and LeadFieldOptions** - `5b583bc` (feat)
|
||||
2. **Task 2: Add updateLeadField + tag CRUD server actions to leads/actions.ts** - `7d98b27` (feat)
|
||||
|
||||
_Note: Task 2 had `tdd="true"` but the plan's `<behavior>` block explicitly specifies manual-trace verification (no dedicated test file convention in this codebase, matching Phase 11's equivalent actions) — verified via line-by-line trace against all 11 documented behaviors, all pass._
|
||||
|
||||
## Files Created/Modified
|
||||
- `src/lib/admin-queries.ts` - Added `desc` to drizzle-orm import, `LEAD_STAGES` import, `LEADS_TAG_ENTITY` const, `LeadWithTags`/`LeadFieldOptions` types, `getLeadsWithTags()`, `getLeadFieldOptions()`
|
||||
- `src/app/admin/leads/actions.ts` - Added `tags` to schema import, `and` to drizzle-orm import, `LEAD_STAGES` import, `getServerSession`/`authOptions` imports, `requireAdmin()` helper, `updateLeadField`, `addLeadTag`, `removeLeadTag`, `renameLeadTag`
|
||||
|
||||
## Decisions Made
|
||||
- Followed the plan's interfaces exactly (1:1 replication of Phase 11's `getAllServices`/`getCatalogFieldOptions` and `catalog/actions.ts` tag-CRUD pattern)
|
||||
- Pre-existing lint issues unrelated to this plan's changes were logged to `deferred-items.md` rather than fixed (Scope Boundary rule) — see Deviations below
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Deferred (out of scope, logged not fixed)
|
||||
|
||||
**1. [Scope Boundary] Pre-existing `no-explicit-any` lint error in `updateLead`**
|
||||
- **Found during:** Task 2 verification (`npx eslint src/app/admin/leads/actions.ts`)
|
||||
- **Issue:** Line 54, `const updateData: Record<string, any> = { updated_at: new Date() };` inside the pre-existing `updateLead()` function (untouched by this plan) causes `npx eslint src/app/admin/leads/actions.ts` to exit 1
|
||||
- **Resolution:** Confirmed via `git show` that this line existed before Task 2's edits (predates Phase 14). Logged to `.planning/phases/14-crm-attio-style-fix/deferred-items.md` per Scope Boundary rule — not fixed. The four new actions added in this plan introduce zero new lint errors/warnings (verified: only line 54 is flagged).
|
||||
- **Files modified:** `.planning/phases/14-crm-attio-style-fix/deferred-items.md` (new)
|
||||
- **Verification:** `npx eslint src/app/admin/leads/actions.ts --format stylish` shows only line 54:38 flagged, pre-dating this commit
|
||||
- **Committed in:** `7d98b27`
|
||||
|
||||
**2. [Scope Boundary] Pre-existing unused-import warnings in admin-queries.ts**
|
||||
- **Found during:** Task 1 verification (`npx eslint src/lib/admin-queries.ts`)
|
||||
- **Issue:** 4x `@typescript-eslint/no-unused-vars` warnings for `settings`, `ServiceCatalog`, `ProjectOffer`, `OfferPhaseService` — pre-existing imports unrelated to the new `getLeadsWithTags`/`getLeadFieldOptions` code, which was appended at end-of-file
|
||||
- **Resolution:** Logged to `deferred-items.md`, not fixed (out of scope)
|
||||
- **Files modified:** `.planning/phases/14-crm-attio-style-fix/deferred-items.md` (new)
|
||||
- **Committed in:** `7d98b27`
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 2 deferred (both Scope Boundary — pre-existing issues unrelated to this plan's changes)
|
||||
**Impact on plan:** None — `npx tsc --noEmit` exits 0 cleanly across the whole project; the eslint exit-1 on `actions.ts` is caused entirely by pre-existing code this plan does not touch. All plan-specified grep/type checks pass.
|
||||
|
||||
## Issues Encountered
|
||||
None.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required. No schema migration created or required (confirmed: `tags.entity_type` is unconstrained text, already supports "leads" in production).
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- `LeadWithTags`, `LeadFieldOptions`, `getLeadsWithTags()`, `getLeadFieldOptions()` are ready for Plan 14-02 (LeadTable rewrite, LeadsSearch, page wiring)
|
||||
- `updateLeadField`, `addLeadTag`, `removeLeadTag`, `renameLeadTag` server actions are ready for Plan 14-02's inline-edit UI wiring
|
||||
- Pre-existing actions (`createLead`, `updateLead`, `deleteLead`, `logActivity`, `assignQuoteToLead`) remain unchanged, as required by out-of-scope note in RESEARCH.md A5 / Open Question 4
|
||||
- Two pre-existing lint issues logged in `deferred-items.md` for future cleanup — do not block Plan 14-02
|
||||
|
||||
---
|
||||
*Phase: 14-crm-attio-style-fix*
|
||||
*Completed: 2026-06-14*
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- FOUND: src/lib/admin-queries.ts
|
||||
- FOUND: src/app/admin/leads/actions.ts
|
||||
- FOUND: .planning/phases/14-crm-attio-style-fix/14-01-SUMMARY.md
|
||||
- FOUND: .planning/phases/14-crm-attio-style-fix/deferred-items.md
|
||||
- FOUND commit: 5b583bc
|
||||
- FOUND commit: 7d98b27
|
||||
- FOUND commit: d1acfe9
|
||||
Reference in New Issue
Block a user