# Creator Gap Closure — Final Status

Date 2026-08-20 · closes the programme opened by [`creator-prototype-coverage-audit.md`](./creator-prototype-coverage-audit.md)

Korean appears only inside quoted UI strings.

## 1. What this document is

The coverage audit put the creator prototype at ~62% of the existing product's UI/UX surface and produced a backlog of ~50 items across five phases. This records the **final disposition of every one of them**. Nothing in the audit is left in an undecided state: each item is Shipped, Already Existed, a Design Choice, Cancelled, or Deferred with a named reason.

**The headline correction:** the audit's 62% was wrong, and wrong in a specific, systematic way. It compared the prototype against the legacy Angular app (`apps/client`) and treated every difference as a gap. In practice, **roughly half the backlog was already built**, deliberately designed differently, or retired product-wide. The real starting coverage was far higher; what genuinely needed building was about 25 screens, not 50.

## 2. Phase outcomes

| Phase | Scope as audited | What actually shipped |
|---|---|---|
| 0 — Shared primitives | 7 primitives | **7 shipped.** Skeletons, error/retry, empty states, upload trio, confirm sheet, success pattern, input-error convention, plus a dev gallery at `route:'devStates'` as their canonical reference. |
| 1 — P0 journey breaks | 9 screens | **8 shipped, 1 built-then-deleted.** Application-complete, proposals inbox and detail, payout history. The demand-survey module was built and then removed — see §4. |
| 2 — Submission pipeline | 7 items | **7 shipped, 4 dropped as already-built.** Upload trio wired into review submission, two confirmation sheets, courier link-out, store contact, closed-campaign state, recommendations. |
| 3 — Auth recovery & channels | 4 items | **5 shipped, 2 dropped as already-built.** Password reset (4 screens), find-email, Naver blog registration, disconnect confirmation, collecting state. |
| 4 — Group buy & affiliate | 9 screens | **Cancelled.** Excluded product-wide. |
| 5 — Supporting flows | ~17 items | **3 shipped, 11 dropped, 3 deferred.** My review activity, brand AlimTalk opt-in, attendance history. |

## 3. Disposition of every audit item

### Shipped (25)

Phase 0's seven primitives · application-complete · proposals inbox · proposal detail · payout history · review-submission upload states · cancel-participation confirm · cancel-reservation confirm · courier tracking link-out · campaign-detail store contact · closed-campaign state · campaign recommendations · password reset (request, sent, new password, success) · find email · Naver blog channel registration · channel disconnect confirmation · channel collecting state · my review activity · followed-brand AlimTalk opt-in · attendance reward history.

### Already existed — the audit was wrong (15)

Each was verified in code before being dropped.

| Item | Evidence |
|---|---|
| Revision re-upload | The review screen already renders `rejectReason` verbatim, switches its CTA to `다시 검수 신청하기`, and has a working file picker |
| Raw-footage URL registration | `stepUrl` with "네이버 블로그는 자동 연결이 안 돼 주소로 받아요" |
| Apply-form consent expansion | `조건 4개 자세히 보기` + `applyDetailOpen` + `agreements` |
| Apply-form raw-footage toggle | `영상 원본 제출` row + `showRawUpload` / `toggleRaw` |
| Campaign-detail image expand | `detailArtOpen` / `detailArtLabel` |
| Channel theme selection sheet | `pickerSheet:'topic'` + `openTopicSheet()` |
| Per-channel disconnect | `해제` control wired to `pc.onDisconnect` (only the confirmation was missing) |
| No-search-results | Two instances: `찾는 결과가 없어요`, `검색 결과가 없어요` |
| Separate marketing consent | `agreeRows` / `optionalAgreeRows` carry marketing, SMS and email separately |
| Brand-detail section tabs | `brandTab` |
| Point-shop purchase confirm | `shopPickId` → `shopSheetOpen` |
| Point-shop sort & category | `shopTab` |
| Profile completeness gauge | `editProgressPct` / `editProgressLine` / `editProgressBar` |
| Penalty score & suspension notice | `penaltyTotal` renders `-N점`; `penaltyNote` explains the 5-point rule |
| Account-deletion notice & grace | `withdrawLoses`, a 30-day grace line, `withdrawBlocked` — all since `fd81402` |

### Design choices, not gaps (3)

