Commit Graph

258 Commits

Author SHA1 Message Date
simone b80f0563b8 docs(12-01): fix markdown lint formatting in summary
- Add blank lines around headings and lists per MD022/MD032
2026-06-14 21:21:37 +02:00
simone bfc99329c5 docs(12-01): complete offer tier schema foundation plan
- Add 12-01-SUMMARY.md documenting additive schema extension, migration 0008, and push script
2026-06-14 21:20:28 +02:00
simone 89d15eeb54 feat(12-01): add migration 0008 for offer tier schema + idempotent push script
- Hand-write 0008_offer_tier_schema.sql: additive ALTER TABLE ADD COLUMN IF NOT EXISTS for offer_macros/offer_micros, guarded DO-block CHECK constraint on tier_letter, CREATE TABLE IF NOT EXISTS offer_tier_services + index
- Append journal entry for 0008_offer_tier_schema following the 0006 entry shape
- Add scripts/push-12-offer-tier-schema.ts: idempotent push script with PRODUCTION DEPLOY NOTE — BLOCKING step for Plan 02 (SSH+docker exec) before Wave 3 query layer
2026-06-14 21:19:10 +02:00
simone 11d6c1179f feat(12-01): extend offer schema with tier, pricing, and category fields
- Add additive offer_macros columns: description, category, ticket, is_archived, and structured transformation-promise fields (cliente_ideale/risultato/tempo/pain/metodo)
- Add additive offer_micros columns: tier_letter (A/B/C, CHECK constraint added in migration 0008) and public_price
- Add new offer_tier_services junction table (offer_micros <-> services), relations, and types
- Extend offerMicrosRelations with tierServices; legacy offer_micro_services/offer_services untouched
2026-06-14 21:17:52 +02:00
simone 1414c3e95c docs(12): finalize wave resequencing in plans and tracking
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:15:09 +02:00
simone 640f986967 docs(12): create phase plan
Re-scoped Offer Editor (Tier A/B/C, Tag & Prezzo Pubblico) per 2026-06-14
user decision: 5-plan wave structure (schema migration -> prod apply
checkpoint -> query/action layer -> list + detail editor UI), OFFER-12
CSV/Notion import deferred.
2026-06-14 21:00:32 +02:00
simone 9bff7623da docs: move CRM Attio-style requirements to Validated (Phase 14)
PROJECT.md: CRM-08..12 moved from Active to Validated in v2.1,
referencing Phase 14 completion.
2026-06-14 15:27:07 +02:00
simone fa5672025f docs(14): mark phase complete, advance roadmap to Phase 15
phase complete 14: ROADMAP plans/progress, STATE position (Phase 15
next, blocked on user mockup), REQUIREMENTS CRM-08..12 -> Complete.
2026-06-14 15:22:40 +02:00
simone 2c227f4ef1 docs(14): add code review report and phase verification (passed)
14-REVIEW.md: 0 critical, 6 warnings, 3 info (standard depth, 11 files).
14-VERIFICATION.md: 5/5 success criteria verified after closing the
SC5/CRM-12 generate_new dead-branch gap.
2026-06-14 15:20:08 +02:00
simone c8d53134ba fix(14): remove dead generate_new branch from assignQuoteToLead (CRM-12)
assignQuoteToLead's generate_new check was unreachable since
SendQuoteModal always passed false. Removes the field from both
the server schema and the modal's local schema/defaultValues/call site.
2026-06-14 15:17:48 +02:00
simone 0378ba78a9 Merge branch 'worktree-agent-a260f91fada48defd' 2026-06-14 13:25:23 +02:00
simone 2a02ca8fbf docs(14-02): add plan summary for LeadTable Attio rewrite 2026-06-14 13:24:47 +02:00
simone ab7fa62059 feat(14-02): add LeadsSearch, rewire leads pages, surface tags in LeadDetail (CRM-08/09)
- New LeadsSearch.tsx: client-side instant filter across name/email/
  company/status/tags (mirrors CatalogSearch.tsx)
- page.tsx: fetch via getLeadsWithTags()/getLeadFieldOptions(), render
  LeadsSearch + CreateLeadModal, revalidate=0
- [id]/page.tsx: fetch getLeadsWithTags()/getLeadFieldOptions(), find
  lead by id, pass tags/tagOptions to LeadDetail
