18 KiB
GEO Agent Article Optimizer MVP 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: Build the local MVP described in docs/superpowers/specs/2026-06-16-geo-agent-article-optimizer-design.md: paste an article, confirm facts, optimize under constraints, run QA gates, and export Markdown, Word, and JSON.
Architecture: Use a single Next.js application with server-side route handlers for workflow execution and SQLite persistence. Keep each workflow node as a focused TypeScript module so fact extraction, optimization, QA, rewriting, and exporting can be tested independently.
Tech Stack: Node.js 22, npm, Next.js, React, TypeScript, Tailwind CSS, better-sqlite3, zod, OpenAI-compatible SDK, docx, Vitest, Playwright.
Environment Summary
The current device is suitable for development:
- macOS 26.3 on Apple M4.
- 16 GB memory, 10 CPU cores.
- Node.js
v22.22.3, npm10.9.8. - SQLite CLI
3.51.0. - Git, curl, jq, and Xcode command line tools are available.
Missing but required or recommended:
- Required project npm dependencies listed below.
- One LLM credential in
.env.local, preferablyOPENAI_API_KEY. - Optional
pnpm,yarn,bun,pandoc, and LibreOffice are not needed for this MVP.
Dependency Set
Runtime dependencies:
npm install next react react-dom better-sqlite3 zod openai docx nanoid
Development dependencies:
npm install -D typescript @types/node @types/react @types/react-dom @types/better-sqlite3 eslint eslint-config-next prettier vitest @vitejs/plugin-react jsdom playwright
Environment file:
cat > .env.local <<'EOF'
OPENAI_API_KEY=replace-with-real-key
OPENAI_MODEL=gpt-4.1-mini
APP_DATA_DIR=./data
EOF
The implementation must never commit .env.local, data/app.db, or generated export files.
Planned File Structure
Create or modify these files:
package.json
tsconfig.json
next.config.ts
eslint.config.mjs
postcss.config.mjs
tailwind.config.ts
vitest.config.ts
.gitignore
.env.example
data/.gitkeep
samples/articles/*.json
src/app/globals.css
src/app/layout.tsx
src/app/page.tsx
src/app/api/jobs/route.ts
src/app/api/jobs/[jobId]/confirm-fact-card/route.ts
src/app/api/jobs/[jobId]/optimize/route.ts
src/app/api/jobs/[jobId]/exports/[fileName]/route.ts
src/components/article-input-form.tsx
src/components/fact-card-editor.tsx
src/components/optimized-preview.tsx
src/components/qa-report-panel.tsx
src/lib/db/connection.ts
src/lib/db/schema.ts
src/lib/db/repositories.ts
src/lib/domain/types.ts
src/lib/domain/validation.ts
src/lib/llm/client.ts
src/lib/llm/prompts.ts
src/lib/workflow/input-normalizer.ts
src/lib/workflow/fact-extractor.ts
src/lib/workflow/article-optimizer.ts
src/lib/workflow/quality-inspector.ts
src/lib/workflow/targeted-rewriter.ts
src/lib/workflow/exporter.ts
src/lib/workflow/orchestrator.ts
src/lib/workflow/__tests__/*.test.ts
Responsibilities:
src/app/page.tsx: single-screen local workflow UI.src/app/api/**: server endpoints for create, confirm, optimize, and download actions.src/components/**: focused UI components for the four page areas in the spec.src/lib/domain/**: shared TypeScript types and Zod schemas.src/lib/db/**: SQLite connection, schema initialization, and repository functions.src/lib/llm/**: model client and prompts. All model calls are isolated here.src/lib/workflow/**: one module per internal agent node from the spec.samples/articles/**: five required risk samples for testing.
Task 1: Scaffold The Application
Files:
-
Create:
package.json -
Create:
tsconfig.json -
Create:
next.config.ts -
Create:
eslint.config.mjs -
Create:
postcss.config.mjs -
Create:
tailwind.config.ts -
Create:
vitest.config.ts -
Modify:
.gitignore -
Create:
.env.example -
Create:
src/app/layout.tsx -
Create:
src/app/globals.css -
Create:
src/app/page.tsx -
Create:
data/.gitkeep -
Step 1: Initialize npm metadata
Use
npm init -y, then set scripts and package metadata:{ "name": "geo-agent-article-optimizer", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "test": "vitest run", "test:watch": "vitest" } } -
Step 2: Install dependencies
Run:
npm install next react react-dom better-sqlite3 zod openai docx nanoid npm install -D typescript @types/node @types/react @types/react-dom @types/better-sqlite3 eslint eslint-config-next prettier vitest @vitejs/plugin-react jsdom playwrightExpected:
package-lock.jsonis created andnpm ls --depth=0shows the listed packages. -
Step 3: Add environment and ignore rules
.env.example:OPENAI_API_KEY= OPENAI_MODEL=gpt-4.1-mini APP_DATA_DIR=./data.gitignoremust include:node_modules/ .next/ .env .env.* !.env.example data/app.db data/exports/ -
Step 4: Add initial Next.js app shell
src/app/layout.tsx:import "./globals.css"; export const metadata = { title: "GEO Agent Article Optimizer", description: "Local article optimization and QA workflow", }; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="zh-CN"> <body>{children}</body> </html> ); }src/app/page.tsxinitially renders a heading and four empty sections: article input, fact card, optimized result, and quality report. -
Step 5: Verify scaffold
Run:
npm run build npm testExpected: build succeeds. Test command may report no test files until Task 2 adds tests.
-
Step 6: Commit scaffold
git add package.json package-lock.json tsconfig.json next.config.ts eslint.config.mjs postcss.config.mjs tailwind.config.ts vitest.config.ts .gitignore .env.example data/.gitkeep src/app git commit -m "chore: scaffold local optimizer app"
Task 2: Define Domain Types And Validation
Files:
-
Create:
src/lib/domain/types.ts -
Create:
src/lib/domain/validation.ts -
Test:
src/lib/domain/__tests__/validation.test.ts -
Step 1: Write validation tests
Cover:
- Valid article input accepts title, body, image descriptions or links, platform, and user instructions.
- Fact card with unresolved
uncertain_itemsis not ready for optimization. - Confirmed fact card with empty company full name is invalid.
- QA report accepts only
pass,warn, orfail.
-
Step 2: Implement shared enums and interfaces
Include:
PublishPlatform:official_site,media_article,comparison_review,recommendation_list.CheckStatus:pass,warn,fail.QualityRuleId: the 10 rule IDs from the spec.ArticleInput,ImageInput,CandidateFactCard,ConfirmedFactCard,OptimizedArticle,QaReport,QaCheck.
-
Step 3: Implement Zod schemas
Add schemas matching the interfaces. Use
.min(1)for required user text fields and.array(...).default([])for list fields. -
Step 4: Verify
Run:
npm test -- src/lib/domain/__tests__/validation.test.tsExpected: all validation tests pass.
-
Step 5: Commit
git add src/lib/domain git commit -m "feat: define optimizer domain model"
Task 3: Add SQLite Persistence
Files:
-
Create:
src/lib/db/connection.ts -
Create:
src/lib/db/schema.ts -
Create:
src/lib/db/repositories.ts -
Test:
src/lib/db/__tests__/repositories.test.ts -
Step 1: Write repository tests
Use a temporary SQLite database path. Test:
- Schema initialization creates all tables.
- A brand template can be inserted and fetched.
- An article job can be inserted and fetched.
- A confirmed fact card can be saved for a job.
- Optimized article revisions increment correctly.
- QA report can be saved and fetched by job/revision.
-
Step 2: Implement schema
Tables:
brand_templatesarticle_jobsfact_cardsoptimized_articlesqa_reports
Store structured arrays and nested objects as JSON text. Add
created_atandupdated_attimestamps where relevant. -
Step 3: Implement repository functions
Required functions:
createBrandTemplatelistBrandTemplatesgetBrandTemplatecreateArticleJobgetArticleJobsaveFactCardgetFactCardsaveOptimizedArticlegetLatestOptimizedArticlesaveQaReportgetLatestQaReport
-
Step 4: Verify
npm test -- src/lib/db/__tests__/repositories.test.ts -
Step 5: Commit
git add src/lib/db git commit -m "feat: add sqlite persistence"
Task 4: Implement Workflow Nodes With Deterministic Fallbacks
Files:
-
Create:
src/lib/llm/client.ts -
Create:
src/lib/llm/prompts.ts -
Create:
src/lib/workflow/input-normalizer.ts -
Create:
src/lib/workflow/fact-extractor.ts -
Create:
src/lib/workflow/article-optimizer.ts -
Create:
src/lib/workflow/quality-inspector.ts -
Create:
src/lib/workflow/targeted-rewriter.ts -
Create:
src/lib/workflow/orchestrator.ts -
Test:
src/lib/workflow/__tests__/*.test.ts -
Step 1: Write node tests before implementation
Tests must cover:
- InputNormalizer trims whitespace and converts image lines into image inputs.
- FactExtractor places missing or conflicting company facts into
uncertain_items. - ArticleOptimizer refuses to add claims outside the confirmed fact card.
- QualityInspector returns the 10 required checks.
- Hard failures are produced for incomplete company names, hallucinated numeric claims, industry drift, and conflicting experience years.
- TargetedRewriter edits only the failing target area.
- Orchestrator stops after two failed rewrite rounds.
-
Step 2: Add LLM abstraction
src/lib/llm/client.tsexports:generateJson<T>(input)for structured JSON responses.generateText(input)for prose responses.isLlmConfigured()for UI/API warnings.
If no API key exists, workflow modules use deterministic local fallbacks so tests and the UI remain usable.
-
Step 3: Implement workflow nodes
Implement the modules from the spec exactly:
normalizeInputextractCandidateFactCardoptimizeArticleinspectQualityrewriteFailedSectionsrunOptimizationWorkflow
Each node accepts typed input and returns typed output. No node reads from the database directly.
-
Step 4: Verify
npm test -- src/lib/workflow -
Step 5: Commit
git add src/lib/llm src/lib/workflow git commit -m "feat: implement article optimization workflow"
Task 5: Add API Routes
Files:
-
Create:
src/app/api/jobs/route.ts -
Create:
src/app/api/jobs/[jobId]/confirm-fact-card/route.ts -
Create:
src/app/api/jobs/[jobId]/optimize/route.ts -
Create:
src/app/api/jobs/[jobId]/exports/[fileName]/route.ts -
Test:
src/app/api/__tests__/jobs.test.ts -
Step 1: Write route tests
Test:
POST /api/jobsvalidates input, creates a job, and returns a candidate fact card.POST /api/jobs/:jobId/confirm-fact-cardrejects unresolved uncertain items.POST /api/jobs/:jobId/optimizerejects jobs without confirmed fact cards.- Successful optimize returns optimized article and QA report.
- Export route rejects unknown filenames.
-
Step 2: Implement routes
Route behavior:
- Create job: normalize input, extract candidate fact card, persist job.
- Confirm fact card: validate user-confirmed facts, save brand template, save fact card.
- Optimize: run orchestrator, save optimized revision, save QA report.
- Export download: return existing generated file with correct content type.
-
Step 3: Verify
npm test -- src/app/api npm run build -
Step 4: Commit
git add src/app/api git commit -m "feat: expose optimizer workflow api"
Task 6: Build The Local Web UI
Files:
-
Modify:
src/app/page.tsx -
Create:
src/components/article-input-form.tsx -
Create:
src/components/fact-card-editor.tsx -
Create:
src/components/optimized-preview.tsx -
Create:
src/components/qa-report-panel.tsx -
Modify:
src/app/globals.css -
Step 1: Build Article Input form
Include fields:
- Title.
- Body.
- Image description or image link, one per line.
- Target platform.
- User instructions.
Submit calls
POST /api/jobs. -
Step 2: Build Fact Card editor
Render all fact-card fields from the spec. Disable optimization while
uncertain_itemsis non-empty. Save callsPOST /api/jobs/:jobId/confirm-fact-card. -
Step 3: Build Optimize action and preview
Optimize button calls
POST /api/jobs/:jobId/optimize. Preview displays title, summary, body markdown, image suggestions, changed sections, and content requiring user confirmation. -
Step 4: Build QA report panel
Show each gate as pass, warn, or fail with evidence, reason, suggested fix, and target agent. Hard failures must visibly block export.
-
Step 5: Build export buttons
Enable downloads for:
optimized.mdoptimized.docxqa_report.json
Disable export when QA has hard failures.
-
Step 6: Verify manually
Run:
npm run devOpen
http://localhost:3000, paste one sample article, confirm the fact card, optimize, review QA, and download files. -
Step 7: Commit
git add src/app src/components git commit -m "feat: build local optimizer interface"
Task 7: Implement Exporter
Files:
-
Create:
src/lib/workflow/exporter.ts -
Test:
src/lib/workflow/__tests__/exporter.test.ts -
Step 1: Write exporter tests
Test:
- Markdown includes optimized title, summary, body, and image suggestions.
- JSON export serializes the QA report.
- Word export creates a
.docxbuffer with nonzero length. - Exporter writes all three files under
data/exports/job_xxx/.
-
Step 2: Implement export functions
Functions:
renderOptimizedMarkdownrenderQaReportJsonrenderOptimizedDocxwriteJobExports
Use the
docxpackage for the Word document. Do not usepandocor LibreOffice. -
Step 3: Integrate exporter with optimize route
After each successful optimization run, write the three export files and persist paths in the job result.
-
Step 4: Verify
npm test -- src/lib/workflow/__tests__/exporter.test.ts npm run build -
Step 5: Commit
git add src/lib/workflow/exporter.ts src/lib/workflow/__tests__/exporter.test.ts src/app/api/jobs git commit -m "feat: export optimized article files"
Task 8: Add Minimum Test Samples And End-To-End Checks
Files:
-
Create:
samples/articles/industry-drift.json -
Create:
samples/articles/company-name.json -
Create:
samples/articles/title-quality.json -
Create:
samples/articles/experience-conflict.json -
Create:
samples/articles/image-text-mismatch.json -
Create:
tests/e2e/mvp.spec.ts -
Step 1: Add five sample articles
Each JSON file includes:
nameinputexpectedHardFailuresexpectedWarnings
-
Step 2: Add Playwright smoke test
Test the happy path:
- Load page.
- Submit article input.
- Edit and confirm fact card.
- Run optimize.
- See QA report.
- Download Markdown, Word, and JSON links are present when hard failures are absent.
-
Step 3: Verify full suite
npm test npm run build npx playwright test -
Step 4: Commit
git add samples tests package.json package-lock.json git commit -m "test: add optimizer mvp samples and smoke test"
Task 9: Final Documentation And Runbook
Files:
-
Create:
README.md -
Create:
docs/superpowers/specs/2026-06-16-geo-agent-article-optimizer-design.mdremains unchanged unless the implementation reveals a spec correction. -
Step 1: Write README
Include:
- Project goal.
- Local setup commands.
- Required
.env.localkeys. - How to run tests.
- How to start the local app.
- Export file location.
- MVP limitations from the spec.
-
Step 2: Run final verification
npm test npm run buildExpected: all tests pass and production build succeeds.
-
Step 3: Commit docs
git add README.md docs/superpowers/specs/2026-06-16-geo-agent-article-optimizer-design.md git commit -m "docs: add local mvp runbook"
Acceptance Mapping
- Paste title, body, image descriptions, and target platform: Task 6.
- Extract fact card and require confirmation: Tasks 2, 4, 5, 6.
- Save and reuse brand template: Task 3 and Task 5.
- Generate optimized article without changing confirmed facts: Task 4.
- Generate structured QA report for 10 gates: Task 4 and Task 6.
- Block export on hard failures: Task 4, Task 6, Task 7.
- Download Markdown and Word document: Task 7.
- Minimum five risk samples: Task 8.
Development Order
Recommended execution order:
- Scaffold app.
- Domain model.
- SQLite.
- Workflow nodes.
- API routes.
- UI.
- Exporter.
- Samples and E2E.
- README and final verification.
This order keeps each task independently testable and avoids building UI against unstable data contracts.
Self-Review
- Spec coverage: all MVP scope items, page areas, workflow nodes, data model, error handling, acceptance criteria, and minimum samples are mapped to tasks.
- Placeholder scan: the plan contains no unresolved
TBD,TODO, or open-ended implementation placeholders. - Type consistency: planned names match the spec and remain stable across tasks.
- Scope check: this is one coherent local MVP. Publishing integrations, permissions, batching, direct
.docxparsing, and complex Word templates remain excluded.