640f986967
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.
143 lines
6.5 KiB
Markdown
143 lines
6.5 KiB
Markdown
---
|
|
phase: 12
|
|
plan: 02
|
|
type: execute
|
|
wave: 2
|
|
depends_on: [1]
|
|
files_modified: []
|
|
autonomous: false
|
|
requirements: [OFFER-11, OFFER-15, OFFER-16, OFFER-17, OFFER-18]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "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"
|
|
artifacts: []
|
|
key_links:
|
|
- from: "scripts/push-12-offer-tier-schema.ts"
|
|
to: "production Postgres (178.104.27.55:54321, via SSH+docker exec)"
|
|
via: "manual operator run of the idempotent push script against prod DATABASE_URL"
|
|
pattern: "tier_letter|public_price|offer_tier_services"
|
|
---
|
|
|
|
<objective>
|
|
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.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
|
@$HOME/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/STATE.md
|
|
@scripts/push-12-offer-tier-schema.ts
|
|
@src/db/migrations/0008_offer_tier_schema.sql
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="checkpoint:human-action" gate="blocking">
|
|
<name>Task 1: Apply migration 0008 to production database</name>
|
|
<what-built>
|
|
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.
|
|
</what-built>
|
|
<how-to-verify>
|
|
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).
|
|
</how-to-verify>
|
|
<resume-signal>Type "applied" once migration 0008 has been run against production and you've confirmed the new columns/table exist (or describe any errors encountered).</resume-signal>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<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>
|
|
|
|
<verification>
|
|
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.
|
|
</verification>
|
|
|
|
<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>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/12-offer-composition-drag-drop-csv-import/12-02-SUMMARY.md`
|
|
</output>
|