- LeadDetail.tsx: add OptionMultiSelect for lead tags in the "Profilo"
  card, wired to addLeadTag/removeLeadTag/renameLeadTag with error display
2026-06-14 13:21:55 +02:00
simone 4887a319f7 feat(14-02): rewrite LeadTable as raw-table database view (CRM-08/09)
Replace shadcn Table-based read-only LeadTable with an Attio-style raw
table database view (1:1 structural port of ServiceTable.tsx):
- EditableCell for name/email/phone/company/next_action, persisted via
  updateLeadField
- Local StatusCell: closed click-to-open dropdown over the 6 fixed
  LEAD_STAGES values, preserving semantic STAGE_COLOR badges (won=green,
  lost=red, etc.) without modifying shared option-select.tsx
- OptionMultiSelect for lead tags, wired to addLeadTag/removeLeadTag/
  renameLeadTag
- Per-row error display and "Nessun lead trovato" empty state
2026-06-14 13:21:23 +02:00
simone 39bd1ce2eb chore: merge executor worktree (worktree-agent-aaf61d7161f7818a0)
# Conflicts:
#	.planning/phases/14-crm-attio-style-fix/deferred-items.md
2026-06-14 12:51:37 +02:00
simone d664d8d3a7 chore: merge executor worktree (worktree-agent-a6c4f07a973e2df91) 2026-06-14 12:50:54 +02:00
simone 3c53672754 docs(14-03): append self-check results to plan summary 2026-06-14 12:49:41 +02:00
simone 6b51403404 docs(14-03): complete CRM residual bug fixes plan
Summary for 14-03: FollowUpWidget Italian translation (CRM-10), LeadForm typed useForm (CRM-11) + shared FormField generic fix, SendQuoteModal dead branch removal (CRM-12)
2026-06-14 12:48:53 +02:00
simone a495d84511 fix(14-03): remove dead onSubmit branch in SendQuoteModal (CRM-12)
- Remove unreachable if (tab === "new") branch in onSubmit - the new-tab button has its own onClick navigation and never triggers form submit
- Escape unescaped double quotes in JSX text (react/no-unescaped-entities)
- generate_new field left as-is per plan (optional cleanup, out of scope)
- Log pre-existing useForm<any>/onSubmit(data: any) no-explicit-any lint errors to deferred-items.md (out of scope: fixing requires resolving a zodResolver/Resolver generic incompatibility with assignQuoteSchema's optional/default fields)
2026-06-14 12:46:55 +02:00
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
simone d1acfe9127 docs(14-01): complete lead data-layer foundation plan
- SUMMARY documents getLeadsWithTags/getLeadFieldOptions and
  updateLeadField/addLeadTag/removeLeadTag/renameLeadTag additions
- Logs 2 pre-existing lint issues (deferred-items.md) unrelated to
  this plan's changes
2026-06-14 12:43:21 +02:00
simone ee509cd5fb fix(14-03): type LeadForm useForm with CreateLeadInput (CRM-11)
- CreateLeadModal and EditLeadModal use useForm<CreateLeadInput>() instead of useForm<any>()
- Import CreateLeadInput from lead-validators, remove local z.infer redeclaration
- Narrow EditLeadModal status default value to CreateLeadInput["status"], remove 'as any'
- Fix FormField generic signature in shared ui/form.tsx (was ControllerProps<any, any>, broke Control<T> assignability once useForm<T> became concrete) - Rule 3 blocking issue
2026-06-14 12:43:00 +02:00
simone 7d98b27e75 feat(14-01): add updateLeadField and lead tag CRUD server actions
- requireAdmin() guard (mirrors catalog/actions.ts pattern), throws
  "Non autorizzato" before any DB access
- updateLeadField: EDITABLE_FIELDS allowlist, name/status validated
  server-side (LEAD_STAGES.includes), nullable fields cleared on empty
- addLeadTag/removeLeadTag/renameLeadTag: polymorphic tags table scoped
  to entity_type="leads" (LEADS_TAG_ENTITY), never touches
  entity_type="services" rows
- All four actions call revalidatePath for /admin/leads (+ detail page
  where a single leadId applies)
- Log pre-existing lint issues (unrelated to this task) to
  deferred-items.md per scope-boundary rule
2026-06-14 12:41:36 +02:00
simone 272e363f4d fix(14-03): translate FollowUpWidget to Italian (CRM-10)
- Replace 6 hardcoded English strings with Italian equivalents
- Remove pluralization ternary (Italian "lead" is invariant)
2026-06-14 12:38:12 +02:00
simone 5b583bcc5e feat(14-01): add getLeadsWithTags and getLeadFieldOptions to admin-queries
- LeadWithTags type + getLeadsWithTags() left-joins leads with tags
  scoped to entity_type="leads", Map-reduce pattern mirroring
  getAllServices (Phase 11)
- LeadFieldOptions type + getLeadFieldOptions() returns fixed
  LEAD_STAGES for status and distinct sorted lead tag names
- desc import added to drizzle-orm import; LEAD_STAGES imported from
  lib/lead-validators
2026-06-14 12:38:09 +02:00
simone f5309345b9 docs(14): annotate plan waves and update milestone progress
Wave-dependency annotations for Phase 14 (14-01/14-03 wave 1, 14-02 wave 2)
and corrected v2.1 progress tracking (4/7 plans, current focus → Phase 14).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 12:30:38 +02:00
simone d115465240 docs(14): create phase plan
Plan Phase 14 (CRM Attio-style & Fix) into 3 waves: data-layer
foundation (query helpers + server actions), LeadTable raw-table
rewrite with inline edit/tags, and isolated bug fixes for CRM-10/11/12.
2026-06-14 12:09:45 +02:00
simone 89adf7a1d4 docs(14): UI design contract for CRM Attio-style redesign
UI-SPEC approved (5/6 PASS, 1 non-blocking flag on focal point).
Locks reuse of Phase 11 primitives (EditableCell, OptionSelect,
OptionMultiSelect) for the leads table, plus scope for the four
CRM bug fixes (i18n, type-safety, dead code).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 11:23:28 +02:00
simone e858a8f577 feat(catalog): Notion-style shared select fields (tag/pacchetto/categoria/fase)
Turn the catalog into Notion/Airtable select properties:
- Tag + Pacchetto: multi-select with a SHARED pool — created values persist and
  are selectable from a dropdown across all services (no more re-typing)
- Categoria + Fase: single-select chips with the same dropdown + create-on-the-fly
- Rename an option once -> propagates to every row (renameServiceOption)
- Deterministic colors per value (shared option-colors util)
- Quick-add row now sets name+description+categoria+fase+prezzo then Enter (active)
- Search broadened to name/categoria/fase/tag/pacchetto

Data model (additive): tag/pacchetto in polymorphic tags table (entity_type
services / services.pacchetto); categoria/fase as single-select columns on
services (new: services.fase). Pools derived from distinct values.

New: OptionSelect, OptionMultiSelect, option-colors. Removed tag-multi-select.
Migration 0007_add_services_fase.sql must be applied before runtime.

tsc + eslint + next build clean. CSV bulk import (OFFER-12) stays Phase 12.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 21:40:34 +02:00
simone 42c16e1bab fix(11): address code-review findings in catalog inline-edit
- WR-01: remove blur-commit on EditableCell toggle (onChange already saves+closes; prevents double updateServiceField)
- WR-02: skip server action when cell value unchanged (commit + new commitOnBlur dirty-check)
- WR-03: on blur, revert required-empty field via cancel() instead of leaving the cell stuck in error state
- WR-04: normalize it-IT price input (1.234,50) before parse; Number() rejects trailing garbage
- IN-01: render row error in its own <tr> instead of an invalid 7th <td> in a 6-column row

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 21:02:50 +02:00
simone 8d62207ccb docs(phase-11): complete phase — OFFER-13 migration applied to prod DB, all validators passed
Tags table + legacy consolidation applied via SSH tunnel to Coolify Postgres.
Both validators: ALL CHECKS PASSED. Protected tables (clients/projects/payments/phases) unchanged.
Phase 11 verification: passed (OFFER-07/08/09/10/13 all Complete).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 20:31:20 +02:00
simone 1e4f917b51 docs(phase-11): add code review + verification (code-complete, DB migration pending)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 16:35:02 +02:00
simone 0387805041 docs(11-04): complete catalog database-view plan
- Mark OFFER-10 complete (REQUIREMENTS.md) — client-side search delivered
- STATE.md: position advanced to Phase 11 plans 1-4 all executed (92%), session/decisions/metrics updated
- 11-04-SUMMARY.md: append self-check results
2026-06-13 16:05:13 +02:00
simone 9bc1e43738 docs(11-04): add plan summary and log unused createService action
- 11-04-SUMMARY.md documents ServiceTable database-view rewrite + CatalogSearch
- deferred-items.md: log now-unused createService/serviceSchema in actions.ts (item 6)
2026-06-13 16:03:10 +02:00
simone 912a892ba5 feat(11-04): add client-side search bar to catalog page, remove ServiceForm
- New CatalogSearch client component: filters ServiceWithTags[] by name/tag, case-insensitive, instant (no reload)
- page.tsx now passes filtered services through CatalogSearch -> ServiceTable
- ServiceForm.tsx deleted — quick-add row in ServiceTable replaces its create-service UX
2026-06-13 16:01:17 +02:00
simone c0bedf300e feat(11-04): rewrite ServiceTable as database-view (inline edit, tags, quick-add, active/inactive split)
- 6-column table (Nome, Descrizione, Categoria, Prezzo, Tag, Stato), no Azioni column (D-14)
- Every field cell uses EditableCell (text/textarea/number/toggle), saving via updateServiceField
- Tags column uses TagMultiSelect, wired to addTagToService/removeTagFromService
- QuickAddRow creates new services (unit_price=0) via quickAddService on Enter (D-12)
- Inactive services sink below a "Servizi disattivati" divider with opacity-50 (D-13)
- All mutations trigger router.refresh()
2026-06-13 15:58:36 +02:00
simone e424653ece docs(11-03): complete EditableCell + TagMultiSelect plan
- add 11-03-SUMMARY.md documenting EditableCell/TagMultiSelect delivery
  and the react-hooks lint-rule fix (Rule 1 deviation)
- update STATE.md position (3 of 4 -> 4 of 4), progress 86% -> 89%,
  performance metrics, and decisions log
- log gsd-sdk unavailability and OFFER-07/08 status timing as deferred
  items for Phase 11
2026-06-13 15:56:06 +02:00
simone a567a90ce3 feat(11-03): add TagMultiSelect component with hashed tag colors
- TAG_COLORS 7-color pastel palette + getTagColorIndex() deterministic
  name->color hash (D-07, no stored color column)
- renders tag badges with inline remove (X), calls removeTagFromService
- "+" dropdown to add a new tag via Enter, calls addTagToService
- closes dropdown on outside click and Escape; inline error display
2026-06-13 15:51:49 +02:00
simone 55276c19fe fix(11-03): avoid setState/ref access during render in EditableCell
- remove value-sync useEffect + render-time ref read that violated
  react-hooks/set-state-in-effect and react-hooks/refs lint rules
- toggle display now reads value directly instead of tempValue,
  which is only meaningful while isEditing is true
2026-06-13 15:51:41 +02:00
simone 3514a3710d feat(11-03): add EditableCell click-to-edit component
- text/number/textarea/toggle types with click-to-edit display mode
- Enter (non-textarea) saves, Escape cancels, blur saves
- required validation with inline error, disabled state styling
- ring-1 ring-primary focus per DESIGN-SYSTEM.md inline-edit pattern
2026-06-13 15:49:15 +02:00
simone 62d5e97f39 docs(11-02): complete catalog query layer + server actions plan
- SUMMARY.md for Plan 02 (ServiceWithTags + 4 new server actions)
- STATE.md: advance to Plan 3/4, record metrics and decision
- REQUIREMENTS.md: mark OFFER-07/08/09 backend foundation complete
2026-06-13 15:47:07 +02:00
simone 445de856e4 feat(11-02): add inline-edit, tag, and quick-add server actions
- updateServiceField: single-field inline edit (name, description,
  category, unit_price, active) with per-field validation
- addTagToService / removeTagFromService: tag assignment scoped to
  entity_type="services" via onConflictDoNothing on the unique index
- quickAddService: creates a unit_price=0.00 row from name only (D-12)
- All actions admin-gated via requireAdmin() and revalidate /admin/catalog
2026-06-13 15:39:55 +02:00
simone f7434102de feat(11-02): extend getAllServices with tags join (ServiceWithTags)
- Add ServiceWithTags type = Service & { tags: string[] }
- getAllServices() now left-joins tags scoped to entity_type=services
- Tags aggregated per service, ordered by service name then tag name
2026-06-13 15:38:57 +02:00
simone a447494dde docs(11-01): complete plan 1 — tags schema + consolidation scripts, DB-execution gated
- Advance STATE.md to plan 2/4, record metrics/decisions/blocker for 11-01
- Fix Status/Progress fields regressed by state advance-plan (status was
  reset to "Ready to execute" / 0% despite phase being mid-execution)
- Note .planning/ROADMAP.md is an empty PLACEHOLDER (pre-existing v2.1
  planning gap) — roadmap update-plan-progress is a no-op until populated
2026-06-13 15:35:18 +02:00
simone afe789c415 docs(11-01): add execution summary and deferred items log
Documents Phase 11 Plan 1 outcome: tags table schema + migration scripts
complete and committed; DB-execution steps (push migration, run legacy
consolidation, run tag-assignment + validators) blocked by network/SSH
access gate to 178.104.27.55:54321 (firewalled, SSH-only per project
memory). Logs pre-existing drizzle-kit migration tooling drift and the
stale quote_items<->service_catalog JOIN as deferred non-blocking items.
2026-06-13 15:30:03 +02:00
simone 2f2589f0b9 feat(11-01): add tag-assignment migration and validation scripts (OFFER-13/D-02)
- scripts/migrate-tags.ts: idempotently assigns the "Offerta" tag to every
  services row where migrated_from = 'offer_services' (D-02)
- scripts/validate-tags-migration.ts: row-count + orphan checks for the
  tags consolidation dimension of OFFER-13

NOTE: Not yet executed against the dev/staging DB (178.104.27.55:54321) —
that host is firewalled and only reachable via SSH+docker exec per project
memory, which is out of scope for this agent's authorization. Execution of
this script, scripts/migrate-services.ts, scripts/validate-services-migration.ts,
and scripts/push-11-tags-migration.ts is documented as a pending access gate
in 11-01-SUMMARY.md.
2026-06-13 15:27:07 +02:00
simone 4773487d0c feat(11-01): add tags table to schema with migration and push script
- Add polymorphic tags table (entity_type/entity_id/name) with unique
  index on (entity_type, entity_id, name) and lookup index on
  (entity_type, entity_id) — pattern follows comments table (D-05/D-06/D-07)
- Add Tag/NewTag types and tagsRelations (no direct FK, query-time join)
- Hand-write src/db/migrations/0006_add_tags_table.sql following the
  established project convention (drizzle-kit generate is unusable here —
  meta/_journal.json snapshots out of sync since 0001, pre-existing since
  Phase 8) and add journal entry for 0006_add_tags_table
- Add scripts/push-11-tags-migration.ts (idempotent CREATE TABLE/INDEX IF
  NOT EXISTS) with production deploy note for manual SSH+docker exec apply
2026-06-13 15:26:14 +02:00
simone d1b1047368 docs(11): create phase plan — 4 plans, 4 waves
Catalog Database-View UX & Legacy Consolidation (OFFER-07/08/09/10/13)
- 11-01: tags table + polymorphic junction + additive legacy migration
- 11-02: getAllServices tag join + inline-edit/tag/quick-add server actions
- 11-03: EditableCell + TagMultiSelect components
- 11-04: database-view ServiceTable + client-side search

Verified by gsd-plan-checker (VERIFICATION PASSED).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:07:17 +02:00
simone 03898f2a59 docs(planning): v2.1 milestone setup + Phase 11 context/patterns
- Archive v2.0 phases (07-10) under .planning/milestones/
- v2.1 REQUIREMENTS/ROADMAP (Phases 11-17: Offer Studio + Proposal AI)
- DESIGN-SYSTEM.md (database-view UI contract for Phases 11-14)
- Phase 11 CONTEXT, DISCUSSION-LOG, PATTERNS

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:07:06 +02:00
simone 857af5c182 docs(handoff): triage user feedback — lead detail bug fixed, tab restructuring decisions, Attio as CRM UX benchmark
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 22:14:31 +02:00