- **Sort/filter as chips, not a drawer.** `sortChips` (추천/최신/마감임박) plus `catFilter` chips; community lists add `listSort`. Converting to a drawer is a design decision.
- **Support as chat, not typed-inquiry CRUD.** A thread view, an empty state, and a `문의 남기기` CTA. Adding a parallel typed-inquiry form would give one job two front doors.
- **My-campaigns as a my-turn panel, not three tabs.** The existing product uses `제작 필요` / `전체` / `미선정·취소`; the prototype answers with a my-turn panel plus filter chips and a separate 지난 캠페인 screen. **Ruled 2026-08-20: keep the my-turn panel.** The three-tab restructure is closed as won't-do.

### Cancelled (3 modules, ~9 screens)

**Demand survey (수요조사)** — retired product-wide by `2026-08-11-cross-role-consistency-design.md` §5.3, which states plainly that "Creator never had it". Advertiser folded it into 제안 관리; admin dropped it in `ef26a46`.

**Group buy (공동구매)** and **affiliate (어필리에이트)** — excluded by §10 of the same spec: "teammate-owned, not on prod".

All three appeared as gaps only because the audit compared against the legacy Angular app, which still carries them.

### Deferred, needs a product decision (3)

| Item | Why |
|---|---|
| Map view | Found only in `client-web`, not in the Angular reference. Needs a real map surface — tiles, pins, location permission — and a different interaction model from every other screen. Worth building only if visit-type campaigns become a priority. |
| Advertiser-conversion inquiry | `campaign-register-request`, `consultation-form`, `mall-partner-form` convert a creator into an advertiser. That is the advertiser app's onboarding. |
| Home banner modal · product preview | Promo and advertiser-side surfaces with no creator journey behind them. |

## 4. What went wrong, and what it cost

Two features were built and then deleted. Both had the same cause: **an audit entry was trusted over the code.**

**The revision-response screen (Phase 1).** The audit said the prototype had no way to read an advertiser's rejection reason or re-upload. A complete flow already existed. The duplicate shipped with a dead `파일 선택` button and split routing — the same status reached a working screen from one entry point and a broken one from another. Deleted in `744ffaa`.

**The demand-survey module (Phase 1).** Four screens plus an entry card, built for a feature retired months earlier by a spec committed to this repo. Deleted in `01e4c90`.

Phase 4 would have been the same mistake at triple the size — nine screens for two modules excluded by §10 of that same spec — caught only because Phase 3 began with a reconciliation pass.

**The fix that worked:** from Phase 2 onward, every plan began by checking each spec item against both the code and the decision records. That pass found 4 false gaps in Phase 2, 2 in Phase 3, and 11 in Phase 5 — and cancelled Phase 4 outright. It also produced one false negative of its own: Phase 5's Task 1 was planned against wording from the legacy app (`파기`) rather than the screen's actual copy, so an already-built deletion notice looked missing. The implementer caught it and correctly refused to build a duplicate.

**Standing rule for future work on this prototype:** an audit is a hypothesis, not a specification. Verify against the code and the decision records before planning, and never re-add anything listed as Cancelled without recording a new decision first.

## 5. Decisions taken

**My-campaigns: my-turn panel, not three tabs — ruled 2026-08-20.** The existing product splits this surface into `제작 필요` / `전체` / `미선정·취소`. The prototype answers the same need with a my-turn panel, filter chips, and a separate 지난 캠페인 screen. Both are coherent, but the my-turn panel answers the question a creator actually arrives with — *what do I need to do?* — rather than making them sort completed work from pending. **Keep the panel; the three-tab restructure is closed as won't-do.** The audit's corresponding 🟡 row and P1 backlog entry are void.

No decisions remain open. The three items in §3's deferred table each need a product call before they could be planned, but none of them blocks a creator journey.

## 6. Known defects outside this programme

- **`timelineUNUSED`** (`creator/main.dc.html`) — self-labelled dead code, a multi-line property. Deleting only its first line breaks the logic class, so remove it whole or leave it.
- **`balanceLabel` / `balanceShort`** — duplicated render keys with identical values. Harmless, pre-existing.
- **Root-scoped upload race** — if a second upload starts before a previous screen's leftover timer fires, both write the same shared fields. Not reachable in normal use.
- **Incomplete `channels` seed crash** — seeding a channel without `platform`/`handle` crashes react-dom. Pre-existing.

The `draftBio` key collision, which made an AI-rewrite handler unreachable, was fixed in `3362ae4`.

## 7. Where the prototype stands

Every creator journey the existing product supports can now be walked end to end in `creator/main.dc.html`: sign up, recover an account, connect any channel type including Naver, discover and apply to a campaign, receive and answer proposals, submit content with real upload states, respond to a revision request, and follow the money through to a payout — with a confirmation in front of every destructive action and a consistent set of loading, empty and error states behind all of it.

What remains is the three deferred items above. None of them blocks a creator from completing anything.
