diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md new file mode 100644 index 00000000..7cd9082d --- /dev/null +++ b/.planning/codebase/ARCHITECTURE.md @@ -0,0 +1,149 @@ +# Architecture + +**Analysis Date:** 2026-01-09 + +## Pattern Overview + +**Overall:** Monolithic Full-Stack Single-Page Application + +**Key Characteristics:** +- Client-driven architecture with Zustand state management +- Next.js App Router for both UI and API routes +- Node-based visual workflow editor pattern +- Local-first with optional cloud AI services + +## Layers + +**Presentation Layer (React Components):** +- Purpose: UI rendering, user interaction, state binding +- Contains: Node components, canvas, modals, toolbars +- Location: `src/components/` +- Depends on: Store layer for state +- Used by: Root page component + +**State Management Layer (Zustand):** +- Purpose: Central application state and business logic +- Contains: Workflow state, node/edge CRUD, execution logic +- Location: `src/store/workflowStore.ts`, `src/store/annotationStore.ts` +- Depends on: API layer for external calls +- Used by: All components via `useWorkflowStore()` hook + +**API Layer (Next.js Routes):** +- Purpose: Server-side processing, external API calls +- Contains: Image generation, LLM, file operations +- Location: `src/app/api/` +- Depends on: External services (Gemini, OpenAI) +- Used by: Store layer via fetch calls + +**Type System Layer:** +- Purpose: Single source of truth for TypeScript interfaces +- Contains: Node types, data interfaces, handle types +- Location: `src/types/index.ts`, `src/types/quickstart.ts` +- Depends on: Nothing +- Used by: All layers + +**Utility Layer:** +- Purpose: Reusable business logic +- Contains: Cost calculation, grid splitting, image storage +- Location: `src/utils/` +- Depends on: Node.js built-ins +- Used by: Store and API layers + +## Data Flow + +**Workflow Execution Flow:** + +1. User triggers execution (Cmd/Ctrl+Enter) via `FloatingActionBar` or `WorkflowCanvas` +2. `executeWorkflow()` called from Zustand store +3. Topological sort on node graph (dependency ordering) +4. For each node in order: + - Check if in locked group → skip if locked + - Check for pause edges → pause if found + - `getConnectedInputs(nodeId)` retrieves upstream data + - Execute node-specific logic (API call or transform) +5. `updateNodeData()` updates status (loading → complete/error) +6. `addIncurredCost()` tracks generation costs + +**Node Data Flow via getConnectedInputs():** + +- Image sources: `imageInput.data.image`, `annotation.data.outputImage`, `nanoBanana.data.outputImage` +- Text sources: `prompt.data.prompt`, `llmGenerate.data.outputText` +- Returns: `{ images: string[], text: string | null }` + +**State Management:** +- Client-side: Zustand store with React subscriptions +- File-based: Workflow JSON saved to disk +- LocalStorage: Settings, costs, configs + +## Key Abstractions + +**Node System:** +- Purpose: Encapsulate workflow step types +- Examples: `ImageInputNode`, `NanoBananaNode`, `PromptNode`, `OutputNode` +- Pattern: BaseNode wrapper with type-specific content +- Location: `src/components/nodes/` + +**Edge System:** +- Purpose: Define connections between nodes +- Examples: `EditableEdge` (with controls), `ReferenceEdge` (dashed) +- Pattern: React Flow edge components +- Location: `src/components/edges/` + +**Group System:** +- Purpose: Logical node grouping with lock state +- Pattern: Groups stored in `Record` +- Behavior: Locked groups skip execution + +**Store Actions:** +- Purpose: State mutations and async operations +- Examples: `addNode()`, `updateNodeData()`, `executeWorkflow()` +- Pattern: Zustand actions with `get()` and `set()` + +## Entry Points + +**Main Client Entry:** +- Location: `src/app/page.tsx` +- Triggers: Browser navigation to root URL +- Responsibilities: Initialize app, render WorkflowCanvas + +**Root Layout:** +- Location: `src/app/layout.tsx` +- Triggers: All page renders +- Responsibilities: Metadata, global providers, Toast + +**API Routes:** +- Location: `src/app/api/[route]/route.ts` +- Triggers: Fetch calls from client +- Responsibilities: Server-side processing, external API calls + +## Error Handling + +**Strategy:** Try/catch at boundaries with status updates + +**Patterns:** +- API routes return `{ success, error, data }` JSON +- Node execution updates `status: 'error'` with error message +- Store catches async errors and updates node state +- Logging captures errors for debugging + +## Cross-Cutting Concerns + +**Logging:** +- Client: `src/utils/logger.ts` with session tracking +- Server: `src/utils/logger-server.ts` +- Categories: workflow, node, api, file, validation + +**Validation:** +- Connection validation in `WorkflowCanvas.tsx` (`isValidConnection()`) +- Workflow validation in `workflowStore.ts` (`validateWorkflow()`) +- Quickstart validation in `src/lib/quickstart/validation.ts` + +**Cost Tracking:** +- Calculation: `src/utils/costCalculator.ts` +- Storage: localStorage per workflow +- Display: `CostIndicator` component + +--- + +*Architecture analysis: 2026-01-09* +*Update when major patterns change* diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md new file mode 100644 index 00000000..d5f91403 --- /dev/null +++ b/.planning/codebase/CONCERNS.md @@ -0,0 +1,126 @@ +# Codebase Concerns + +**Analysis Date:** 2026-01-09 + +## Tech Debt + +**Large Monolithic Store File:** +- Issue: `src/store/workflowStore.ts` is 2,027 lines with mixed concerns +- Files: `src/store/workflowStore.ts` +- Why: Rapid development, all logic centralized for convenience +- Impact: Difficult to test, hard to navigate, violates single responsibility +- Fix approach: Split into `workflowActions.ts`, `workflowExecution.ts`, `workflowPersistence.ts` + +**Silent Log Failures:** +- Issue: Fetch calls to `/api/logs` have `.catch()` with only console.error +- Files: `src/store/workflowStore.ts` (lines 1071-1082, 1327-1333, 1345-1351, 1700-1706) +- Why: Non-critical logging shouldn't block execution +- Impact: Silent failures, no user visibility into logging issues +- Fix approach: Add retry logic or toast notifications + +## Known Bugs + +**None Identified:** +- No TODO/FIXME comments indicating known bugs found in codebase scan +- Application appears stable based on code review + +## Security Considerations + +**Shell Command Execution:** +- Risk: `browse-directory/route.ts` executes osascript/PowerShell commands +- Files: `src/app/api/browse-directory/route.ts` (lines 19-21, 74-77) +- Current mitigation: Commands are hardcoded (not user input) +- Recommendations: Validate returned paths with `path.resolve()`, use `execFile` instead of `exec` + +**Unvalidated Base64 Processing:** +- Risk: Large/malformed base64 strings could cause memory issues +- Files: `src/app/api/generate/route.ts` (line 74), `src/app/api/save-generation/route.ts` +- Current mitigation: None - Buffer.from() called on any size input +- Recommendations: Add size validation before processing (e.g., 10MB limit) + +**API Keys in Environment:** +- Risk: Low - standard practice for API keys +- Files: `.env.local` (gitignored), `.env.example` (documented) +- Current mitigation: .gitignore includes .env.local +- Recommendations: Ensure .env.local never committed + +## Performance Bottlenecks + +**Synchronous localStorage Operations:** +- Problem: localStorage.getItem/setItem called synchronously during state updates +- Files: `src/store/workflowStore.ts` (lines 251, 273, 290, 305, 314, 320) +- Measurement: Not measured, but could block on large workflows +- Cause: Simple implementation for persistence +- Improvement path: Consider IndexedDB for large datasets, add debouncing + +**Deep Cloning with JSON:** +- Problem: `JSON.parse(JSON.stringify())` used for cloning +- Files: `src/store/workflowStore.ts` (line 508) +- Measurement: Not measured +- Cause: Simple solution for deep cloning +- Improvement path: Use `structuredClone()` for better performance + +## Fragile Areas + +**Workflow Execution Pipeline:** +- Files: `src/store/workflowStore.ts` (executeWorkflow, lines 815-1356) +- Why fragile: 500+ lines of complex state management with topological sort +- Common failures: Edge cases with pause edges, group locking, error recovery +- Safe modification: Split into smaller functions, add unit tests first +- Test coverage: None - HIGH PRIORITY gap + +**Connection Validation:** +- Files: `src/components/WorkflowCanvas.tsx` (isValidConnection) +- Why fragile: Type matching logic affects entire workflow +- Common failures: Invalid connections accepted or valid connections rejected +- Safe modification: Review handle type definitions in `src/types/index.ts` +- Test coverage: None + +## Scaling Limits + +**Workflow Size:** +- Current capacity: Unknown - no explicit limits +- Limit: Browser memory for large node graphs with many images +- Symptoms at limit: Slow rendering, memory pressure +- Scaling path: External image storage (already implemented), virtualization for node list + +## Dependencies at Risk + +**No Critical Risks Identified:** +- All dependencies appear actively maintained +- React 19, Next.js 16, TypeScript 5.9 are current versions +- @xyflow/react actively maintained + +## Missing Critical Features + +**No Tests for Critical Code:** +- Problem: Workflow execution logic untested +- Files: `src/store/workflowStore.ts`, `src/app/api/**` +- Current workaround: Manual testing only +- Blocks: Safe refactoring, confidence in changes +- Implementation complexity: Medium - need to mock API calls + +## Test Coverage Gaps + +**Workflow Execution:** +- What's not tested: `executeWorkflow()`, `getConnectedInputs()`, node-specific execution +- Risk: Bugs in core functionality not caught until runtime +- Priority: High +- Difficulty to test: Medium - requires mocking API calls and store setup + +**API Routes:** +- What's not tested: All routes in `src/app/api/**` +- Risk: Server-side bugs not caught +- Priority: Medium +- Difficulty to test: Medium - need request/response mocking + +**React Components:** +- What's not tested: All components in `src/components/**` +- Risk: UI bugs not caught +- Priority: Low - visual testing manual +- Difficulty to test: Medium - need React Testing Library setup + +--- + +*Concerns audit: 2026-01-09* +*Update as issues are fixed or new ones discovered* diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md new file mode 100644 index 00000000..e8e79185 --- /dev/null +++ b/.planning/codebase/CONVENTIONS.md @@ -0,0 +1,154 @@ +# Coding Conventions + +**Analysis Date:** 2026-01-09 + +## Naming Patterns + +**Files:** +- PascalCase for components: `WorkflowCanvas.tsx`, `BaseNode.tsx`, `CostDialog.tsx` +- camelCase for utilities: `costCalculator.ts`, `gridSplitter.ts`, `imageStorage.ts` +- kebab-case for API routes: `save-generation/`, `browse-directory/` +- `*.test.ts` for test files, colocated in `__tests__/` directories + +**Functions:** +- camelCase for all functions: `executeWorkflow()`, `updateNodeData()`, `calculateGenerationCost()` +- No special prefix for async functions +- `handle*` for event handlers: `handleChange`, `handleOpenModal`, `handleSubmit` + +**Variables:** +- camelCase for variables: `nodeData`, `selectedNodes`, `isModalOpen` +- UPPER_SNAKE_CASE for constants: `PRICING`, `COMMON_ASPECT_RATIOS`, `MODEL_MAP` +- No underscore prefix for private members + +**Types:** +- PascalCase for interfaces, no I prefix: `WorkflowNode`, `NodeType`, `BaseNodeData` +- PascalCase for type aliases: `WorkflowNodeData`, `AspectRatio`, `NodeStatus` +- Node data types: `{NodeName}NodeData` (e.g., `ImageInputNodeData`, `NanoBananaNodeData`) + +## Code Style + +**Formatting:** +- 2-space indentation +- Double quotes for strings: `"use client"`, `"text"` +- Semicolons required +- No Prettier config (uses IDE defaults) + +**Linting:** +- Next.js built-in ESLint via `npm run lint` +- No custom `.eslintrc` file +- TypeScript strict mode enabled in `tsconfig.json` + +## Import Organization + +**Order:** +1. React/framework imports: `import { useState } from "react"` +2. External packages: `import { Handle, Position } from "@xyflow/react"` +3. Internal modules with path alias: `import { useWorkflowStore } from "@/store/workflowStore"` +4. Type imports: `import { PromptNodeData } from "@/types"` + +**Grouping:** +- Blank line between groups +- Related imports grouped together + +**Path Aliases:** +- `@/*` maps to `src/*` (configured in `tsconfig.json`) +- Always use alias for internal imports + +## Error Handling + +**Patterns:** +- Try/catch at API route boundaries +- Status field updates for async operations: `status: 'loading' | 'complete' | 'error'` +- Error messages stored in node data for display + +**API Routes:** +```typescript +return NextResponse.json({ success: true, data }); +return NextResponse.json({ success: false, error: "message" }, { status: 500 }); +``` + +**Store Actions:** +- Update node status on error +- Log errors for debugging +- Catch and handle async errors + +## Logging + +**Framework:** +- Custom logger in `src/utils/logger.ts` +- Session-based with unique IDs +- Console output in development + +**Patterns:** +- Structured logging: `logger.info(category, message, context)` +- Categories: `workflow`, `node`, `api`, `file`, `validation` +- Sanitize sensitive data (truncate prompts, remove image data) + +## Comments + +**When to Comment:** +- Explain complex algorithms (e.g., topological sort in execution) +- Document connection validation rules +- Clarify non-obvious business logic + +**JSDoc/TSDoc:** +- Used for public utility functions +- Include `@param`, `@returns` tags +- Example: +```typescript +/** + * Generate a unique image ID for external storage + */ +export function generateImageId(): string { ... } +``` + +**TODO Comments:** +- Format: `// TODO: description` +- Found sparingly in codebase + +## Function Design + +**Size:** +- Most functions under 50 lines +- Exception: `executeWorkflow()` is large (~500 lines) - candidate for splitting + +**Parameters:** +- Use destructuring for component props: `{ id, data, selected }` +- Options object for complex parameters + +**Return Values:** +- Explicit returns +- Return early for guard clauses +- API routes return consistent `{ success, data/error }` shape + +## Module Design + +**Exports:** +- Named exports preferred +- Default exports for React components (optional) +- Barrel exports via `index.ts` for component directories + +**Store Pattern:** +- Single large Zustand store (`workflowStore.ts`) +- Actions defined inline with state +- Selectors via `useWorkflowStore((state) => state.property)` + +## React Patterns + +**Client Directive:** +- `"use client"` at top of client components +- Server components by default in App Router + +**Hooks:** +- `useCallback` for memoized handlers +- `useState` for local component state +- `useWorkflowStore` for global state + +**Modals:** +- Use `createPortal` to render outside React Flow stacking context +- Track modal count in store to prevent keyboard shortcuts + +--- + +*Convention analysis: 2026-01-09* +*Update when patterns change* diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md new file mode 100644 index 00000000..d4d2bd24 --- /dev/null +++ b/.planning/codebase/INTEGRATIONS.md @@ -0,0 +1,114 @@ +# External Integrations + +**Analysis Date:** 2026-01-09 + +## APIs & External Services + +**AI Image Generation - Google Gemini:** +- SDK/Client: `@google/genai` 1.30.0 - `package.json` +- Route: `src/app/api/generate/route.ts` (5-minute timeout) +- Models: `gemini-2.5-flash-image`, `gemini-3-pro-image-preview` +- Internal names: `nano-banana`, `nano-banana-pro` +- Auth: `GEMINI_API_KEY` env var +- Features: Aspect ratio, resolution (2K/4K), Google Search tool + +**AI Text Generation - Google Gemini:** +- Route: `src/app/api/llm/route.ts` (1-minute timeout) +- Models: `gemini-2.5-flash`, `gemini-3-flash-preview`, `gemini-3-pro-preview` +- Auth: `GEMINI_API_KEY` env var +- Features: Temperature, max tokens, multimodal (text + images) + +**AI Text Generation - OpenAI (Optional):** +- Route: `src/app/api/llm/route.ts` +- Models: `gpt-4.1-mini`, `gpt-4.1-nano` +- Endpoint: `https://api.openai.com/v1/chat/completions` +- Auth: `OPENAI_API_KEY` env var (optional) +- Features: Temperature, max tokens, multimodal support + +## Data Storage + +**File System (Server-side):** +- Workflow JSON files - `src/app/api/workflow/route.ts` +- Generated images as PNG - `src/app/api/save-generation/route.ts` +- Auto-creates `inputs/` and `generations/` subdirectories +- Uses `fs/promises` for async file operations + +**LocalStorage (Client-side):** +- `node-banana-workflow-configs` - Project metadata and file paths +- `node-banana-workflow-costs` - Cost tracking per workflow +- `node-banana-nanoBanana-defaults` - Sticky generation settings +- Reference: `src/store/workflowStore.ts` + +**Caching:** +- None (all database queries, no Redis) + +## Authentication & Identity + +**Auth Provider:** +- None - Local-first application +- API keys stored in environment variables only + +## Monitoring & Observability + +**Custom Logging:** +- Logger: `src/utils/logger.ts` (client), `src/utils/logger-server.ts` (server) +- Session-based logging with unique session IDs +- Structured JSON format with timestamps +- Categories: workflow, node execution, API calls, file operations +- Privacy: Truncates prompts (200 chars), sanitizes image data +- Server persistence: `src/app/api/logs/route.ts` +- Rotation: Keeps last 10 sessions + +**Error Tracking:** +- Console logging only (no Sentry/external service) + +**Analytics:** +- None + +## CI/CD & Deployment + +**Hosting:** +- Local development primary use case +- Compatible with Vercel for production deployment + +**CI Pipeline:** +- None configured (no GitHub Actions workflows found) + +## Environment Configuration + +**Development:** +- Required: `GEMINI_API_KEY` +- Optional: `OPENAI_API_KEY` +- Secrets location: `.env.local` (gitignored) +- Reference: `.env.example` + +**Production:** +- Same env vars as development +- No staging environment configured + +## Webhooks & Callbacks + +**Incoming:** +- None + +**Outgoing:** +- None + +## API Timeout Configuration + +| Route | Timeout | Purpose | +|-------|---------|---------| +| `/api/generate` | 5 min | Image generation via Gemini | +| `/api/llm` | 1 min | Text generation (Google/OpenAI) | +| `/api/workflow` | Default | Save/load workflow files | +| Other routes | Default | Various operations | + +## Request Body Size Limits + +- Server Actions body limit: 50MB - `next.config.ts` +- Supports large image payloads in workflows + +--- + +*Integration audit: 2026-01-09* +*Update when adding/removing external services* diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md new file mode 100644 index 00000000..539f7200 --- /dev/null +++ b/.planning/codebase/STACK.md @@ -0,0 +1,81 @@ +# Technology Stack + +**Analysis Date:** 2026-01-09 + +## Languages + +**Primary:** +- TypeScript 5.9.3 - All application code (`package.json`, `tsconfig.json`) + +**Secondary:** +- JavaScript (JSX/TSX) - React components throughout `src/` +- CSS (Tailwind) - `src/app/globals.css`, `postcss.config.mjs` + +## Runtime + +**Environment:** +- Node.js 18+ - Referenced in README, no explicit .nvmrc +- Next.js 16 App Router - Server-side rendering and API routes +- React 19.2.0 - Client-side rendering + +**Package Manager:** +- npm - Primary package manager +- Lockfile: `package-lock.json` present + +## Frameworks + +**Core:** +- Next.js 16.0.6 - Full-stack web framework with App Router (`next.config.ts`) +- React 19.2.0 - UI framework +- @xyflow/react 12.9.3 - Node-based visual editor / React Flow canvas + +**Testing:** +- Vitest 4.0.16 - Unit testing framework (`vitest.config.ts`) +- @vitest/coverage-v8 4.0.16 - V8 coverage provider + +**Build/Dev:** +- TypeScript 5.9.3 - Static type checking +- Turbopack - Rust-based bundler (enabled in `next.config.ts`) +- PostCSS 8.5.6 - CSS preprocessor with Autoprefixer 10.4.22 +- Tailwind CSS 4.1.17 - Utility-first CSS framework + +## Key Dependencies + +**Critical:** +- `@xyflow/react` 12.9.3 - Node editor canvas (`src/components/WorkflowCanvas.tsx`) +- `zustand` 5.0.9 - State management (`src/store/workflowStore.ts`) +- `@google/genai` 1.30.0 - Google Gemini AI SDK (`src/app/api/generate/route.ts`) +- `konva` 10.0.12 + `react-konva` 19.2.1 - Canvas drawing (`src/components/nodes/AnnotationNode.tsx`) + +**Infrastructure:** +- `jszip` 3.10.1 - ZIP file compression for workflow export +- `next` 16.0.6 - App routing and server functions + +## Configuration + +**Environment:** +- `.env.local` files for secrets (gitignored) +- Required: `GEMINI_API_KEY` +- Optional: `OPENAI_API_KEY` + +**Build:** +- `tsconfig.json` - TypeScript config with path aliases (`@/*` → `src/*`) +- `next.config.ts` - Next.js with Turbopack, 50MB body size limit +- `postcss.config.mjs` - PostCSS with Tailwind CSS +- `vitest.config.ts` - Vitest with V8 coverage + +## Platform Requirements + +**Development:** +- macOS/Linux/Windows (any platform with Node.js 18+) +- No external dependencies beyond npm + +**Production:** +- Designed for local execution (desktop app workflow) +- Can deploy to Vercel or similar Next.js hosting +- Requires access to Google Gemini API + +--- + +*Stack analysis: 2026-01-09* +*Update after major dependency changes* diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md new file mode 100644 index 00000000..3d544d02 --- /dev/null +++ b/.planning/codebase/STRUCTURE.md @@ -0,0 +1,171 @@ +# Codebase Structure + +**Analysis Date:** 2026-01-09 + +## Directory Layout + +``` +node-banana/ +├── src/ +│ ├── app/ # Next.js App Router +│ │ ├── layout.tsx # Root layout, metadata +│ │ ├── page.tsx # Main workflow page +│ │ ├── globals.css # Tailwind base styles +│ │ └── api/ # API routes +│ │ ├── generate/ # Image generation +│ │ ├── llm/ # Text generation +│ │ ├── workflow/ # Save/load workflows +│ │ └── ... # Other routes +│ ├── components/ # React components +│ │ ├── nodes/ # Node type implementations +│ │ ├── edges/ # Edge type implementations +│ │ ├── modals/ # Modal dialogs +│ │ ├── quickstart/ # Onboarding UI +│ │ └── *.tsx # Top-level components +│ ├── store/ # Zustand state +│ │ ├── workflowStore.ts # Central workflow state +│ │ └── annotationStore.ts # Drawing state +│ ├── types/ # TypeScript definitions +│ │ ├── index.ts # Main types +│ │ └── quickstart.ts # Quickstart types +│ ├── utils/ # Utilities +│ │ ├── costCalculator.ts # Pricing calculation +│ │ ├── gridSplitter.ts # Grid detection +│ │ ├── imageStorage.ts # Image persistence +│ │ └── logger*.ts # Logging +│ └── lib/ # Feature libraries +│ └── quickstart/ # Quickstart logic + tests +├── public/ # Static assets +├── examples/ # Community workflows +├── .planning/ # Project planning docs +├── package.json # Dependencies +├── tsconfig.json # TypeScript config +└── next.config.ts # Next.js config +``` + +## Directory Purposes + +**src/app/** +- Purpose: Next.js App Router pages and API routes +- Contains: Page components, API handlers +- Key files: `page.tsx` (main entry), `layout.tsx` (root layout) +- Subdirectories: `api/` for server routes + +**src/components/** +- Purpose: React UI components +- Contains: All visual components +- Key files: `WorkflowCanvas.tsx`, `Header.tsx`, `FloatingActionBar.tsx` +- Subdirectories: `nodes/`, `edges/`, `modals/`, `quickstart/` + +**src/components/nodes/** +- Purpose: Node type implementations (7 types) +- Contains: `BaseNode.tsx` (wrapper), `*Node.tsx` (specific types) +- Key files: `NanoBananaNode.tsx`, `PromptNode.tsx`, `ImageInputNode.tsx` + +**src/store/** +- Purpose: Zustand state management +- Contains: Store definitions and actions +- Key files: `workflowStore.ts` (2000+ lines, central state) + +**src/types/** +- Purpose: TypeScript type definitions +- Contains: All interfaces and type unions +- Key files: `index.ts` (main types), `quickstart.ts` + +**src/utils/** +- Purpose: Business logic utilities +- Contains: Standalone helper functions +- Key files: `costCalculator.ts`, `gridSplitter.ts`, `imageStorage.ts` + +**src/lib/quickstart/** +- Purpose: Quickstart/onboarding feature +- Contains: Templates, prompts, validation +- Subdirectories: `__tests__/` for test files + +## Key File Locations + +**Entry Points:** +- `src/app/page.tsx` - Main application entry +- `src/app/layout.tsx` - Root layout and providers + +**Configuration:** +- `tsconfig.json` - TypeScript config (path alias: `@/*`) +- `next.config.ts` - Next.js with Turbopack +- `vitest.config.ts` - Test configuration +- `.env.local` - Environment variables (gitignored) + +**Core Logic:** +- `src/store/workflowStore.ts` - All workflow state and execution +- `src/components/WorkflowCanvas.tsx` - Canvas orchestration +- `src/types/index.ts` - Type definitions + +**API Routes:** +- `src/app/api/generate/route.ts` - Image generation +- `src/app/api/llm/route.ts` - Text generation +- `src/app/api/workflow/route.ts` - File operations + +**Testing:** +- `src/lib/quickstart/__tests__/*.test.ts` - Unit tests + +**Documentation:** +- `README.md` - User-facing documentation +- `CLAUDE.md` - AI assistant instructions + +## Naming Conventions + +**Files:** +- PascalCase.tsx - React components (`WorkflowCanvas.tsx`) +- camelCase.ts - Utilities and stores (`costCalculator.ts`) +- kebab-case directories - API routes (`save-generation/`) +- *.test.ts - Test files (colocated in `__tests__/`) + +**Directories:** +- camelCase - Feature directories (`quickstart/`) +- Plural for collections (`nodes/`, `edges/`, `modals/`) + +**Special Patterns:** +- `route.ts` - Next.js API route handler +- `index.ts` - Barrel exports +- `__tests__/` - Test directory + +## Where to Add New Code + +**New Node Type:** +- Implementation: `src/components/nodes/{Name}Node.tsx` +- Types: Add to `src/types/index.ts` (NodeType union, data interface) +- Registration: `src/components/WorkflowCanvas.tsx` (nodeTypes) +- Store logic: `src/store/workflowStore.ts` (createDefaultNodeData, executeWorkflow) + +**New API Route:** +- Handler: `src/app/api/{route-name}/route.ts` +- Export: `GET`, `POST`, etc. functions + +**New Utility:** +- Implementation: `src/utils/{name}.ts` +- Tests: `src/utils/__tests__/{name}.test.ts` + +**New Component:** +- Implementation: `src/components/{Name}.tsx` +- Or in feature directory: `src/components/{feature}/{Name}.tsx` + +## Special Directories + +**examples/** +- Purpose: Community workflow examples +- Source: JSON workflow files +- Committed: Yes + +**.planning/** +- Purpose: Project planning documentation +- Source: GSD planning system +- Committed: Yes + +**.next/** +- Purpose: Next.js build output +- Source: Generated during build +- Committed: No (gitignored) + +--- + +*Structure analysis: 2026-01-09* +*Update when directory structure changes* diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md new file mode 100644 index 00000000..70dbc347 --- /dev/null +++ b/.planning/codebase/TESTING.md @@ -0,0 +1,180 @@ +# Testing Patterns + +**Analysis Date:** 2026-01-09 + +## Test Framework + +**Runner:** +- Vitest 4.0.16 +- Config: `vitest.config.ts` in project root + +**Assertion Library:** +- Vitest built-in expect +- Matchers: `toBe`, `toEqual`, `toHaveLength`, `toContainEqual`, `toHaveProperty` + +**Run Commands:** +```bash +npm test # Run all tests in watch mode +npm run test:run # Run tests once +npm run test:coverage # Run with coverage report +``` + +## Test File Organization + +**Location:** +- Colocated in `__tests__/` directories within feature folders +- Pattern: `src/lib/{feature}/__tests__/*.test.ts` + +**Naming:** +- `{module-name}.test.ts` for all tests +- No distinction between unit/integration in filename + +**Current Test Files:** +``` +src/lib/quickstart/__tests__/ + ├── templates.test.ts # Template data validation + ├── prompts.test.ts # Prompt generation tests + └── validation.test.ts # JSON validation tests +``` + +## Test Structure + +**Suite Organization:** +```typescript +import { describe, it, expect } from "vitest"; + +describe("validation", () => { + describe("validateWorkflowJSON", () => { + describe("root validation", () => { + it("should reject null input", () => { + const result = validateWorkflowJSON(null); + expect(result.valid).toBe(false); + expect(result.errors).toContainEqual({ + path: "", + message: "Workflow must be an object", + }); + }); + }); + }); +}); +``` + +**Patterns:** +- Nested `describe()` blocks for logical grouping +- `it()` with descriptive "should" naming +- Arrange/Act/Assert structure (implicit) +- One concept per test + +## Mocking + +**Framework:** +- No mocks currently used +- Tests work with actual functions and data + +**What to Mock (if needed):** +- API calls (fetch) +- File system operations +- External services + +**What NOT to Mock:** +- Pure functions +- Validation logic +- Data structures + +## Fixtures and Factories + +**Test Data:** +- Inline test data in test files +- No separate fixtures directory + +**Pattern Example:** +```typescript +const validWorkflow = { + version: 1, + nodes: [], + edges: [], +}; +``` + +## Coverage + +**Requirements:** +- No enforced coverage target +- Coverage tracked for awareness + +**Configuration:** +```typescript +// vitest.config.ts +coverage: { + provider: "v8", + reporter: ["text", "json", "html"], + include: ["src/lib/quickstart/**"], + exclude: ["node_modules", "src/__tests__"], +} +``` + +**View Coverage:** +```bash +npm run test:coverage +open coverage/index.html +``` + +## Test Types + +**Unit Tests:** +- Current focus: Quickstart validation functions +- Test single functions in isolation +- Examples: `validateWorkflowJSON()`, `repairWorkflowJSON()`, `parseJSONFromResponse()` + +**Integration Tests:** +- Not currently implemented +- Needed for: API routes, workflow execution + +**E2E Tests:** +- Not currently implemented +- Would use Playwright if added + +## Test Coverage Gaps + +**Untested Areas:** +- `src/store/workflowStore.ts` - Core execution logic (HIGH PRIORITY) +- `src/app/api/**` - All API routes +- `src/components/**` - All React components +- `src/utils/costCalculator.ts` - Cost calculation +- `src/utils/gridSplitter.ts` - Grid detection + +**Tested Areas:** +- `src/lib/quickstart/validation.ts` - Workflow JSON validation +- `src/lib/quickstart/templates.ts` - Template data structures +- `src/lib/quickstart/prompts.ts` - Prompt generation + +## Common Patterns + +**Async Testing:** +```typescript +it("should handle async operation", async () => { + const result = await asyncFunction(); + expect(result).toBe("expected"); +}); +``` + +**Error Testing:** +```typescript +it("should reject invalid input", () => { + const result = validateWorkflowJSON(null); + expect(result.valid).toBe(false); + expect(result.errors).toContainEqual({ + path: "", + message: "Workflow must be an object", + }); +}); +``` + +**Snapshot Testing:** +- Not used in this codebase +- Prefer explicit assertions + +--- + +*Testing analysis: 2026-01-09* +*Update when test patterns change*