塑造个人品牌,发现细分市场,构建可持续盈利的产品
개인 브랜드 구축·세분화 시장 발굴·지속 가능한 수익 제품 만들기를 공유
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
An AI-assisted workflow for turning incomplete commercial intent (briefs, meeting notes, requirements) into a structured proposal that is ready for human review in Proposales. Built as a Next.js App Router application on the Proposales API.README 전문 보기 ↗An AI-assisted workflow for turning incomplete commercial intent (briefs, meeting notes, requirements) into a structured proposal that is ready for human review in Proposales. Built as a Next.js App Router application on the Proposales API.
Integrated and working end to end, with no persistence. A brief typed in the browser reaches the AI agent through a Server Action; the agent asks clarifying questions or returns a structured proposition; a human edits it inline, asks for revisions, and approves; the approved payload is executed deterministically as a Proposales draft, whose applied pricing is read back and shown beside the editor link.
The root route renders the two-pane Proposal Preparation workspace: named landmarks, a keyboard- and pointer-operable divider, and a keyboard-accessible, reorderable, closable session tab strip. Sessions are independent and live for the browser page lifetime — a reload destroys them, deliberately and visibly.
Nothing is stored anywhere: no database, no client-side persistence, no session restore. A workflow lives for as long as its browser page does, and the proposal's life after creation belongs to Proposales.
Every step below is implemented, wired together, and tested — from the browser through to the created Proposales draft.
Human intent (brief, notes, requirements)
→ AI reasons and gathers information
→ AI prepares a structured proposal
→ human reviews and corrects
→ human approves
→ deterministic Proposales mutation with the exact approved payload
→ human finishes editing and sends in Proposales
The human reviews and sends from Proposales; this application never sends a proposal, and the Proposales adapter exposes no operation that could.
The principle: AI prepares, the human decides. Consequential mutations stay human-controlled, the approved payload is executed without model reinterpretation, and Proposales remains the final editing and sending environment. The full rules are in 08-agent-architecture.md.
Client code owns interaction. Server code owns authority. Shared code owns contracts.
One repository, one Vercel deployment, two runtimes. Secrets, external calls, agent execution, and mutations stay on the server. Everything else about how the system must be built lives in architectural_contracts/. Start with 01-implementation-contract-guide.md, which routes a task to the contracts that govern it; the contracts README records precedence, scaffold decisions, and resolved decisions.
Verified against package.json.
| Concern | Choice |
|---|---|
| Framework | Next.js 16, App Router, React 19 |
| Language | TypeScript, strict |
| AI layer | Vercel AI SDK (ai) with Anthropic/OpenAI provider boundary in src/lib/ai/ |
| Runtime validation | Zod 4 |
| Unit and component tests | Vitest 5 with React Testing Library and jest-dom; node project for server tests, jsdom project for app/component tests |
| End-to-end tests | Playwright, Chromium |
| Headless interaction primitives | Radix Tabs 1.1.21 (with Roving Focus 1.1.19), Radix Popover 1.1.23 |
| Icons | Lucide React 1.41.0; session controls use native text glyphs where sufficient |
| Lint | ESLint 9 with eslint-config-next |
| Hosting | Vercel |
npm install
npx playwright install chromium # once, for end-to-end tests
All variables are read by server code only. Nothing is exposed to the browser.
| Variable | Purpose | Required | Kind | Safe example |
|---|---|---|---|---|
PROPOSALES_API_KEY | Bearer token for the Proposales API | yes | server-only secret | test-placeholder-not-a-key |
PROPOSALES_COMPANY_ID | The single Proposales company this deployment operates on | yes | server-only configuration | 1 |
PROPOSALES_EDITOR_ORIGIN | Exact HTTPS origin for human-facing proposal editor URLs | yes | server-only configuration | https://proposales.example |
AI_PROVIDER | Provider selected for AI generation | yes | server-only configuration | anthropic |
AI_MODEL | Provider-specific model identifier | yes | server-only configuration | test-placeholder-model |
ANTHROPIC_API_KEY | Anthropic credential when Anthropic is selected | conditional | server-only secret | test-placeholder-not-a-key |
OPENAI_API_KEY | OpenAI credential when OpenAI is selected | conditional | server-only secret | test-placeholder-not-a-key |
COPILOT_LIVE_MUTATIONS | Whether this deployment may create real Proposales drafts | yes | server-only configuration | disabled |
Copy .env.example to .env and fill in the values. .env is ignored by git.
COPILOT_LIVE_MUTATIONS has no default, because whether a deployment may write to Proposales is a decision each deployment states rather than inherits. It gates draft creation only: with disabled, approval returns "Draft creation is disabled on this deployment." and everything before it — preparation, clarification, review, editing, revision — still works.
.env.example is committed and is the inventory of configuration: every variable the application reads, every value empty, one comment per variable. Adding a variable means adding it there, to the validation schema in src/lib/env/ once it exists, and to the Vercel project, in the same change. Real values live only in .env or .env.local, which are never committed. Nothing sensitive is ever named NEXT_PUBLIC_*, because that prefix inlines the value into the browser bundle. Rule and rationale: 02-runtime-boundaries.md §8.
Run from the repository root.
npm run dev # local development server on http://localhost:3000
npm run build # production build
npm start # serve the production build
npm run typecheck # tsc --noEmit
npm run lint # eslint .
npm test # vitest run (unit and component tests, fully offline)
npm run test:watch # vitest in watch mode
npm run test:e2e # playwright test
npm run test:live # opt-in live suites; a no-op unless LIVE_SMOKE=1
npm test never touches the network: its setup installs an offline fetch guard and seeds placeholder configuration. The live suites are separate, excluded from the default projects, and skipped unless LIVE_SMOKE=1 is set:
LIVE_SMOKE=1 npm run test:live
They read real credentials from .env. One of them creates a real Proposales draft, titled [DISPOSABLE COPILOT SMOKE] <timestamp>, and prints its uuid so it can be deleted by hand; it also prints the observed editor-URL origin, which is how PROPOSALES_EDITOR_ORIGIN should be set. The other runs the real AI provider against a fixture catalog with Proposales faked, and writes nothing anywhere.
The same switch adds the live browser flow, which drives the whole critical path against the real backend and creates one more real draft, titled [DISPOSABLE COPILOT E2E] <timestamp> and printed for deletion. It needs COPILOT_LIVE_MUTATIONS=enabled:
LIVE_SMOKE=1 npm run test:e2e
None of the live suites run in CI, because two of them write.
CI (.github/workflows/ci.yml) runs typecheck, lint, unit tests, end-to-end tests, and the production build on every push and pull request.
*.test.ts(x) under src/ or test/ is claimed by exactly one project: the jsdom project claims every .tsx test and every .ts test under a feature's hooks/; the node project claims everything else (src/lib/**, src/styles/**, src/app/**, src/features/** outside hooks/, test/**). Vitest excludes e2e/ and *.live.test.ts so the default projects never overlap with end-to-end or opt-in live tests.src/features/proposal-preparation/workflow-ui.test.tsx) is where the integration is proven: it drives the real components through the real transport, the real Server Action functions and the real services, replacing only the services' collaborators. CI runs it like any other test, with no secrets and no network.e2e/, in two projects. The chromium project is what CI runs: the config injects placeholder configuration so next dev starts without secrets, and the specs it collects never need a backend result — workspace.spec.ts (landmarks, skip link, divider, narrow-width containment, idle state, visual foundation), session-tabs.spec.ts (tab geometry, focus, hit targets, elision, URL stability) and proposal-flow.spec.ts (close guard, reload losing the workspace, and one row that sends an over-long brief through the real Server Action and renders the returned error). The chromium-live project is collected only under LIVE_SMOKE=1 and holds proposal-flow.live.spec.ts, the full critical flow against the real backend.Claude Code and Codex are routed through a shared Architecture Context policy before any material planning, implementation, review, debugging, or refactoring decision. The policy makes the agent classify the task, read the implementation contract guide, and load only the applicable contracts. Reading a contract never implies introducing the capability it governs.
| Layer | Path |
|---|---|
| Behavior (authoritative) | agent-skills/policy/architecture-context-policy.md |
| Claude adapter | .claude/skills/architecture-context/SKILL.md |
| Codex adapter | .codex/skills/architecture-context/SKILL.md |
| Auto-loaded bootstrap | CLAUDE.md, AGENTS.md |
How the layers relate and how to add a skill: agent-skills/README.md.
First-party Proposales documentation and the OpenAPI spec are vendored under api-documentation/proposales/ and refreshed with:
./scripts/update-proposales-api-docs.sh
A refresh detects possible contract drift; a dependency-aware review of the diff decides whether the application must change. Only vendor changes that touch behavior the application relies on (adapter assumptions, schemas, tests, known quirks) require action. The rule is in that folder's README. How this application uses the API is documented in src/lib/proposales/README.md.
.
├── src/app/ # Next.js routes: root layout and Proposal Preparation workspace route
├── src/features/ # Feature code; today: proposal-preparation
├── src/lib/ # Integrations and shared primitives: proposales, ai, agent, env, errors, values
├── src/styles/ # Tailwind theme layer (visual values, defined once) and global base styles
├── e2e/ # Playwright specs
├── architectural_contracts/ # Normative engineering contracts (numbered in read order)
├── agent-skills/ # Shared agent policies
├── .claude/skills/, .codex/ # Platform adapters for those policies
├── api-documentation/proposales # Vendored Proposales reference (never hand-edited)
├── scripts/ # Repository maintenance scripts
├── .github/workflows/ci.yml # CI pipeline
└── .env.example # Configuration inventory
Feature code lives under src/features/<feature>/ and integrations under src/lib/<system>/ per 03-feature-architecture.md. Today that is one feature, proposal-preparation, over four server-side integrations: proposales, ai, agent, and env. Within the feature, server/ holds the workflow and server/actions.ts the six Server Actions that expose it; the two transports in client/ are the only browser modules that call them. client/ also owns the workspace shell, the page-lifetime session runtime and tab strip, and the presentation layer, whose client/view-models/ adapt the server's own schema types for the components. client/fixtures/ is test data only, and retirement.test.ts keeps it off every shipping path.
The application deploys to Vercel. Environment variables are configured in the Vercel project, never in the repository — all eight of them, including COPILOT_LIVE_MUTATIONS. A missing variable fails at the first action with the variable's name and never its value.
src/app/page.tsx sets maxDuration = 300, which the Server Actions invoked from that page inherit. An agent run has a 240-second wall-time budget and a 120-second per-call ceiling, leaving bounded headroom for catalog reads and response handling; approval is a search, a create and a read-back. This requires Fluid compute, which caps Hobby functions at 300 seconds. There is no streaming and no progress reporting: a turn shows one honest label for as long as it takes.
Deployment posture is a deliberate choice, because Vercel Authentication on Hobby protects preview and deployment URLs but not the production domain. Two configurations are compliant: a protected preview URL with COPILOT_LIVE_MUTATIONS=enabled, or a public production URL with COPILOT_LIVE_MUTATIONS=disabled, where reviewers see everything up to approval and creation is refused with a clear message. The code is identical under both; only the environment differs.
Established:
server/actions.ts, a client transport composing each turn envelope and a second one reading line-item images, expected failures crossing as error DTOs rather than thrown errors, and the COPILOT_LIVE_MUTATIONS switch gating draft creation.Decided and deliberately absent:
Decided for the frontend:
src/styles/theme.css (15-ui-styling-and-component-system.md).useState and useReducer (05-client-architecture.md §5.1).Deliberately absent from the workflow itself: the application never sends a proposal, never writes a price, and never lets a model touch an approved payload. Those are enforced in code and pinned by tests, not conventions; the rules and where each is enforced are in the feature README.
Known limitations of the working system, rather than missing pieces: a replaced line item moves to the end of the list, which is backend semantics; a typical turn takes roughly 15–60 seconds behind one static label, with no progress reporting (the bounded worst-case agent allowance is 240 seconds); a reload loses the workspace; and there is no human-driven content search UI.