{ "project": "WebVNWrite", "branchName": "ralph/vn-flowchart-editor", "description": "Visual Novel Flowchart Editor - A web-based tool for authoring visual novels with drag-and-drop nodes, branching connections, user authentication, and Ren'Py JSON export", "userStories": [ { "id": "US-001", "title": "Project scaffolding and configuration", "description": "As a developer, I need the project set up with Next.js, TailwindCSS, and Supabase so that I can build the application.", "acceptanceCriteria": [ "Initialize Next.js project with TypeScript and App Router", "Install and configure TailwindCSS", "Install Supabase client library (@supabase/supabase-js)", "Create .env.example with NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY", "Basic folder structure: app/, components/, lib/, types/", "Typecheck passes" ], "priority": 1, "passes": true, "notes": "" }, { "id": "US-002", "title": "Define TypeScript types for flowchart data", "description": "As a developer, I need TypeScript types for nodes, connections, and conditions.", "acceptanceCriteria": [ "Create types/flowchart.ts file", "DialogueNode type: id, type='dialogue', position: {x,y}, data: { speaker?: string, text: string }", "ChoiceNode type: id, type='choice', position: {x,y}, data: { prompt: string, options: { id: string, label: string }[] }", "VariableNode type: id, type='variable', position: {x,y}, data: { variableName: string, operation: 'set'|'add'|'subtract', value: number }", "Condition type: { variableName: string, operator: '>'|'<'|'=='|'>='|'<='|'!=', value: number }", "FlowchartEdge type: id, source, sourceHandle?, target, targetHandle?, data?: { condition?: Condition }", "FlowchartData type: { nodes: (DialogueNode|ChoiceNode|VariableNode)[], edges: FlowchartEdge[] }", "All types exported from types/flowchart.ts", "Typecheck passes" ], "priority": 2, "passes": true, "notes": "" }, { "id": "US-003", "title": "Supabase schema for users and projects", "description": "As a developer, I need database tables to store users and their projects.", "acceptanceCriteria": [ "Create supabase/migrations/ directory", "Create SQL migration file with profiles table: id (uuid, references auth.users), email (text), display_name (text), is_admin (boolean default false), created_at (timestamptz)", "Create projects table: id (uuid), user_id (uuid, foreign key to profiles.id), name (text), flowchart_data (jsonb), created_at (timestamptz), updated_at (timestamptz)", "Add RLS policy: users can SELECT/INSERT/UPDATE/DELETE their own projects (user_id = auth.uid())", "Add RLS policy: users can SELECT their own profile", "Add RLS policy: admin users (is_admin=true) can SELECT all profiles", "Typecheck passes" ], "priority": 3, "passes": true, "notes": "" }, { "id": "US-004", "title": "Supabase client configuration", "description": "As a developer, I need Supabase client utilities for auth and database access.", "acceptanceCriteria": [ "Create lib/supabase/client.ts with browser client (createBrowserClient)", "Create lib/supabase/server.ts with server client (createServerClient for App Router)", "Create lib/supabase/middleware.ts with middleware client helper", "Export typed database client using generated types or manual types", "Typecheck passes" ], "priority": 4, "passes": true, "notes": "" }, { "id": "US-005", "title": "Protected routes middleware", "description": "As a developer, I need authentication middleware so that only logged-in users can access the app.", "acceptanceCriteria": [ "Create middleware.ts at project root", "Middleware checks Supabase session on each request", "Unauthenticated users accessing /dashboard or /editor/* are redirected to /login", "Authenticated users accessing /login or /signup are redirected to /dashboard", "Public routes allowed without auth: /login, /signup, /forgot-password, /reset-password", "Typecheck passes" ], "priority": 5, "passes": true, "notes": "" }, { "id": "US-006", "title": "Login page", "description": "As a user, I want to log in with my email and password so that I can access my projects.", "acceptanceCriteria": [ "Create app/login/page.tsx", "Form with email and password input fields", "Submit button calls Supabase signInWithPassword", "Show error message for invalid credentials", "On success, redirect to /dashboard", "Link to /forgot-password page", "Styled with TailwindCSS", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 6, "passes": true, "notes": "" }, { "id": "US-007", "title": "Sign up page (invite-only)", "description": "As an invited user, I want to complete my account setup so that I can access the tool.", "acceptanceCriteria": [ "Create app/signup/page.tsx", "Form with email (pre-filled if from invite link), password, and confirm password fields", "Validate passwords match before submission", "Handle Supabase invite token from URL (type=invite or type=signup)", "On success, create profile record in profiles table and redirect to /dashboard", "Show error message if signup fails", "Styled with TailwindCSS", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 7, "passes": true, "notes": "" }, { "id": "US-008", "title": "Logout functionality", "description": "As a user, I want to log out so that I can secure my session.", "acceptanceCriteria": [ "Create components/LogoutButton.tsx component", "Button calls Supabase signOut", "On success, redirect to /login", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 8, "passes": true, "notes": "" }, { "id": "US-009", "title": "Password reset - forgot password page", "description": "As a user, I want to request a password reset if I forget my password.", "acceptanceCriteria": [ "Create app/forgot-password/page.tsx", "Form with email input field", "Submit button calls Supabase resetPasswordForEmail", "Show confirmation message after sending (check your email)", "Link back to /login", "Styled with TailwindCSS", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 9, "passes": true, "notes": "" }, { "id": "US-010", "title": "Password reset - set new password page", "description": "As a user, I want to set a new password after clicking the reset link.", "acceptanceCriteria": [ "Create app/reset-password/page.tsx", "Form with new password and confirm password fields", "Handle Supabase recovery token from URL", "Submit calls Supabase updateUser with new password", "On success, redirect to /login with success message", "Show error if token invalid or expired", "Styled with TailwindCSS", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 10, "passes": true, "notes": "" }, { "id": "US-011", "title": "Dashboard layout with navbar", "description": "As a user, I want a consistent layout with navigation so that I can move around the app.", "acceptanceCriteria": [ "Create app/dashboard/layout.tsx", "Navbar component with app title/logo", "Navbar shows current user email", "Navbar includes LogoutButton", "Main content area below navbar", "Styled with TailwindCSS", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 11, "passes": true, "notes": "" }, { "id": "US-012", "title": "Dashboard - list projects", "description": "As a user, I want to see all my projects so that I can choose which one to edit.", "acceptanceCriteria": [ "Create app/dashboard/page.tsx", "Fetch projects from Supabase for current user", "Display projects as cards in a grid", "Each card shows: project name, last updated date (formatted)", "Click card navigates to /editor/[projectId]", "Empty state with message when no projects exist", "Loading state while fetching", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 12, "passes": true, "notes": "" }, { "id": "US-013", "title": "Create new project", "description": "As a user, I want to create a new project so that I can start a new flowchart.", "acceptanceCriteria": [ "Add 'New Project' button on dashboard", "Clicking opens modal with project name input", "Submit creates project in Supabase with empty flowchart_data: { nodes: [], edges: [] }", "On success, redirect to /editor/[newProjectId]", "Show error if creation fails", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 13, "passes": true, "notes": "" }, { "id": "US-014", "title": "Delete project", "description": "As a user, I want to delete a project I no longer need.", "acceptanceCriteria": [ "Add delete icon/button on each project card", "Clicking shows confirmation dialog (Are you sure?)", "Confirm deletes project from Supabase", "Project removed from dashboard list without page reload", "Show success toast after deletion", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 14, "passes": true, "notes": "" }, { "id": "US-015", "title": "Rename project", "description": "As a user, I want to rename a project to keep my work organized.", "acceptanceCriteria": [ "Add edit/rename icon on project card", "Clicking opens modal or enables inline edit for project name", "Submit updates project name in Supabase", "UI updates immediately without page reload", "Show error if rename fails", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 15, "passes": true, "notes": "" }, { "id": "US-016", "title": "Admin - invite new user", "description": "As an admin, I want to invite new users so that collaborators can access the tool.", "acceptanceCriteria": [ "Create app/admin/invite/page.tsx", "Only accessible by users with is_admin=true (redirect others to /dashboard)", "Form with email address input", "Submit calls Supabase admin inviteUserByEmail (requires service role key in server action)", "Show success message with invite sent confirmation", "Show error if invite fails", "Link to this page visible in navbar only for admins", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 16, "passes": true, "notes": "" }, { "id": "US-017", "title": "Editor page with React Flow canvas", "description": "As a user, I want an editor page with a canvas where I can build my flowchart.", "acceptanceCriteria": [ "Install reactflow package", "Create app/editor/[projectId]/page.tsx", "Fetch project from Supabase by ID", "Show error if project not found or user unauthorized", "Show loading state while fetching", "Render React Flow canvas filling the editor area", "Canvas has grid background (React Flow Background component)", "Header shows project name with back link to /dashboard", "Initialize React Flow with nodes and edges from flowchart_data", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 17, "passes": true, "notes": "" }, { "id": "US-018", "title": "Canvas pan and zoom controls", "description": "As a user, I want to pan and zoom the canvas to navigate large flowcharts.", "acceptanceCriteria": [ "Canvas supports click-and-drag panning (React Flow default)", "Mouse wheel zooms in/out (React Flow default)", "Add React Flow Controls component with zoom +/- buttons", "Add fitView button to show all nodes", "Controls positioned in bottom-right corner", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 18, "passes": true, "notes": "" }, { "id": "US-019", "title": "Editor toolbar", "description": "As a user, I want a toolbar with actions for adding nodes and saving/exporting.", "acceptanceCriteria": [ "Create components/editor/Toolbar.tsx", "Toolbar positioned at top of editor below header", "Buttons: Add Dialogue, Add Choice, Add Variable (no functionality yet)", "Buttons: Save, Export, Import (no functionality yet)", "Buttons styled with TailwindCSS, icons optional", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 19, "passes": true, "notes": "" }, { "id": "US-020", "title": "Create custom dialogue node component", "description": "As a user, I want dialogue nodes to display and edit character speech.", "acceptanceCriteria": [ "Create components/editor/nodes/DialogueNode.tsx", "Node styled with blue background/border", "Displays editable input for speaker name (placeholder: 'Speaker')", "Displays editable textarea for dialogue text (placeholder: 'Dialogue text...')", "Has one Handle at top (type='target', id='input')", "Has one Handle at bottom (type='source', id='output')", "Register as custom node type in React Flow", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 20, "passes": true, "notes": "" }, { "id": "US-021", "title": "Add dialogue node from toolbar", "description": "As a user, I want to add dialogue nodes by clicking the toolbar button.", "acceptanceCriteria": [ "Clicking 'Add Dialogue' in toolbar creates new DialogueNode", "Node appears at center of current viewport", "Node has unique ID (use nanoid or uuid)", "Node added to React Flow nodes state", "Node can be dragged to reposition", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 21, "passes": true, "notes": "" }, { "id": "US-022", "title": "Create custom choice node component", "description": "As a user, I want choice nodes to display branching decisions.", "acceptanceCriteria": [ "Create components/editor/nodes/ChoiceNode.tsx", "Node styled with green background/border", "Displays editable input for prompt text (placeholder: 'What do you choose?')", "Displays 2 default options, each with editable label input", "Has one Handle at top (type='target', id='input')", "Each option has its own Handle at bottom (type='source', id='option-0', 'option-1', etc.)", "Register as custom node type in React Flow", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 22, "passes": true, "notes": "" }, { "id": "US-023", "title": "Add choice node from toolbar", "description": "As a user, I want to add choice nodes by clicking the toolbar button.", "acceptanceCriteria": [ "Clicking 'Add Choice' in toolbar creates new ChoiceNode", "Node appears at center of current viewport", "Node has unique ID", "Node initialized with 2 options (each with unique id and empty label)", "Node added to React Flow nodes state", "Node can be dragged to reposition", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 23, "passes": true, "notes": "" }, { "id": "US-024", "title": "Add/remove choice options", "description": "As a user, I want to add or remove choice options (2-6 options supported).", "acceptanceCriteria": [ "ChoiceNode has '+' button to add new option", "Maximum 6 options (button disabled or hidden at max)", "Each option has 'x' button to remove it", "Minimum 2 options (remove button disabled or hidden at min)", "Adding option creates new output Handle dynamically", "Removing option removes its Handle", "Node data updates in React Flow state", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 24, "passes": true, "notes": "" }, { "id": "US-025", "title": "Create custom variable node component", "description": "As a user, I want variable nodes to set or modify story variables.", "acceptanceCriteria": [ "Create components/editor/nodes/VariableNode.tsx", "Node styled with orange background/border", "Displays editable input for variable name (placeholder: 'variableName')", "Displays dropdown/select for operation: set, add, subtract", "Displays editable number input for value (default: 0)", "Has one Handle at top (type='target', id='input')", "Has one Handle at bottom (type='source', id='output')", "Register as custom node type in React Flow", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 25, "passes": true, "notes": "" }, { "id": "US-026", "title": "Add variable node from toolbar", "description": "As a user, I want to add variable nodes by clicking the toolbar button.", "acceptanceCriteria": [ "Clicking 'Add Variable' in toolbar creates new VariableNode", "Node appears at center of current viewport", "Node has unique ID", "Node initialized with empty variableName, operation='set', value=0", "Node added to React Flow nodes state", "Node can be dragged to reposition", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 26, "passes": true, "notes": "" }, { "id": "US-027", "title": "Connect nodes with edges", "description": "As a user, I want to connect nodes with arrows to define story flow.", "acceptanceCriteria": [ "Dragging from source Handle to target Handle creates edge (React Flow default)", "Edges render as smooth bezier curves (default edge type or smoothstep)", "Edges show arrow marker indicating direction (markerEnd)", "Edges update position when nodes are moved", "Cannot connect source-to-source or target-to-target (React Flow handles this)", "New edges added to React Flow edges state", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 27, "passes": true, "notes": "" }, { "id": "US-028", "title": "Select and delete nodes", "description": "As a user, I want to delete nodes to revise my flowchart.", "acceptanceCriteria": [ "Clicking a node selects it (visual highlight via React Flow)", "Pressing Delete or Backspace key removes selected node(s)", "Deleting node also removes all connected edges", "Use onNodesDelete callback to handle deletion", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 28, "passes": true, "notes": "" }, { "id": "US-029", "title": "Select and delete edges", "description": "As a user, I want to delete connections between nodes.", "acceptanceCriteria": [ "Clicking an edge selects it (visual highlight via React Flow)", "Pressing Delete or Backspace key removes selected edge(s)", "Use onEdgesDelete callback to handle deletion", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 29, "passes": true, "notes": "" }, { "id": "US-030", "title": "Right-click context menu", "description": "As a user, I want a context menu for quick actions.", "acceptanceCriteria": [ "Create components/editor/ContextMenu.tsx", "Right-click on canvas shows menu: Add Dialogue, Add Choice, Add Variable", "New node created at click position", "Right-click on node shows menu: Delete", "Right-click on edge shows menu: Delete, Add Condition", "Clicking elsewhere or pressing Escape closes menu", "Menu styled with TailwindCSS", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 30, "passes": true, "notes": "" }, { "id": "US-031", "title": "Condition editor modal", "description": "As a user, I want to add conditions to edges so branches depend on variables.", "acceptanceCriteria": [ "Create components/editor/ConditionEditor.tsx modal/popover", "Opens on double-click edge or via context menu 'Add Condition'", "Form fields: variable name input, operator dropdown (>, <, ==, >=, <=, !=), value number input", "Pre-fill fields if edge already has condition", "Save button applies condition to edge data", "Clear/Remove button removes condition from edge", "Cancel button closes without saving", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 31, "passes": true, "notes": "" }, { "id": "US-032", "title": "Display conditions on edges", "description": "As a user, I want to see conditions displayed on edges.", "acceptanceCriteria": [ "Create custom edge component or use edge labels", "Edges with conditions render as dashed lines (strokeDasharray)", "Condition label displayed on edge (e.g., 'score > 5')", "Unconditional edges remain solid lines", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 32, "passes": true, "notes": "" }, { "id": "US-033", "title": "Auto-save to LocalStorage", "description": "As a user, I want my work auto-saved locally so I don't lose progress if the browser crashes.", "acceptanceCriteria": [ "Save flowchart state (nodes + edges) to LocalStorage on every change", "Debounce saves (e.g., 1 second delay after last change)", "LocalStorage key format: 'vnwrite-draft-{projectId}'", "On editor load, check LocalStorage for saved draft", "If local draft exists and differs from database, show prompt to restore or discard", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 33, "passes": true, "notes": "" }, { "id": "US-034", "title": "Save project to database", "description": "As a user, I want to save my project to the database manually.", "acceptanceCriteria": [ "Clicking 'Save' in toolbar saves current nodes/edges to Supabase", "Update project's flowchart_data and updated_at fields", "Show saving indicator/spinner while in progress", "Show success toast on completion", "Clear LocalStorage draft after successful save", "Show error toast if save fails", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 34, "passes": true, "notes": "" }, { "id": "US-035", "title": "Export project as .vnflow file", "description": "As a user, I want to export my project as a JSON file for backup or sharing.", "acceptanceCriteria": [ "Clicking 'Export' in toolbar triggers file download", "File named '[project-name].vnflow'", "File contains JSON with nodes and edges arrays", "JSON is pretty-printed (2-space indent) for readability", "Uses browser download API (create blob, trigger download)", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 35, "passes": true, "notes": "" }, { "id": "US-036", "title": "Import project from .vnflow file", "description": "As a user, I want to import a .vnflow file to restore or share projects.", "acceptanceCriteria": [ "Clicking 'Import' in toolbar opens file picker", "Accept .vnflow and .json file extensions", "If current project has unsaved changes, show confirmation dialog", "Validate imported file has nodes and edges arrays", "Show error toast if file is invalid", "Load valid data into React Flow state (replaces current flowchart)", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 36, "passes": true, "notes": "" }, { "id": "US-037", "title": "Export to Ren'Py JSON format", "description": "As a user, I want to export my flowchart to Ren'Py-compatible JSON for use in my game.", "acceptanceCriteria": [ "Add 'Export to Ren'Py' option (button or dropdown item)", "File named '[project-name]-renpy.json'", "Dialogue nodes export as: { type: 'dialogue', speaker: '...', text: '...' }", "Choice nodes export as: { type: 'menu', prompt: '...', choices: [{ label: '...', next: '...' }] }", "Variable nodes export as: { type: 'variable', name: '...', operation: '...', value: ... }", "Edges with conditions include condition object on the choice/jump", "Organize nodes into labeled sections based on flow (traverse from first node)", "Include metadata: projectName, exportedAt timestamp", "Output JSON is valid (test with JSON.parse)", "Typecheck passes" ], "priority": 37, "passes": true, "notes": "" }, { "id": "US-038", "title": "Unsaved changes warning", "description": "As a user, I want a warning before losing unsaved work.", "acceptanceCriteria": [ "Track dirty state: true when flowchart modified after last save", "Set dirty=true on node/edge add, delete, or modify", "Set dirty=false after successful save", "Browser beforeunload event shows warning if dirty", "Navigating to dashboard shows confirmation modal if dirty", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 38, "passes": true, "notes": "" }, { "id": "US-039", "title": "Loading and error states", "description": "As a user, I want clear feedback when things are loading or when errors occur.", "acceptanceCriteria": [ "Loading spinner component for async operations", "Editor shows loading spinner while fetching project", "Error message displayed if project fails to load (with back to dashboard link)", "Toast notification system for success/error messages", "Save error shows toast with retry option", "Typecheck passes", "Verify in browser using dev-browser skill" ], "priority": 39, "passes": true, "notes": "" } ] }