Files
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

6.5 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
12 02 execute 2
1
false
OFFER-11
OFFER-15
OFFER-16
OFFER-17
OFFER-18
truths artifacts key_links
Migration 0008 (offer_macros/offer_micros additive columns + offer_tier_services table) has been applied to the production database
Plan 03's query layer and Plan 04/05's UI can read/write tier_letter, public_price, offer_macros category/ticket/transformation-promise fields, and offer_tier_services against real production data
from to via pattern
scripts/push-12-offer-tier-schema.ts production Postgres (178.104.27.55:54321, via SSH+docker exec) manual operator run of the idempotent push script against prod DATABASE_URL tier_letter|public_price|offer_tier_services
BLOCKING checkpoint: apply migration 0008 (`src/db/migrations/0008_offer_tier_schema.sql`, created in Plan 01) to the production database. Per CLAUDE.md Data Safety and project memory (`project_clienthub_deploy_db.md`: Gitea→Coolify, prod Postgres reachable only via SSH+docker exec, port 54321 firewalled from outside), this migration MUST be applied to prod BEFORE Plans 03-05 (query layer, server actions, and UI that read/write `tier_letter`, `public_price`, the new `offer_macros` columns, and `offer_tier_services`) are exercised against production data.

Purpose: Unblock Wave 2/3 schema-dependent code per the project's locked migration convention (migrations applied to prod before schema-dependent code ships). Output: Migration 0008 applied to production; confirmation that offer_tier_services exists and the new columns are queryable on the live DB.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/STATE.md @scripts/push-12-offer-tier-schema.ts @src/db/migrations/0008_offer_tier_schema.sql Task 1: Apply migration 0008 to production database Plan 01 created `src/db/migrations/0008_offer_tier_schema.sql` (additive-only: 11 `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` statements on `offer_macros`/`offer_micros`, a guarded `CHECK` constraint on `offer_micros.tier_letter`, and `CREATE TABLE IF NOT EXISTS offer_tier_services` + index) and the idempotent push script `scripts/push-12-offer-tier-schema.ts` that applies it.
This script CANNOT be run from this environment: the production DATABASE_URL
(`178.104.27.55:54321`) is firewalled and reachable only via SSH to the production host
(per `project_clienthub_deploy_db.md`). Opening a root SSH session to the shared
production host is outside this agent's authorization.
On your machine (or via your existing SSH access to the production host), run the migration push script against the production database, then confirm the new schema objects exist:
1. SSH to the production host and exec into the Postgres container (same pattern used
   for the Phase 11 migration apply):
   ```bash
   ssh root@178.104.27.55
   docker exec -it <postgres-container-name> psql -U clienthub -d clienthub
   ```
   OR, if you prefer running the idempotent TypeScript push script with
   `DATABASE_URL` pointed at prod (via SSH port-forward / tunnel, same as Phase 11):
   ```bash
   npx tsx scripts/push-12-offer-tier-schema.ts
   ```

2. If using `psql` directly, run the contents of
   `src/db/migrations/0008_offer_tier_schema.sql` (copy/paste — it is additive-only and
   idempotent, safe to run even if partially applied already).

3. Confirm the new columns and table exist:
   ```sql
   \d offer_macros
   \d offer_micros
   \d offer_tier_services
   ```
   Expect: `offer_macros` has `description`, `category`, `ticket`, `is_archived`,
   `cliente_ideale`, `risultato`, `tempo`, `pain`, `metodo`; `offer_micros` has
   `tier_letter` (with a CHECK constraint `offer_micros_tier_letter_check`) and
   `public_price`; `offer_tier_services` table exists with columns `tier_id`,
   `service_id`, `created_at` and a composite primary key on (`tier_id`, `service_id`).

4. Confirm no existing data was affected:
   ```sql
   SELECT count(*) FROM offer_macros;
   SELECT count(*) FROM offer_micros;
   SELECT count(*) FROM clients;
   SELECT count(*) FROM projects;
   ```
   Row counts should match pre-migration counts (migration is additive — no rows
   deleted).
Type "applied" once migration 0008 has been run against production and you've confirmed the new columns/table exist (or describe any errors encountered).

<threat_model>

Trust Boundaries

Boundary Description
Operator (human) -> Production Postgres Manual SSH+docker exec session per project convention; only additive, idempotent SQL from migration 0008 is executed

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-12-05 Denial of Service / Tampering Manual prod migration apply accept Operator runs only the additive, idempotent migration 0008 (already grep-gated in Plan 01 against DROP/TRUNCATE/RENAME); per project convention this is a manual, out-of-band step not reachable via any HTTP endpoint
</threat_model>
1. Operator confirms (via `\d offer_macros`, `\d offer_micros`, `\d offer_tier_services` on prod) that all Plan 01 additive columns and the new junction table exist. 2. Operator confirms row counts for `offer_macros`, `offer_micros`, `clients`, `projects` are unchanged (additive migration, no data loss). 3. Resume-signal "applied" received before Wave 3 (Plans 04/05) begins relying on these columns/table against production data.

<success_criteria>

  • Migration 0008 is live on production.
  • offer_tier_services table and all new offer_macros/offer_micros columns are queryable on prod.
  • No row in clients, projects, payments, phases, offer_macros, or offer_micros was deleted or modified destructively. </success_criteria>
After completion, create `.planning/phases/12-offer-composition-drag-drop-csv-import/12-02-SUMMARY.md`