> ## Documentation Index
> Fetch the complete documentation index at: https://meganharrisonconsulting.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# pattern-c-attachment-migration

> Migrate Alleato PM legacy PURT/entity attachment tables to Pattern C document_metadata plus junction tables. Use when converting *_attachments routes, repairing dual attachment storage, creating Pattern C junctions, reconciling attachment backfills, or dropping legacy attachment tables in alleato-pm.

This page is generated from the actual `SKILL.md` file on disk.

## Metadata

| Field               | Value                                                                                                                                                                                                                                                                                                            |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Source group        | Workspace Skills                                                                                                                                                                                                                                                                                                 |
| Source root         | `/Users/meganharrison/Documents/alleato-pm/.codex/skills`                                                                                                                                                                                                                                                        |
| Relative skill path | `pattern-c-attachment-migration/SKILL.md`                                                                                                                                                                                                                                                                        |
| Actual file         | `/Users/meganharrison/Documents/alleato-pm/.codex/skills/pattern-c-attachment-migration/SKILL.md`                                                                                                                                                                                                                |
| Description         | Migrate Alleato PM legacy PURT/entity attachment tables to Pattern C document\_metadata plus junction tables. Use when converting \*\_attachments routes, repairing dual attachment storage, creating Pattern C junctions, reconciling attachment backfills, or dropping legacy attachment tables in alleato-pm. |
| Docs overview       | [Workspace Skills](/skills/workspace-skills)                                                                                                                                                                                                                                                                     |

## Why this exists

Use this page when you want to review the real instructions behind a skill
without leaving the docs site. The content below is copied from the actual
`SKILL.md` file, not rewritten by hand.

## Raw SKILL.md

````md theme={null}
---
name: pattern-c-attachment-migration
description: Migrate Alleato PM legacy PURT/entity attachment tables to Pattern C document_metadata plus junction tables. Use when converting *_attachments routes, repairing dual attachment storage, creating Pattern C junctions, reconciling attachment backfills, or dropping legacy attachment tables in alleato-pm.
argument-hint: <legacy table or entity route>
---

# Pattern C Attachment Migration

This skill is for `/Users/meganharrison/Documents/alleato-pm`.

Use it when migrating a legacy attachment surface from a per-entity table such as
`attachments`, `cco_attachments`, `pcco_attachments`, `invoice_attachments`,
`change_event_attachments`, `submittal_attachments`,
`subcontract_attachments`, `purchase_order_attachments`, or
`prime_contract_pco_attachments` to Pattern C:

```text
document_metadata row + entity-specific *_documents junction row
```

## Non-Negotiable Outcome

There must be one attachment writer and one reader path for the entity. Do not
leave a legacy writer feeding a Pattern C reader, or a Pattern C writer feeding a
legacy reader.

## Source Of Truth

Read these before editing:

1. `WORKING_CONTEXT.md`
2. `docs/architecture/DATABASE-ARCHITECTURE.md` Pattern C section
3. `docs/architecture/TASKS-CONSOLIDATED-IMPLEMENTATION.md` Phase 4
4. `docs/architecture/pattern-c-attachment-migration-manifest.json`
5. Existing shared routes:
   - `frontend/src/app/api/document-picker/upload/route.ts`
   - `frontend/src/app/api/document-picker/linked/route.ts`
   - `frontend/src/app/api/document-picker/attach/route.ts`
   - `frontend/src/components/ds/document-picker.tsx`

## Required First Checks

Run these from the repo root before changing files:

```bash
git status --short
rg -n "from\\(\"(attachments|cco_attachments|pcco_attachments|prime_contract_pco_attachments|invoice_attachments|change_event_attachments|submittal_attachments|subcontract_attachments|purchase_order_attachments)\"\\)|from\\('(attachments|cco_attachments|pcco_attachments|prime_contract_pco_attachments|invoice_attachments|change_event_attachments|submittal_attachments|subcontract_attachments|purchase_order_attachments)'\\)" frontend/src -g '*.ts' -g '*.tsx'
```

Then run live counts. Do not trust stale docs for row counts.

