Commit Graph

12 Commits

Author SHA1 Message Date
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 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 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 008a43469d feat(10-redo-C): CRM leads module — schema, services, UI (Phase 10 redo)
Stage C of staged Phase 10 redo. Restores dangling phase10-wip work:
- schema.ts: leads expansion + activities/reminders tables + relations
- lead-service.ts / lead-validators.ts service layer
- /admin/leads list + detail + actions, LeadTable/LeadDetail/LeadForm
- LogActivityModal, SendQuoteModal, FollowUpWidget on dashboard
- migration 0005 (applied to prod DB in Stage B, along with
  previously-missing 0001/0003/0004 — root cause of all post-deploy
  500s: prod DB had no migrations applied since 0000)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:58:14 +02:00
simone abf37323fe feat(09-01): add quote validators and service layer for Phase 9 quote builder
- Updated quotes table schema: added accepted_total, state, client_email, client_notes fields
- Updated quote_items relations: changed service_id FK to unified services table
- Created quote-validators.ts: Zod schemas for quote creation, acceptance, and step validation
- Created quote-service.ts: public query layer (excludes line items) and admin queries
- Added Phase 9 migration: additive columns for quotes state machine and client capture
- Maintained backward compatibility: legacy quote_items tied to projects remain functional
- TypeScript builds successfully with no errors

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-11 07:30:10 +02:00
simone 37fe5eae48 feat(08-01): add offer_phases, offer_phase_services, and quotes table schema
- Create offer_phases table (hierarchical phases within offer micros)
- Create offer_phase_services junction (phases → unified services)
- Create quotes table (separate headers from line items)
- Create leads placeholder table (FK for quotes, Phase 10 CRM)
- Update quote_items: add quote_id, offer_micro_id, offer_phase_id columns
- Update projects: add offer_id, created_from_lead_id columns
- Update phases: add offer_phase_id column for audit trail
- Add all Drizzle relations and TypeScript types
- Build verified with npm run build

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-11 07:14:56 +02:00
simone e4ddb878ff feat(07-unified-service-catalog): add services table to schema with audit trail columns
- New `services` pgTable with: id, name, description, unit_price, category, active, migrated_from, migrated_id, created_at
- Audit trail columns (migrated_from, migrated_id) enable rollback safety during expand-contract migration
- Service and NewService TypeScript types exported
- Migration SQL file created (0001_add_services_table.sql) for schema push
- No FK relations added yet (Phase 8 will establish connections)
- service_catalog, offer_services tables unchanged — legacy compatibility preserved
- npm run build passes TypeScript checks

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-11 06:21:35 +02:00
simone f0034410ff feat(05-01): append five offer tables + Drizzle relations to schema.ts
- Add primaryKey to drizzle-orm/pg-core import
- Define offer_macros, offer_micros, offer_services, offer_micro_services, project_offers
- Add Drizzle relations for all five new tables (+ projectOffers in projectsRelations)
- Export TypeScript infer types for all new tables
2026-05-30 15:26:02 +02:00
simone 63c9f750df feat(04-01): multi-project schema migration — projects, settings, FK pivot
- schema.ts: add projects table, settings kv table, slug on clients;
  migrate 6 FK from client_id to project_id (phases, payments, documents, notes,
  time_entries, quote_items); update all relations and TypeScript types
- admin-queries.ts: fix getAllClientsWithPayments + getClientFullDetail to aggregate
  through projects; add getAllProjectsWithPayments, getProjectFullDetail,
  getClientWithProjects, ClientWithProjects type
- settings.ts: new file — getSetting, updateSetting, getTargetHourlyRate, SETTINGS_KEYS
- Fix all downstream files: actions.ts, quote-actions.ts, new/actions.ts,
  timer-actions.ts, approve/route.ts, comment/route.ts, TimerCell.tsx,
  analytics-queries.ts, client-view.ts, seed.ts
- DB migration applied to Coolify Postgres (all test data cleared, schema rebuilt)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 21:58:15 +02:00
Simone Cavalli 9ddb69929a feat(03-01): make quote_items.service_id nullable and add custom_label column
- Remove .notNull() from service_id to allow free-form items without catalog ref
- Add custom_label: text("custom_label") for free-form item label storage
- TypeScript compiles with zero errors (QuoteItem.service_id now string | null)
2026-05-17 11:36:43 +02:00
Simone Cavalli 0f48570cd7 feat: client edit/delete/archive + time tracker + analytics time section
Schema:
- clients.archived boolean (default false)
- time_entries table (client_id, started_at, ended_at, duration_seconds)

Client management:
- /admin/clients/[id]/edit — form pre-compilato con nome, brand, brief
- ClientActions: Modifica / Archivia / Elimina con doppia conferma
- setClientArchived: toggle archiviazione senza perdere dati
- deleteClient: elimina con cascade, redirect a /admin
- Admin list: toggle "Mostra archiviati" via ?archived=1, righe archiviate opache

Time tracker:
- startTimer: crea sessione, ferma automaticamente quella precedente
- stopTimer: chiude sessione, calcola duration_seconds
- TimerCell: ▶/⏹ per ogni cliente, contatore live in secondi, totale cumulativo
- Una sola sessione attiva alla volta su tutta la lista

Analytics:
- Sezione "Fatturato" (invariata) + sezione "Tempo tracciato" separata
- Ore totali per anno + barre orizzontali per cliente
- getTotalTrackedHours, getTimeByClient queries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 21:28:01 +02:00
Simone Cavalli 1bdbe7ab5d feat(01-02): create complete Drizzle schema with all 10 tables
- clients: token as separate text field (notNull, unique, nanoid) — never PK
- accepted_total denormalized on clients — client API never touches quote_items
- deliverables.approved_at immutable timestamp (TIMESTAMPTZ) — audit trail
- payments: label (Acconto 50% / Saldo 50%), status (da_saldare/inviata/saldato)
- comments: polymorphic entity_type+entity_id pattern
- service_catalog + quote_items: admin-only, never exposed to client API
- Full relations defined for all FK chains
- TypeScript types exported: Client, Phase, Task, Deliverable, etc.
- ID strategy: text + nanoid() via $defaultFn (cryptographically secure, URL-safe)
2026-05-13 22:46:30 +02:00