Northwind 커머스 옵트인 + netscript CLI로 스캐폴딩된 비공개 Assistant/MCP 쇼케이스
README 링크에서 발견 · today
commerce, saga, webhooks, private를 조합한 쇼케이스 아키타입을 추가했습니다.
What they did
작성자는 netscript CLI에 옵트인 쇼케이스를 추가했다: `netscript init northwind --from showcase`, 그리고 문서화된 `showcase:setup` 레시피도 함께. 쇼케이스는 기존 Utility 페이지와 플러그인 배선을 조합해 동작하는 커머스 앱으로 만든다 — 주문, 고객, 상품, 라인 아이템에 타입이 지정된 oRPC 읽기, Prisma 영속성, 현실적인 날짜 기반 시드 데이터까지. 그 위에 내구성 있는 워커 진행 상황과 주문 상세 페이지에 표시되는 order → payment → shipping 사가 상태, 실제 웹훅 인그레스, 스트림 연동 활동을 연결했다. 또한 유한한 캐치업, 정확한 오프셋 재개, 소유권 검사, 네이티브 트랜스크립트 재생을 갖춘 인증된 프라이빗 채팅/MCP 표면과, 키 없는 프로바이더 설정 및 표준 로그인 표면도 구축했다. 작업은 S0 리서치/설계부터 S3 구성된 게이트, 런타임 CI, 경계가 정해진 부채 문서화, 형식적 리프 평가까지 분할되었다. 결정적으로, 일반 init은 바이트 단위로 동일하게 유지되었다: 에이전트 번들을 포함한 220개의 기본 파일 전부가 현재 main과 일치한다. 검증은 16개의 루트 체크 태스크, 구조화된 타입 체크, 아키텍처/품질 게이트, CLI 린트/포맷 래칫, export 문서 린트, 퍼블리시 드라이런을 포함했다; 새 scaffold.showcase 실행은 여섯 개의 로컬 게이트를 모두 통과했다; 96개의 집중 테스트, 21개의 소스/스텁 시나리오, 마운트된 채팅 브라우저 회귀 테스트가 통과했다; 읽기 전용 시각 서브게이트는 60개의 뷰/테마/너비 조합 전부를 ≥8/10으로 평가했다; 그리고 런타임 CI는 Postgres(124/124), SQLite(116/116), 쇼케이스(8/8)에서 통과했다. 첫 번째 비드래프트 품질 실행은 release:preflight에서 실패했는데, 따옴표로 묶인 문자열 안의 생성된 스캐폴드 소스가 실행 가능한 패키지 파일 IO로 오분류되었기 때문이다; 수리는 업스트림 Babel 토큰 범위를 사용하고 파싱 실패 시 보수적 스캐닝을 적용했으며, 허용 목록이나 생성 파일 예외는 추가하지 않았다.
How it went
쇼케이스는 릴리스 범위 0.0.9로 출시되었으며, 수리된 슬라이스에 대해 공식적인 독립 IMPL-EVAL PASS와 리뷰어 승인을 받았습니다. 기본 init 격리는 220/220 동일 파일로 입증되었고, 런타임 CI는 Postgres, SQLite 및 쇼케이스 레인 전반에서 통과했으며, 시각적 승인은 모든 조합을 통과했습니다. 수용된 부채는 각각 쇼케이스 자식 하나씩 증가하는 두 개의 초과 상위 항목에 대해 기록되었으며, 소유자, 비용 및 종료 게이트가 포함되었습니다.
Worth knowing
프라이빗 채팅은 현재 POSIX 시크릿 파일 권한과 로컬 소유권 KV를 가진 단일 앱 호스트를 요구하며, 대화 메타데이터 목록 조회는 O(n)이므로 더 큰 배포에는 공유 소유권과 인덱스 페이지네이션이 필요합니다. 실제 OAuth/OIDC와 모델 자격 증명은 외부 전제 조건입니다 — CI는 스텁 제공자를 사용하며 외부 제공자 브라우저 인수 테스트는 수행되지 않았습니다. 텔레메트리는 현재의 사용 불가 상태를 렌더링합니다. 최종 repair-head 불변 원격 CI는 작성 시점에 여전히 진행 중이었고, 데스크톱 예외 경계 #859는 수정이 아닌 강제 적용되었습니다.
Wiring
CLI는 init에서 `--from showcase` 소스를 얻어 기본 템플릿 세트 대신 showcase 아키타입을 가져오며, 이와 함께 문서화된 `showcase:setup` 레시피도 제공한다. showcase는 프레임워크 런타임을 대체하는 대신 기존 Utility 페이지와 플러그인 연결을 구성한다. Prisma가 영속성을 제공하고, 타입이 지정된 oRPC 프로시저가 읽기를 노출하며, 주문 상세 뷰는 durable worker 진행 상황이 공급하는 saga 상태를 바인딩한다. Webhook 인그레스는 activity 뷰가 읽는 동일한 스트림에 기록하므로, 커밋된 스트림 활동과 saga 타임스탬프가 함께 렌더링된다. 비공개 Assistant/MCP 경로는 소유권 검사와 함께 인증 뒤에 위치하며, 자격 증명에는 로컬 소유권 KV와 POSIX 시크릿 파일 권한을 사용하고, 네이티브 트랜스크립트 재생을 통한 유한 캐치업과 정확한 오프셋 재개를 지원한다. CI는 스텁 provider와 함께 Postgres 및 SQLite에 대해 showcase 레인을 실행하며, 별도의 읽기 전용 시각적 서브게이트가 1440 및 390px에서 라이트/다크 전반에 걸쳐 15개 뷰를 렌더링한다. 릴리스 프리플라이트는 업스트림 Babel 토큰 범위를 사용하여 생성된 스캐폴드 소스를 스캔하며, 파싱에 실패하면 보수적 스캐닝으로 폴백한다.
Try it yourself
# Showcase Archetype Implementation Plan
## 1. CLI Entry Point: `netscript init <name> --from showcase`
Add an opt-in flag to the existing `init` command. Default behavior (no `--from`) must remain untouched.
```ts
// packages/cli/src/commands/init.ts
export async function init(name: string, opts: { from?: string }) {
if (opts.from === 'showcase') {
return scaffoldShowcase(name);
}
return scaffoldDefault(name); // unchanged
}
```
Document a `showcase:setup` recipe in `docs/recipes/showcase.md` covering:
- Prerequisites (Node, pnpm, Postgres for Prisma)
- `netscript init my-app --from showcase`
- `pnpm showcase:setup` (migrations, seed, dev server)
- Sign-in flow and MCP/chat entry points
## 2. Commerce App Composition
Reuse existing Utility pages and plugin wiring. New domain modules:
- `orders`, `customers`, `products`, `line_items` — Prisma models with realistic dated seed data (spread across the last 90 days, deterministic).
- Typed oRPC reads: `orders.list`, `orders.byId`, `customers.list`, `products.list` with shared Zod schemas.
- Prisma persistence layer with a thin repository per aggregate.
## 3. Durable Worker Progress + Saga
- Worker writes progress rows (`worker_progress`) keyed by `(job_id, step)` — idempotent upserts.
- Order detail page renders saga state: `order → payment → shipping`, each with `pending | active | done | failed` and timestamps.
- Real webhook ingress at `/api/webhooks/:provider` with signature verification and idempotency keys.
- Activity feed stream-linked to the order via SSE, replaying from the last seen offset.
## 4. Authenticated Private Chat / MCP
- Session-scoped chat with ownership checks on every read/write.
- Finite catch-up: client requests `since=<offset>`, server returns bounded batch + `next_offset`.
- Exact-offset resume: no gaps, no duplicates; offsets are monotonic per conversation.
- Native transcript replay: server can replay full transcript for a conversation the caller owns.
- No-key provider setup: local echo/stub provider so the app runs without API keys.
- Canonical sign-in: single auth entry point reused by chat and MCP.
## 5. Byte-Identical Default Init Proof
- Snapshot the default scaffold output (all 220 files, including the agent bundle) into `test/fixtures/default-init/`.
- Test compares byte-for-byte with **no exclusions, no normalization** (no line-ending or whitespace normalization).
- Any drift fails CI with a diff.
## 6. Gate Run
Execute in order:
1. Root check tasks
2. Type check
3. Architecture/quality gate
4. Lint/format ratchet
5. Export doc-lint
6. Publish dry-run
7. Fresh `scaffold.showcase` through all local gates
## 7. Focused Tests + Negative Controls
- Unit tests for saga transitions, offset resume, ownership checks.
- Stub scenarios for webhook ingress and worker progress.
- Mounted chat browser regression (Playwright) covering catch-up + replay.
- Negative controls:
- **Missing shipping persistence** → saga must fail loudly, not silently pass.
- **Empty-conversation deadlock** → catch-up on empty conversation returns immediately with `next_offset=0`.
- **Cold evidence-directory failure** → missing evidence dir surfaces a clear error, not a hang.
## 8. Cardinality Debt Register
Record in `docs/debt/cardinality.md`:
| Item | Owner | Cost | Stop condition | Closure gate |
|------|-------|------|----------------|--------------|
| Per-order activity fan-out | @backend | O(n) reads per order | >100 events/order | Paginated activity API |
| Chat offset storage | @platform | 1 row per conversation | >10k conversations | Move to append-only log |
| Webhook idempotency table growth | @backend | Unbounded | >1M rows | TTL + archival job |
Each entry requires owner, cost estimate, stop condition, and closure gate before merge.