```bash
set -a; source .env >/dev/null 2>&1; set +a
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -qAt <<'SQL'
with legacy(table_name, row_count) as (
  values
    ('attachments', (select count(*)::bigint from public.attachments)),
    ('cco_attachments', (select count(*)::bigint from public.cco_attachments)),
    ('pcco_attachments', (select count(*)::bigint from public.pcco_attachments)),
    ('prime_contract_pco_attachments', (select count(*)::bigint from public.prime_contract_pco_attachments)),
    ('invoice_attachments', (select count(*)::bigint from public.invoice_attachments)),
    ('change_event_attachments', (select count(*)::bigint from public.change_event_attachments)),
    ('submittal_attachments', (select count(*)::bigint from public.submittal_attachments)),
    ('subcontract_attachments', (select count(*)::bigint from public.subcontract_attachments)),
    ('purchase_order_attachments', (select count(*)::bigint from public.purchase_order_attachments))
)
select table_name || '|' || row_count from legacy order by table_name;
SQL
```

## Migration Pattern

For each entity, do the work in this order:

1. Confirm the legacy table shape from `information_schema.columns`.
2. Confirm the parent entity table and project access path.
3. Confirm or create the Pattern C junction table.
4. Confirm `public.user_can_access_entity(entity_type, entity_id)` handles the entity.
5. Backfill legacy rows into `document_metadata` using deterministic ids.
6. Backfill junction rows from the deterministic document ids.
7. Rewrite API routes/forms to use `/api/document-picker/upload`,
   `/api/document-picker/linked`, and `/api/document-picker/attach`, or a shared
   registry-backed wrapper around those routes.
8. Remove legacy route code only after all callers are moved.
9. Grep for legacy reads/writes.
10. Drop legacy tables only after live row reconciliation and zero code refs.

## Deterministic IDs

Use stable prefixes so reruns are idempotent:

- `attachments`: `att-<legacy_attachment_id>`
- `change_event_attachments`: `cea-<legacy_attachment_id>`
- `submittal_attachments`: `sa-<legacy_attachment_id>`
- `cco_attachments`: `cco-att-<legacy_attachment_id>`
- `pcco_attachments`: `pcco-att-<legacy_attachment_id>`
- `prime_contract_pco_attachments`: `pcpco-att-<legacy_attachment_id>`
- `invoice_attachments`: `inv-att-<legacy_attachment_id>`
- `subcontract_attachments`: `sub-att-<legacy_attachment_id>`
- `purchase_order_attachments`: `po-att-<legacy_attachment_id>`

Every migrated `document_metadata.source_metadata` object must include:

- `migrated_from`
- `legacy_table`
- `legacy_attachment_id`
- `migrated_at`
- original uploader when present

## Fail Loudly Gates

Stop and fix the root cause if any gate fails:

- A legacy table has rows but the manifest has no mapping.
- Remote migration ledger contains a migration version missing locally.
- A route still writes to a legacy attachment table after the entity is converted.
- A detail page reads Pattern C while create/edit still writes legacy attachments.
- A junction table exists without RLS.
- `user_can_access_entity()` returns false for an entity that should be accessible.
- A drop migration exists before the code reference grep is clean.
- `document_metadata` rows are created without a matching junction row for entity-scoped uploads.

## Verification

Minimum short checks:

```bash
npm run check:routes
rg -n "from\\(\"<legacy_table>\"\\)|from\\('<legacy_table>'\\)" frontend/src -g '*.ts' -g '*.tsx'
npm run db:migrations:verify-applied -- supabase/migrations/<migration>.sql
```

For user-facing upload flows, use `agent-browser` and save artifacts under
`tests/agent-browser-runs/<timestamp>-pattern-c-attachments/`.

Long full builds or broad test suites should be delegated to a cheaper
verification sub-agent when available.

## Completion Report

Report:

- legacy table count before migration
- migrated `document_metadata` count
- migrated junction count
- changed routes/components
- exact verification commands
- what remains blocked or intentionally deferred
- recommended next entity/table

````
