diff --git a/docs/superpowers/plans/2026-06-16-geo-agent-article-optimizer-mvp.md b/docs/superpowers/plans/2026-06-16-geo-agent-article-optimizer-mvp.md new file mode 100644 index 0000000..5ff8ab7 --- /dev/null +++ b/docs/superpowers/plans/2026-06-16-geo-agent-article-optimizer-mvp.md @@ -0,0 +1,655 @@ +# 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`, npm `10.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`, preferably `OPENAI_API_KEY`. +- Optional `pnpm`, `yarn`, `bun`, `pandoc`, and LibreOffice are not needed for this MVP. + +## Dependency Set + +Runtime dependencies: + +```bash +npm install next react react-dom better-sqlite3 zod openai docx nanoid +``` + +Development dependencies: + +```bash +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: + +```bash +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: + +```text +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: + + ```json + { + "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: + + ```bash + 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 playwright + ``` + + Expected: `package-lock.json` is created and `npm ls --depth=0` shows the listed packages. + +- [ ] **Step 3: Add environment and ignore rules** + + `.env.example`: + + ```text + OPENAI_API_KEY= + OPENAI_MODEL=gpt-4.1-mini + APP_DATA_DIR=./data + ``` + + `.gitignore` must include: + + ```text + node_modules/ + .next/ + .env + .env.* + !.env.example + data/app.db + data/exports/ + ``` + +- [ ] **Step 4: Add initial Next.js app shell** + + `src/app/layout.tsx`: + + ```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 ( + +
{children} + + ); + } + ``` + + `src/app/page.tsx` initially renders a heading and four empty sections: article input, fact card, optimized result, and quality report. + +- [ ] **Step 5: Verify scaffold** + + Run: + + ```bash + npm run build + npm test + ``` + + Expected: build succeeds. Test command may report no test files until Task 2 adds tests. + +- [ ] **Step 6: Commit scaffold** + + ```bash + 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_items` is not ready for optimization. + - Confirmed fact card with empty company full name is invalid. + - QA report accepts only `pass`, `warn`, or `fail`. + +- [ ] **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: + + ```bash + npm test -- src/lib/domain/__tests__/validation.test.ts + ``` + + Expected: all validation tests pass. + +- [ ] **Step 5: Commit** + + ```bash + 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_templates` + - `article_jobs` + - `fact_cards` + - `optimized_articles` + - `qa_reports` + + Store structured arrays and nested objects as JSON text. Add `created_at` and `updated_at` timestamps where relevant. + +- [ ] **Step 3: Implement repository functions** + + Required functions: + + - `createBrandTemplate` + - `listBrandTemplates` + - `getBrandTemplate` + - `createArticleJob` + - `getArticleJob` + - `saveFactCard` + - `getFactCard` + - `saveOptimizedArticle` + - `getLatestOptimizedArticle` + - `saveQaReport` + - `getLatestQaReport` + +- [ ] **Step 4: Verify** + + ```bash + npm test -- src/lib/db/__tests__/repositories.test.ts + ``` + +- [ ] **Step 5: Commit** + + ```bash + 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.ts` exports: + + - `generateJson