Files
simone f21f13909d docs(14-01): append self-check results to SUMMARY
- Verified created/modified files exist and task commits are present
  in git history
2026-06-14 12:44:19 +02:00

7.8 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
14-crm-attio-style-fix 01 database
drizzle
postgres
server-actions
leads
tags
crm
phase provides
11-catalog-database-view Polymorphic `tags` table + getAllServices/getCatalogFieldOptions left-join + Map-reduce pattern, requireAdmin() convention in catalog/actions.ts
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'
14-02-leadtable-rewrite
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
created modified
src/lib/admin-queries.ts
src/app/admin/leads/actions.ts
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
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
CRM-08
CRM-09
12min 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