Browse Source
- STACK.md - Technologies and dependencies - ARCHITECTURE.md - System design and patterns - STRUCTURE.md - Directory layout - CONVENTIONS.md - Code style and patterns - TESTING.md - Test structure - INTEGRATIONS.md - External services - CONCERNS.md - Technical debt and issueshandoff-20260429-1057
7 changed files with 975 additions and 0 deletions
@ -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<string, NodeGroup>` |
|||
- 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* |
|||
@ -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* |
|||
@ -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* |
|||
@ -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* |
|||
@ -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* |
|||
@ -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* |
|||
@ -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* |
|||
Loading…
Reference in new issue