# StartView 3-App Cross-Role Consistency — Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Make the creator, advertiser, and admin prototypes tell one coherent, walkable story — shared vocabulary, one proposal/campaign status model rendered per seat, an explicit admin payment-approval gate, and a single golden-thread case (보미 → 글로우드롭) that appears identically in all three apps on one date.

**Architecture:** Three independent single-file `.dc.html` prototypes with no backend and no shared module. Consistency is achieved by editing each app's inline seed data and label maps so they agree at the seams. Design doc: `docs/specs/2026-08-11-cross-role-consistency-design.md`.

**Tech Stack:** Custom DreamCode (`.dc.html`) templates rendered by `support.js` (a generated runtime — never edit it). Data and view logic live in inline `<script type="text/x-dc">` blocks. Served by `server.py` (Python `http.server`).

## Global Constraints

- **No backend, no test framework.** Verification is (a) a `grep` assertion on the edited file, and (b) a browser smoke-check via the preview server. Never claim a browser check passed without running it.
- **Preview server:** launch config `startview-prototypes` (port **8123**). Apps at `http://localhost:8123/creator/`, `/advertiser/`, `/admin/`. Start with `preview_start({name: "startview-prototypes"})`; never run the server via Bash.
- **Never edit `support.js`** (any app) — it is a generated runtime (`GENERATED from dc-runtime/src/*.ts — do not edit`). Same for `review-layer.js` / `giftbox.js` unless a task says so.
- **Commits:** never add Co-Authored-By, "Claude", "AI", or any attribution trailer to commit messages or PRs. Korean commit subjects, matching the existing `feat(admin):` / `docs:` style.
- **Copy:** all UI copy Korean, polite informal (`-요`), no emoji.
- **Canonical values (verbatim):**
  - Creator role term: **크리에이터** (never 리뷰어 in user-facing copy).
  - Product types: **배송형 / 방문형** only. **구매형 is removed.**
  - Unified "today": **2026.08.11**.
  - Canonical brand: **글로우드롭** (creator's 글로우리프 is renamed to this).
  - Canonical 보미 identity: name `보미`, handle `@bomi.daily`, 인스타그램 팔로워 **12,000** (1.2만), 원고료 **300,000**.
- **Authority when apps disagree:** creator wins on flow/UX; advertiser `data.js` is the structural template; admin conforms.
- **Out of scope (do not touch):** 공동구매 (group-buy), 어필리에이트 (affiliate). Leave all their screens/data as-is.
- **Prototype files are huge single files.** Prefer targeted `grep -n` to locate a const before editing; edit the smallest unique snippet.

---

## File Map

| App | File | What changes |
|---|---|---|
| admin | `admin/main.dc.html` | 리뷰어→크리에이터 relabel; drop 구매형; retire 수요조사 menu/tables; 결제 승인 dashboard queue; campaign status alignment; seed golden-thread rows |
| advertiser | `advertiser/data.js` | fix `bomi` identity; bump date to 08.11; add `payApproved` gate field; seed/align 보미→글로우드롭 proposal |
| advertiser | `advertiser/SecProposals.dc.html` | render the `결제 승인 대기 중` sub-state on `awaiting` proposals |
| creator | `creator/main.dc.html` | 글로우리프→글로우드롭 rename; align 보미 thread record + dates |

No files are created except this plan. No new modules — each app keeps its own inline data.

---

# WAVE 1 — Vocabulary & relabels (admin only)

### Task 1: Admin — 리뷰어 → 크리에이터 relabel

**Files:**
- Modify: `admin/main.dc.html` (MENU line ~1007–1009; ~16 occurrences of `리뷰어`)

**Interfaces:**
- Produces: menu group `크리에이터 관리` with children `크리에이터 관리` / `리뷰 신청 이력` → `크리에이터 신청 이력` / `월별 지급 건` / `출석이벤트 현황`. Route hrefs (`/reviewer`, `/reviewer-application-history`, `/reviewer-payout`) **stay unchanged** — only labels change.

- [ ] **Step 1: List every occurrence**

Run: `grep -n "리뷰어" admin/main.dc.html`
Expected: ~16 lines — the MENU group + children (1007–1009), any screen hints/primary labels, `TABLES['/reviewer']` hint/empty text, `PAYOUTS` heading copy.

- [ ] **Step 2: Relabel the MENU group and children**

In the MENU array (line ~1007–1009), change the group `name: '리뷰어 관리'` → `name: '크리에이터 관리'`, and the child `{ name: '리뷰어 관리', href: '/reviewer' }` → `{ name: '크리에이터 관리', href: '/reviewer' }`. Change `{ name: '리뷰 신청 이력', ... }` → `{ name: '크리에이터 신청 이력', ... }`. Leave `href` values untouched.

- [ ] **Step 3: Relabel remaining user-facing 리뷰어 strings**

For each other `grep` hit, replace user-facing `리뷰어` with `크리에이터` in hints, `primary`, `empty`, column headers, and any `EXTRA_TITLES`/route-title map entry for `/reviewer*`. Do **not** change route path segments (`reviewer` in an href) or localStorage keys.

- [ ] **Step 4: Verify no user-facing 리뷰어 remains**

Run: `grep -n "리뷰어" admin/main.dc.html`
Expected: zero hits in display strings. (If any remain, they must be inside an href/key comment — confirm each is non-visual.)

- [ ] **Step 5: Browser smoke-check**

`preview_start({name:"startview-prototypes"})`, navigate to `http://localhost:8123/admin/#/reviewer`, `read_page`. Expected: sidebar group reads **크리에이터 관리**; the roster screen title reads 크리에이터 관리; no 리뷰어 text visible.

- [ ] **Step 6: Commit**

```bash
git add admin/main.dc.html
git commit -m "refactor(admin): 리뷰어 표기를 크리에이터로 통일"
```

---

### Task 2: Admin — remove 구매형 product type

**Files:**
- Modify: `admin/main.dc.html` (CAMPAIGNS rows 1035/1039/1043/1046; TABLES rows 1123/1127/1249/1250/1256/1278/1455; filter group line 2164)

**Interfaces:**
- Produces: product-type filter with exactly `전체 / 배송형 / 방문형`. No record anywhere carries `productType: '구매형'` or a `'구매형'` cell.

- [ ] **Step 1: Locate all 구매형 references**

Run: `grep -n "구매형" admin/main.dc.html`
Expected: 8 lines (4 CAMPAIGNS objects, 3 TABLES product/campaign rows + 1 more, 1 filter option).

- [ ] **Step 2: Remove the filter option**

At line ~2164, delete the `{ label: '구매형', v: '구매형' }` entry from the `유형`/`ptype` filter group so it reads:

```js
this.group('유형', 'ptype', [{ label: '전체', v: '전체' }, { label: '배송형', v: '배송형' }, { label: '방문형', v: '방문형' }]),
```

- [ ] **Step 3: Delete the 구매형 mock records**

Delete the four `CAMPAIGNS` objects whose `productType: '구매형'` (락앤락 텀블러, 모나미 볼펜, 오뚜기 진짬뽕, 코렐 식기세트 — lines ~1035/1039/1043/1046) and the matching product/table rows at lines ~1123/1127/1249/1250/1256/1278/1455 (same product names). Remove whole array elements, keeping surrounding commas valid.

- [ ] **Step 4: Verify**

Run: `grep -n "구매형" admin/main.dc.html`
Expected: zero hits.

- [ ] **Step 5: Browser smoke-check**

Navigate to `http://localhost:8123/admin/#/campaign`, `read_page`. Expected: the 유형 filter shows only 전체/배송형/방문형; campaign list has no 구매형 rows; no runtime error in `read_console_messages`.

- [ ] **Step 6: Commit**

```bash
git add admin/main.dc.html
git commit -m "refactor(admin): 구매형 상품 유형 제거 (배송형·방문형만 유지)"
```

---

### Task 3: Admin — retire 수요조사 (fold into 협업/결제 승인)

**Files:**
- Modify: `admin/main.dc.html` (MENU line 1013; TABLES `/demand-survey` ~1186; TABLES `/demand-db` ~1287)

**Interfaces:**
- Produces: 브랜드 존 관리 group children = `협업 검수` / `결제 승인` / `협업 정산` / `브랜드 목록` (no 수요조사 목록, no 수요 DB). Routes `/demand-survey` and `/demand-db` no longer reachable from nav.

- [ ] **Step 1: Remove the two menu entries**

In the `브랜드 존 관리` group (line ~1010–1013), delete `{ name: '수요조사 목록', href: '/demand-survey' }` and `{ name: '수요 DB', href: '/demand-db' }`. The children array becomes:

```js
{ icon: 'chart', name: '브랜드 존 관리', children: [
  { name: '협업 검수', href: '/collaboration-inspection' }, { name: '결제 승인', href: '/demand-payment' },
  { name: '협업 정산', href: '/collaboration-settlement' }, { name: '브랜드 목록', href: '/brand' }] },
```

- [ ] **Step 2: Delete the two TABLES definitions**

Remove the whole `'/demand-survey': { … }` object (starts line ~1186) and the whole `'/demand-db': { … }` object (starts line ~1287) from the `TABLES` map. Keep `'/demand-payment'` and `'/collaboration-inspection'` intact.

- [ ] **Step 3: Verify no dangling references**

Run: `grep -nE "demand-survey|demand-db|수요조사|수요 DB" admin/main.dc.html`
Expected: zero hits (route + label both gone). If `ROUTES()` derives from MENU only, removal is automatic; confirm no hardcoded `EXTRA_ROUTES` entry references them.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/admin/#/dashboard`, `read_page`. Expected: 브랜드 존 관리 expands to exactly 협업 검수 / 결제 승인 / 협업 정산 / 브랜드 목록. Navigate to `#/demand-survey`; expected: silent fallback to `/dashboard` (unknown hash rule), no crash.

- [ ] **Step 5: Commit**

```bash
git add admin/main.dc.html
git commit -m "refactor(admin): 수요조사 폐지 — 협업/결제 승인 흐름으로 흡수"
```

---

# WAVE 2 — Proposal lifecycle + admin payment gate

### Task 4: Advertiser — add the payment-approval gate to proposals

**Files:**
- Modify: `advertiser/data.js` (proposals array, starts line ~965)
- Modify: `advertiser/SecProposals.dc.html` (`STATUS_LABEL` ~527; the `awaiting` render block ~269)

**Interfaces:**
- Produces: proposals in `status: 'awaiting'` carry a boolean `payApproved` (default `false`). `payApproved:false` = advertiser paid, **admin has not yet approved** (creator still sees 채택 대기). `payApproved:true` = admin approved, offer dispatched (creator sees 응답 대기). Consumed by Task 5 (admin queue) and Task 10 (thread proposal).

- [ ] **Step 1: Add `payApproved` to every `awaiting` proposal**

In `advertiser/data.js`, for each proposal object with `status: 'awaiting'`, add `payApproved: true` (existing seed proposals are already dispatched) — except leave room for one to be `false` in Task 10. Add a one-line comment above the proposals array documenting the field:

```js
/* payApproved: awaiting 단계에서만 의미. false = 광고주 결제함, 어드민 결제 승인 대기(크리에이터는 아직 '채택 대기').
   true = 어드민 승인 완료 → 제안 발송됨(크리에이터 '응답 대기'). 두 번째 상태머신을 만들지 않기 위한 한 필드다. */
```

- [ ] **Step 2: Render the pending sub-state in SecProposals**

In `advertiser/SecProposals.dc.html`, find the `awaiting` detail render block (comment `승인 후: 수락 대기` near line ~269). Add a sub-line that shows when `!p.payApproved`:

```html
<sc-if cond="{{ p.status === 'awaiting' && !p.payApproved }}">
  <span class="sv-kr" style="font-size: 12px; color: #666666;">결제 승인 대기 중 · 어드민 승인 후 크리에이터에게 발송돼요</span>
</sc-if>
```

Place it directly under the existing 수락 대기 status chip so the advertiser sees why the creator hasn't responded yet. Do not add a new status value to `STATUS_LABEL` — `awaiting` stays labelled `수락 대기`.

- [ ] **Step 3: Verify the field and render exist**

Run: `grep -n "payApproved" advertiser/data.js advertiser/SecProposals.dc.html`
Expected: field present on awaiting proposals in `data.js`; the `sc-if` guard present in `SecProposals.dc.html`.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/advertiser/#proposals/awaiting`, `read_page`. Expected: awaiting proposals render 수락 대기; no console error. (The `결제 승인 대기 중` line appears only for a `payApproved:false` proposal, created in Task 10 — a `false` case is not required to exist yet.)

- [ ] **Step 5: Commit**

```bash
git add advertiser/data.js advertiser/SecProposals.dc.html
git commit -m "feat(advertiser): 제안에 어드민 결제 승인 게이트(payApproved) 추가"
```

---

### Task 5: Admin — make 결제 승인 a real dashboard queue

**Files:**
- Modify: `admin/main.dc.html` (`QUEUES` line ~1627; `TABLES['/demand-payment']` line ~1301)

**Interfaces:**
- Consumes: the canonical `결제 승인 대기` concept (mirrors advertiser `awaiting` + `payApproved:false`).
- Produces: a `/demand-payment` table whose rows carry a `['승인 대기','대기']` (or `['승인 완료','종료']`) status tuple, and a `QUEUES` entry so the dashboard 처리 대기 band counts pending payment approvals.

- [ ] **Step 1: Add a status column to `/demand-payment`**

In `TABLES['/demand-payment']` (line ~1301), insert a `상태` column and give each row a status tuple. Rows whose `승인일` is `'-'` are pending; the rest are approved. Example (first three rows shown; apply the rule to all):

```js
columns: [['수요조사','left'],['기업명','left'],['상태','left'],['결제 모드','left'],['결제 금액','right'],['선정 인원','right'],['승인일','left'],['결제일','left']],
rows: [
  ['가을 신제품 앰플 협업 크리에이터 모집','(주)어스랩',['승인 완료','종료'],'포인트','4,200,000','12','2026.08.10','2026.08.11'],
  ['프리미엄 밀키트 리뷰 수요조사','컬리(주)',['승인 대기','대기'],'무통장 입금','6,800,000','16','-','-'],
  ['숏폼 전용 마스크팩 챌린지','엘앤피코스메틱',['승인 완료','종료'],'카드','9,450,000','30','2026.08.02','2026.08.02'],
  /* …apply the same 대기/종료 rule (pending when 승인일 === '-') to the remaining rows… */
],
```

- [ ] **Step 2: Add the queue entry**

In `QUEUES` (line ~1627), add after the `협업 검수` line:

```js
{ label: '결제 승인', href: '/demand-payment', dateCol: 6 },
```

(`dateCol: 6` = the `승인일` column index after inserting 상태 at index 2. Verify the index matches the new column order.)

- [ ] **Step 3: Verify the count logic will fire**

Run: `grep -n "결제 승인" admin/main.dc.html`
Expected: the QUEUES entry present. Confirm `waitingRows('/demand-payment')` (the `c[1] === '대기'` filter) now matches the pending rows — i.e. at least one row has a `['…','대기']` tuple.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/admin/#/dashboard`, `read_page`. Expected: the 처리 대기 band shows a **결제 승인** row with a count ≥ 1. Click it → lands on the 결제 승인 screen showing the 상태 column with 승인 대기/승인 완료 chips.

- [ ] **Step 5: Commit**

```bash
git add admin/main.dc.html
git commit -m "feat(admin): 결제 승인을 처리 대기 큐로 연결 (결제 게이트 가시화)"
```

---

### Task 6: Admin — align collaboration status labels to canonical

**Files:**
- Modify: `admin/main.dc.html` (`TABLES['/collaboration-inspection']` ~1315; `/collaboration-settlement` view)

**Interfaces:**
- Consumes: canonical collaboration states — content_review → `협업 검수`; revision → `수정요청`; settled → `협업 정산 완료`.
- Produces: `/collaboration-inspection` status cells use exactly `검수대기` / `수정요청` / `검수중` / `승인완료`; settlement view labels completed rows `정산 완료`.

- [ ] **Step 1: Audit current labels**

Run: `grep -nE "검수대기|수정요청|검수중|승인완료|정산" admin/main.dc.html`
Expected: `/collaboration-inspection` rows already use 검수대기/수정요청 tuples. Note any variant spellings.

- [ ] **Step 2: Normalize any drift**

If any collaboration row uses a non-canonical label (e.g. `검수 대기` with a space, or `반려` where `수정요청` is meant), edit it to the canonical spelling from the design doc §5.1 Admin column. If all already match, record "no change needed" and skip to Step 4.

- [ ] **Step 3: Verify**

Run: `grep -nE "협업 검수|검수대기|수정요청|승인완료" admin/main.dc.html`
Expected: consistent canonical spellings only.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/admin/#/collaboration-inspection`, `read_page`. Expected: status chips read 검수대기/수정요청/검수중/승인완료; no other collaboration status vocabulary.

- [ ] **Step 5: Commit**

```bash
git add admin/main.dc.html
git commit -m "refactor(admin): 협업 검수·정산 상태 표기를 표준 어휘로 정렬"
```

---

# WAVE 3 — Golden thread (보미 → 글로우드롭, 2026.08.11)

### Task 7: Creator — rename 글로우리프 → 글로우드롭

**Files:**
- Modify: `creator/main.dc.html` (BRANDS b1 ~4229; BRAND_INFO key ~4240/4249; OFFERS o1 ~4209; POINT_SEED pl6 ~4329; PARTICIPATIONS pc1 ~4374; notifications n3/n13/n7 ~4721/4726/4735; portfolio caption ~7056; caption/hashtags ~4621)

**Interfaces:**
- Produces: no occurrence of `글로우리프` anywhere in the creator app; brand `b1.name === '글로우드롭'`; `BRAND_INFO` keyed `"글로우드롭"`.

- [ ] **Step 1: List occurrences**

Run: `grep -n "글로우리프" creator/main.dc.html`
Expected: ~9 lines (BRANDS, BRAND_INFO key + head text, OFFERS title, POINT_SEED title, PARTICIPATIONS brand, 3 notifications, portfolio/caption).

- [ ] **Step 2: Replace all occurrences**

Replace every `글로우리프` with `글로우드롭` in `creator/main.dc.html`, including the `BRAND_INFO` object key `"글로우리프": {` → `"글로우드롭": {` and any `#글로우리프` hashtag → `#글로우드롭`. Keep product names (비타 C 앰플 etc.) unchanged.

- [ ] **Step 3: Verify**

Run: `grep -n "글로우리프" creator/main.dc.html`
Expected: zero hits. Then `grep -c "글로우드롭" creator/main.dc.html` ≥ 9.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/creator/` → discover/brand detail for b1, `read_page`. Expected: brand shows 글로우드롭; brand-info intro renders (BRAND_INFO key resolved, no blank body); no console error.

- [ ] **Step 5: Commit**

```bash
git add creator/main.dc.html
git commit -m "refactor(creator): 브랜드명 글로우리프 → 글로우드롭 통일"
```

---

### Task 8: Creator — align the 보미 thread proposal + date

**Files:**
- Modify: `creator/main.dc.html` (PARTICIPATIONS pc1 ~4374–4376; notifications referencing the thread ~4726)

**Interfaces:**
- Consumes: canonical thread — 보미 → 글로우드롭, 원고료 300,000, 인스타그램, sent 2026.08.10, response deadline 2026.08.15, status `응답 대기` (creator's turn).
- Produces: pc1 reflects the frozen snapshot so the creator seat of the golden thread matches advertiser (Task 10) and admin (Task 11).

- [ ] **Step 1: Set pc1 to the canonical thread values**

In PARTICIPATIONS `pc1` (line ~4374), ensure `brand:'글로우드롭'` (from Task 7), `platform:'instagram'`, `price:300000`, and set the proposal dates to the 08.11 frame:

```js
{ id:'pc1', origin:'직접 제안', brand:'글로우드롭', title:'비타 C 앰플 리필 2종 리뷰',
  platform:'instagram', price:300000, appliedAt:'2026.08.09 14:02',
  proposal:{ status:'응답 대기', sentAt:'2026.08.10 10:30', deadline:'2026.08.15 10:30' } },
```

- [ ] **Step 2: Align the matching notification**

Update the thread notification (n13, the 광고주 제안 도착 for pc1, line ~4726) body deadline to `8월 15일까지 응답해주세요` and brand to 글로우드롭 so the D-day matches.

- [ ] **Step 3: Verify**

Run: `grep -n "2026.08.10 10:30\|2026.08.15\|pc1" creator/main.dc.html`
Expected: pc1 carries the 08.10 sent / 08.15 deadline dates.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/creator/` → 내 협업 tab, `read_page`. Expected: the 글로우드롭 collaboration shows 응답 대기 (내 차례) with a D-day computed toward 08.15; opening it shows the proposal detail with 원고료 300,000.

- [ ] **Step 5: Commit**

```bash
git add creator/main.dc.html
git commit -m "feat(creator): 골든 스레드 정렬 — 보미↔글로우드롭 제안 · 08.11 기준일"
```

---

### Task 9: Advertiser — fix `bomi` identity + unify date

**Files:**
- Modify: `advertiser/data.js` (`bomi` pool entry line 156; propagated rows ~191/228; `metricsUpdatedAt` ~1327; relevant `createdAt`)

**Interfaces:**
- Consumes: canonical 보미 identity (`보미 / @bomi.daily / 12000`).
- Produces: `C.bomi` and every row derived from it show 보미 / @bomi.daily / 12,000. Advertiser "now" anchor = 2026.08.11.

- [ ] **Step 1: Fix the pool record**

At `advertiser/data.js:156`, update the `bomi` entry:

```js
bomi:   { name: '보미',   handle: '@bomi.daily',   platform: '인스타그램', follower: 12000, avgView: 2140, er: 6.8, gender: '여', age: 25, photo: 'mock/person/person-65.jpg' },
```

- [ ] **Step 2: Sweep stale display copies**

Run: `grep -n "봄이일상\|@bomi.day\|4730\|4,730" advertiser/data.js`
For each hit that is a **display copy** of bomi's identity (e.g. an applicant/selectedList/shipment row with `name: '봄이일상'` or `follower: 4730` at lines ~191/228), update to `보미` / `12000`. Leave `key: 'bomi'` and `id`/date fields unchanged.

- [ ] **Step 3: Unify the date anchor**

Change `metricsUpdatedAt` (line ~1327) to a `2026.08.11 …` timestamp. Bump any `createdAt: '2026.08.05'` on **live/current** records that represent "just now" to `2026.08.11` (historical stamps in the past may stay). Do not touch the `라비앙` crawl-note dates (`2026.08.07`) — those are provenance comments.

- [ ] **Step 4: Verify**

Run: `grep -n "봄이일상\|@bomi.day\|4730" advertiser/data.js`
Expected: zero hits. `grep -n "@bomi.daily\|follower: 12000" advertiser/data.js` shows the canonical values.

- [ ] **Step 5: Browser smoke-check**

Navigate to `http://localhost:8123/advertiser/#creators`, `read_page` / `find` for 보미. Expected: 보미 appears as @bomi.daily with 1.2만 / 12,000 followers; no `봄이일상`. Check any campaign applicant list that included bomi shows 보미.

- [ ] **Step 6: Commit**

```bash
git add advertiser/data.js
git commit -m "fix(advertiser): bomi 신원을 표준값(보미·@bomi.daily·12,000)으로 정정 · 기준일 08.11"
```

---

### Task 10: Advertiser — seed the 보미 → 글로우드롭 proposal

**Files:**
- Modify: `advertiser/data.js` (proposals array ~965)

**Interfaces:**
- Consumes: `C.bomi` (Task 9), brand 글로우드롭, `payApproved` field (Task 4).
- Produces: a proposal object linking 보미 → 글로우드롭 at the frozen snapshot, matching the creator's pc1 and admin's row. Snapshot state: `awaiting` with `payApproved: true` (admin approved 08.11, offer dispatched, creator's turn).

- [ ] **Step 1: Check for an existing 보미 proposal**

Run: `grep -n "bomi\|보미" advertiser/data.js` (within the proposals array range).
If one exists, align it to the values below; otherwise add a new object.

- [ ] **Step 2: Add/align the thread proposal**

Insert into `proposals` (use a free id, e.g. `pgold`):

```js
{ id: 'pgold', seed: true, direction: 'inbound', target: 'product', brandId: null,
  productId: 'pd2', rawProductText: null, key: 'bomi', name: '보미', handle: '@bomi.daily',
  platform: '인스타그램', follower: 12000, er: 6.8, price: 300000, secondary: false, secondaryExt: false,
  receivedAt: '2026.08.09', dday: null, status: 'awaiting', payApproved: true, withdrawn: false,
  acceptedAt: null, respondBy: '2026.08.15', fee: 30000, payTotal: 330000, campaignId: null,
  closedReason: null, message: '비타 C 앰플 리필 2종을 인스타그램 릴스로 소개하고 싶어요.' },
```

(Confirm `productId: 'pd2'` resolves to a 글로우드롭 비타민C 앰플 product; if the id differs, use the actual 글로우드롭 앰플 product id from `products`.)

- [ ] **Step 3: Verify**

Run: `grep -n "pgold\|respondBy: '2026.08.15'" advertiser/data.js`
Expected: the object present with `status: 'awaiting'`, `payApproved: true`, `respondBy: '2026.08.15'`.

- [ ] **Step 4: Browser smoke-check**

Navigate to `http://localhost:8123/advertiser/#proposals/awaiting`, `read_page`. Expected: a 수락 대기 proposal from 보미 for the 글로우드롭 앰플, 결제 총액 330,000, awaiting the creator's response (no 결제 승인 대기 중 line, since payApproved is true).

- [ ] **Step 5: Commit**

```bash
git add advertiser/data.js
git commit -m "feat(advertiser): 골든 스레드 제안 시드 — 보미→글로우드롭 (수락 대기)"
```

---

### Task 11: Admin — seed the shared cast into admin queues

**Files:**
- Modify: `admin/main.dc.html` (`TABLES['/demand-payment']` rows; `TABLES['/reviewer']` roster rows; optionally `/collaboration-inspection`)

**Interfaces:**
- Consumes: the frozen thread — 보미 / 글로우드롭 / 원고료 300,000 / approved 2026.08.11.
- Produces: admin shows the **same** record the other two apps produce — the 글로우드롭 payment approved 08.11, and 보미 in the creator roster with canonical numbers.

- [ ] **Step 1: Add the thread row to 결제 승인**

In `TABLES['/demand-payment']` rows (Task 5 gave it a 상태 column), add an approved row for the thread:

```js
['글로우드롭 비타 C 앰플 리필 협업','주식회사 글로우드롭',['승인 완료','종료'],'포인트','330,000','1','2026.08.11','2026.08.11'],
```

- [ ] **Step 2: Add 보미 to the creator roster**

In `TABLES['/reviewer']` rows, add (matching that table's column shape — inspect its `columns` first):

```js
/* columns order per TABLES['/reviewer'].columns — fill 보미 / @bomi.daily / 인스타그램 / 12,000 / 활동중 accordingly */
```

Use name 보미, handle @bomi.daily, platform 인스타그램, follower 12,000, status `['활동중','진행']`. Match the existing column count exactly.

- [ ] **Step 3: (Optional) add the thread to 협업 검수**

If demonstrating the post-upload stage, add a `/collaboration-inspection` row: `['글로우드롭','비타 C 앰플 리필',['검수대기','대기'],'릴스 1건','-']`. Skip if keeping the snapshot at 응답 대기.

- [ ] **Step 4: Verify**

Run: `grep -n "글로우드롭\|@bomi.daily" admin/main.dc.html`
Expected: the thread payment row and the 보미 roster row present.

- [ ] **Step 5: Browser smoke-check**

Navigate to `#/demand-payment` and `#/reviewer`, `read_page`. Expected: 결제 승인 lists the 글로우드롭 330,000 row approved 08.11; the 크리에이터 roster lists 보미 @bomi.daily 12,000. Cross-check these match the advertiser (`pgold`) and creator (`pc1`) numbers exactly.

- [ ] **Step 6: Commit**

```bash
git add admin/main.dc.html
git commit -m "feat(admin): 골든 스레드 공유 데이터 시드 — 보미·글로우드롭 결제/로스터"
```

---

# WAVE 4 — Campaign lifecycle + cleanup

### Task 12: Admin — align campaign status vocabulary

**Files:**
- Modify: `admin/main.dc.html` (`STATUS_TONE` line 976; any campaign status cells that drift from canonical)

**Interfaces:**
- Consumes: canonical campaign superset (design doc §5.2): `임시저장 / 결제대기 / 등록 검수대기 / 모집중 / 선정 필요 / 진행중 / 검수중 / 완료 / 취소`.
- Produces: `STATUS_TONE` maps every canonical campaign status to a tone; admin's two campaign models use one status vocabulary.

- [ ] **Step 1: Review current status set**

Read `STATUS_TONE` (line 976) and the campaign list rows. Current keys: `임시저장, 등록대기중, 승인대기중, 모집대기중, 모집중, 진행대기중, 진행중, 검수중, 완료, 취소`.

- [ ] **Step 2: Reconcile to the canonical superset**

Collapse the redundant `대기중` variants toward the canonical labels: keep `임시저장`, map `등록대기중`/`승인대기중` → `등록 검수대기` (admin approval), keep `모집중`, add `선정 필요`, keep `진행중`, `검수중`, `완료`, `취소`. Drop `모집대기중`/`진행대기중` (fold into `모집중`/`진행중`). Update `STATUS_TONE` accordingly:

```js
const STATUS_TONE = { 임시저장: '대기', 결제대기: '대기', '등록 검수대기': '대기', 모집중: '진행', '선정 필요': '진행', 진행중: '진행', 검수중: '진행', 완료: '종료', 취소: '취소' };
```

Then update any `CAMPAIGNS[].status` / table status cell using a dropped label to its canonical replacement.

- [ ] **Step 3: Verify**

Run: `grep -nE "등록대기중|승인대기중|모집대기중|진행대기중" admin/main.dc.html`
Expected: zero hits (all migrated). `grep -n "STATUS_TONE" admin/main.dc.html` shows the canonical map.

- [ ] **Step 4: Browser smoke-check**

Navigate to `#/campaign` and `#/campaign-registration-request`, `read_page`. Expected: campaign status chips read only canonical labels; every chip still resolves to a tone (no uncolored/broken chip); no console error.

- [ ] **Step 5: Commit**

```bash
git add admin/main.dc.html
git commit -m "refactor(admin): 캠페인 상태 어휘를 표준 상태머신으로 정렬"
```

---

## Final verification (after all tasks)

- [ ] **Walk the golden thread across three seats.** With the preview server running, open in turn: creator 내 협업 (보미의 글로우드롭 제안, 응답 대기, D-day→08.15), advertiser `#proposals/awaiting` (보미→글로우드롭, 수락 대기, 330,000), admin `#/demand-payment` (글로우드롭 330,000 승인 완료 08.11) + `#/reviewer` (보미 @bomi.daily 12,000). Confirm name, handle, follower count, amount, and date agree at all three.
- [ ] **Console clean.** `read_console_messages` on each app root shows no runtime errors introduced by the edits.
- [ ] **Vocabulary sweep.** `grep -rnE "리뷰어|구매형|수요조사|봄이일상|글로우리프" creator/ advertiser/ admin/` returns only non-user-facing hits (route segments, keys, provenance comments) — or none.

---

## Self-Review (planner's check against the spec)

**Spec coverage:**
- §4.1 크리에이터 term → Task 1. §4.2 drop 구매형 → Task 2. §5.3 retire 수요조사 → Task 3. §4.3 money model → carried by canonical labels (no code change needed beyond existing 원고료/캐시/포인트, already consistent). §5.1 proposal machine + admin gate → Tasks 4–6, 10. §5.2 campaign machine → Task 12. §6.1 unified date → Tasks 8, 9, 11. §6.2 shared cast → Tasks 7, 8, 9, 10, 11. §6.3 walkable scenario → Final verification. §7 per-app change lists → distributed across waves. §8 cross-role defects (bomi, brand, date, disjoint records) → Tasks 7, 8, 9, 11.
- Not separately tasked (intentional, per spec §2/§11): admin placeholder-detail deepening beyond thread records (thread rows are made real in Task 11; a broader pass is out of scope); storing vocab maps as a shared module (no shared module — each app edited inline).

**Placeholder scan:** No "TBD/TODO/handle edge cases". The one `/* fill accordingly */` in Task 11 Step 2 is gated on inspecting that table's actual `columns` at edit time (its shape isn't quoted in the maps) — the exact values to place (보미 / @bomi.daily / 인스타그램 / 12,000 / 활동중) are given; the implementer maps them to the columns they read.

**Type consistency:** `payApproved` (boolean) used identically in Tasks 4, 5 (concept), 10. Canonical strings (크리에이터, 글로우드롭, @bomi.daily, 12000, 300,000/330,000, 2026.08.11, 응답 대기 / 수락 대기 / 승인 완료) are used verbatim across creator (Task 8), advertiser (Tasks 9,10), admin (Tasks 5,11). Route hrefs deliberately unchanged while labels change (Task 1).
