764 lines
37 KiB
JSON
764 lines
37 KiB
JSON
{
|
|
"project": "WebVNWrite",
|
|
"branchName": "ralph/collaboration-and-character-variables",
|
|
"description": "Real-time Collaboration & Character/Variable Management - Enable multi-user editing with CRDT sync, presence indicators, audit trail, plus centralized character/variable definitions with dropdown selectors",
|
|
"userStories": [
|
|
{
|
|
"id": "US-054",
|
|
"title": "Character and Variable TypeScript types",
|
|
"description": "As a developer, I need TypeScript types for Character and Variable models so that the rest of the feature can be built with type safety.",
|
|
"acceptanceCriteria": [
|
|
"Add Character type to types/flowchart.ts: id (string), name (string), color (string, hex), description (string, optional)",
|
|
"Add Variable type to types/flowchart.ts: id (string), name (string), type ('numeric' | 'string' | 'boolean'), initialValue (number | string | boolean), description (string, optional)",
|
|
"Update FlowchartData type to include characters: Character[] and variables: Variable[]",
|
|
"Update DialogueNodeData to add optional characterId: string field (alongside existing speaker for migration)",
|
|
"Update Condition type to add optional variableId: string field (alongside existing variableName for migration)",
|
|
"Update VariableNodeData to add optional variableId: string field (alongside existing variableName for migration)",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 1,
|
|
"passes": true,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-055",
|
|
"title": "Database schema update for characters and variables",
|
|
"description": "As a developer, I need the database schema to store characters and variables as part of the project's flowchart data.",
|
|
"acceptanceCriteria": [
|
|
"Create migration that documents the new JSONB structure (characters/variables arrays stored within flowchart_data)",
|
|
"Update the default value for flowchart_data column to include characters: [] and variables: []",
|
|
"Existing projects with no characters/variables arrays continue to load (handled as empty arrays in app code)",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 2,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-054"
|
|
},
|
|
{
|
|
"id": "US-065",
|
|
"title": "Searchable combobox component",
|
|
"description": "As a developer, I need a reusable searchable combobox component so that all character/variable dropdowns share consistent behavior and styling.",
|
|
"acceptanceCriteria": [
|
|
"Create components/editor/Combobox.tsx - a reusable searchable dropdown component",
|
|
"Props: items (id, label, color?, badge?), value, onChange, placeholder, onAddNew (optional callback)",
|
|
"Typing in the input filters the list by name (case-insensitive)",
|
|
"Keyboard navigation: arrow keys to move, Enter to select, Escape to close",
|
|
"Shows color swatch and/or badge next to item labels when provided",
|
|
"'Add new...' option rendered at bottom when onAddNew prop is provided",
|
|
"Dropdown positions itself above or below input based on available space",
|
|
"Matches existing editor styling (TailwindCSS, dark mode support)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 3,
|
|
"passes": true,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-056",
|
|
"title": "Character management UI in project settings",
|
|
"description": "As a user, I want a dedicated page to manage my project's characters so that I can define them once and reuse them throughout the flowchart.",
|
|
"acceptanceCriteria": [
|
|
"Add 'Project Settings' button to editor toolbar",
|
|
"Project settings opens as a modal with 'Characters' and 'Variables' tabs",
|
|
"Characters tab shows a list of defined characters with name, color swatch, and description",
|
|
"'Add Character' button opens inline form with: name (required), color picker (required, defaults to random), description (optional)",
|
|
"Each character row has Edit and Delete buttons",
|
|
"Deleting a character referenced by nodes shows warning with usage count",
|
|
"Character names must be unique within the project (validation error if duplicate)",
|
|
"Changes are saved to the flowchart data (same save mechanism as nodes/edges)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 4,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-054, US-055"
|
|
},
|
|
{
|
|
"id": "US-057",
|
|
"title": "Variable management UI in project settings",
|
|
"description": "As a user, I want a dedicated page to manage my project's variables so that I can define them with types and initial values for use throughout the flowchart.",
|
|
"acceptanceCriteria": [
|
|
"Variables tab in project settings modal shows a list of defined variables",
|
|
"Each variable displays: name, type badge (numeric/string/boolean), initial value, description",
|
|
"'Add Variable' button opens inline form with: name (required), type dropdown (required), initial value (required, input adapts to type), description (optional)",
|
|
"Each variable row has Edit and Delete buttons",
|
|
"Deleting a variable referenced by nodes/edges shows warning with usage count",
|
|
"Variable names must be unique within the project",
|
|
"Changes are saved to the flowchart data",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 5,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-054, US-055"
|
|
},
|
|
{
|
|
"id": "US-058",
|
|
"title": "Dialogue node speaker dropdown",
|
|
"description": "As a user, I want to select a character from a dropdown in the dialogue node instead of typing a name so that I avoid typos and maintain consistency.",
|
|
"acceptanceCriteria": [
|
|
"Replace the speaker text input in DialogueNode with the Combobox component",
|
|
"Dropdown lists all characters defined in the project, showing color swatch + name",
|
|
"Selecting a character sets characterId on the node data",
|
|
"Dropdown includes 'Add new character...' option at the bottom",
|
|
"Clicking 'Add new character...' opens a mini form inline (name + color) that creates the character and selects it",
|
|
"If node has a characterId that doesn't match any defined character, show orange warning border on the dropdown",
|
|
"Empty/unset speaker shows placeholder 'Select speaker...'",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 6,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-056, US-065"
|
|
},
|
|
{
|
|
"id": "US-059",
|
|
"title": "Variable node variable dropdown",
|
|
"description": "As a user, I want to select a variable from a dropdown in the variable node instead of typing a name so that I avoid typos and maintain consistency.",
|
|
"acceptanceCriteria": [
|
|
"Replace the variableName text input in VariableNode with the Combobox component",
|
|
"Dropdown lists all variables defined in the project, showing type badge + name",
|
|
"Selecting a variable sets variableId on the node data",
|
|
"Dropdown includes 'Add new variable...' option that opens inline creation form",
|
|
"If node references a variableId that doesn't match any defined variable, show orange warning border",
|
|
"Operation options (set/add/subtract) are filtered based on selected variable's type (add/subtract only for numeric)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 7,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-057, US-065"
|
|
},
|
|
{
|
|
"id": "US-060",
|
|
"title": "Edge condition variable dropdown",
|
|
"description": "As a user, I want to select a variable from a dropdown when setting edge conditions so that I reference valid variables consistently.",
|
|
"acceptanceCriteria": [
|
|
"Replace the variableName text input in ConditionEditor with the Combobox component",
|
|
"Dropdown lists all variables defined in the project, showing type badge + name",
|
|
"Selecting a variable sets variableId on the condition object",
|
|
"Dropdown includes 'Add new variable...' option",
|
|
"If condition references an undefined variableId, show orange warning indicator",
|
|
"Operator options are filtered based on variable type (comparison operators for numeric, == and != for string/boolean)",
|
|
"Value input adapts to variable type (number input for numeric, text for string, checkbox for boolean)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 8,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-057, US-065"
|
|
},
|
|
{
|
|
"id": "US-061",
|
|
"title": "Choice option condition variable dropdown",
|
|
"description": "As a user, I want to select a variable from a dropdown when setting choice option conditions so that I reference valid variables consistently.",
|
|
"acceptanceCriteria": [
|
|
"Replace the variableName text input in OptionConditionEditor with the Combobox component",
|
|
"Dropdown lists all variables defined in the project, showing type badge + name",
|
|
"Selecting a variable sets variableId on the option's condition object",
|
|
"Dropdown includes 'Add new variable...' option",
|
|
"If condition references an undefined variableId, show orange warning indicator",
|
|
"Operator and value inputs adapt to variable type (same behavior as US-060)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 9,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-057, US-065"
|
|
},
|
|
{
|
|
"id": "US-062",
|
|
"title": "Auto-migration of existing free-text values",
|
|
"description": "As a user, I want my existing projects to automatically create character and variable definitions from free-text values so that I don't have to manually re-enter them.",
|
|
"acceptanceCriteria": [
|
|
"On project load, if characters array is empty but nodes have speaker values, auto-create Character entries from unique speaker names",
|
|
"Auto-created characters get randomly assigned colors and the speaker text as name",
|
|
"On project load, if variables array is empty but nodes/edges have variableName values, auto-create Variable entries (default type: numeric, initial value: 0)",
|
|
"After auto-creation, update all nodes to set characterId/variableId references pointing to the new entries",
|
|
"Show a toast notification: 'Auto-imported N characters and M variables from existing data'",
|
|
"Migration only runs once (presence of characters/variables arrays, even if empty, means migration already happened)",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 10,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-054, US-058, US-059"
|
|
},
|
|
{
|
|
"id": "US-063",
|
|
"title": "Import characters/variables from another project",
|
|
"description": "As a user, I want to import character and variable definitions from another project so that I can reuse them without redefining everything.",
|
|
"acceptanceCriteria": [
|
|
"Add 'Import from project' button in both Characters and Variables tabs of project settings",
|
|
"Button opens a modal listing the user's other projects",
|
|
"Selecting a project shows its characters (or variables) with checkboxes for selection",
|
|
"User can select which entries to import (select all / none / individual)",
|
|
"Imported entries are added to the current project (duplicates by name are skipped with a warning)",
|
|
"Imported characters keep their colors; imported variables keep their types and initial values",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 11,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-056, US-057"
|
|
},
|
|
{
|
|
"id": "US-064",
|
|
"title": "Export validation for undefined references",
|
|
"description": "As a user, I want to be warned before exporting if any nodes reference undefined characters or variables so that I can fix issues before generating output.",
|
|
"acceptanceCriteria": [
|
|
"Before export, scan all nodes and edges for characterId/variableId references that don't match defined entries",
|
|
"If issues found, show a warning modal listing: node type, node content snippet, and the undefined reference",
|
|
"Modal offers 'Export anyway' and 'Cancel' options",
|
|
"Nodes with undefined references are highlighted on the canvas with orange warning borders when modal is shown",
|
|
"If no issues found, export proceeds normally",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 12,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-058, US-059, US-060, US-061"
|
|
},
|
|
{
|
|
"id": "US-043",
|
|
"title": "Database schema for collaboration sessions and audit trail",
|
|
"description": "As a developer, I need database tables to track active collaboration sessions and store the full change history for projects.",
|
|
"acceptanceCriteria": [
|
|
"Create migration adding project_collaborators table: id (uuid), project_id (references projects), user_id (references profiles), role ('owner' | 'editor' | 'viewer'), invited_at (timestamptz), accepted_at (timestamptz)",
|
|
"Create collaboration_sessions table: id (uuid), project_id, user_id, cursor_position (jsonb), selected_node_id (text nullable), connected_at (timestamptz), last_heartbeat (timestamptz)",
|
|
"Create audit_trail table: id (uuid), project_id, user_id, action_type (text: 'node_add' | 'node_update' | 'node_delete' | 'edge_add' | 'edge_update' | 'edge_delete'), entity_id (text), previous_state (jsonb), new_state (jsonb), created_at (timestamptz)",
|
|
"Add RLS policies: collaborators can access sessions/audit for projects they belong to",
|
|
"Add index on audit_trail(project_id, created_at) for efficient history queries",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 13,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-045",
|
|
"title": "Supabase Realtime channel and connection management",
|
|
"description": "As a developer, I need a WebSocket connection layer using Supabase Realtime so that clients can exchange presence and change events in real time.",
|
|
"acceptanceCriteria": [
|
|
"Create lib/collaboration/realtime.ts module",
|
|
"On editor mount, join a Supabase Realtime channel scoped to the project ID",
|
|
"Track connection state (connecting, connected, disconnected, reconnecting)",
|
|
"Implement heartbeat mechanism (update last_heartbeat every 30 seconds)",
|
|
"Auto-reconnect on network interruption with exponential backoff",
|
|
"Clean up session record on disconnect/unmount",
|
|
"Show connection status indicator in editor toolbar (green=connected, yellow=reconnecting, red=disconnected)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 14,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-043"
|
|
},
|
|
{
|
|
"id": "US-044",
|
|
"title": "Project sharing and collaborator management",
|
|
"description": "As a project owner, I want to invite other users to collaborate on my project so that we can work together.",
|
|
"acceptanceCriteria": [
|
|
"Add 'Share' button in the editor toolbar",
|
|
"Share modal displays current collaborators with roles (owner/editor/viewer)",
|
|
"Owner can invite users by email with a selected role",
|
|
"Owner can change collaborator roles or remove collaborators",
|
|
"Invited users see shared projects on their dashboard with a 'Shared with me' indicator",
|
|
"RLS policies updated so collaborators can read/write projects based on their role",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 15,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-043"
|
|
},
|
|
{
|
|
"id": "US-046",
|
|
"title": "Presence indicators for active collaborators",
|
|
"description": "As a user, I want to see who else is currently viewing or editing the project so that I am aware of my collaborators.",
|
|
"acceptanceCriteria": [
|
|
"Display a row of avatar circles in the editor toolbar showing connected users",
|
|
"Each avatar shows the user's display_name on hover (tooltip)",
|
|
"Each user is assigned a consistent color (derived from user ID hash)",
|
|
"Avatars appear when users join and disappear when they leave",
|
|
"Maximum 5 avatars shown with '+N' overflow indicator",
|
|
"Own avatar not shown in the list",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 16,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-045"
|
|
},
|
|
{
|
|
"id": "US-048",
|
|
"title": "Integrate Yjs CRDT for conflict-free node/edge synchronization",
|
|
"description": "As a developer, I need to integrate a CRDT library so that concurrent edits from multiple users merge automatically without data loss.",
|
|
"acceptanceCriteria": [
|
|
"Install and configure Yjs with a Supabase-compatible provider (or WebSocket provider)",
|
|
"Create lib/collaboration/crdt.ts module wrapping Yjs document setup",
|
|
"Model flowchart nodes as a Y.Map keyed by node ID",
|
|
"Model flowchart edges as a Y.Map keyed by edge ID",
|
|
"Local React Flow state changes are synced to the Yjs document",
|
|
"Remote Yjs document changes update local React Flow state",
|
|
"Initial load populates Yjs document from database state",
|
|
"Periodic persistence of Yjs document state to Supabase (debounced 2 seconds)",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 17,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-045"
|
|
},
|
|
{
|
|
"id": "US-047",
|
|
"title": "Live cursor positions on canvas",
|
|
"description": "As a user, I want to see other collaborators' cursor positions on the canvas so that I can understand where they are working.",
|
|
"acceptanceCriteria": [
|
|
"Broadcast local cursor position to the Realtime channel (throttled to 50ms)",
|
|
"Render remote cursors as colored arrows/pointers on the canvas with user name labels",
|
|
"Cursor color matches the user's assigned presence color",
|
|
"Remote cursors smoothly interpolate between position updates (no jumping)",
|
|
"Remote cursors fade out after 5 seconds of inactivity",
|
|
"Cursors are rendered in screen coordinates and properly transform with canvas zoom/pan",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 18,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-045, US-046"
|
|
},
|
|
{
|
|
"id": "US-050",
|
|
"title": "Join/leave notifications",
|
|
"description": "As a user, I want to be notified when collaborators join or leave the editing session so that I stay aware of the team's activity.",
|
|
"acceptanceCriteria": [
|
|
"Show a toast notification when a collaborator joins: '[Name] joined'",
|
|
"Show a toast notification when a collaborator leaves: '[Name] left'",
|
|
"Notifications use the collaborator's assigned color as an accent",
|
|
"Notifications auto-dismiss after 3 seconds (matches existing Toast behavior)",
|
|
"No notification shown for own join/leave events",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 19,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-045, US-046"
|
|
},
|
|
{
|
|
"id": "US-049",
|
|
"title": "Node editing lock indicators",
|
|
"description": "As a user, I want to see when another collaborator is actively editing a specific node so that I can avoid conflicts and wait for them to finish.",
|
|
"acceptanceCriteria": [
|
|
"When a user focuses/opens a node for editing, broadcast the node ID to the channel",
|
|
"Nodes being edited by others show a colored border matching the editor's presence color",
|
|
"A small label with the editor's name appears on the locked node",
|
|
"Other users can still view but see a 'Being edited by [name]' indicator if they try to edit",
|
|
"Lock is released when the user clicks away, closes the node, or disconnects",
|
|
"Lock auto-expires after 60 seconds of inactivity as a safety measure",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 20,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-045, US-048"
|
|
},
|
|
{
|
|
"id": "US-051",
|
|
"title": "Audit trail recording",
|
|
"description": "As a developer, I need all node and edge changes to be recorded in the audit trail so that users can review history and revert changes.",
|
|
"acceptanceCriteria": [
|
|
"Every node add/update/delete operation writes a record to audit_trail table",
|
|
"Every edge add/update/delete operation writes a record to audit_trail table",
|
|
"Records include previous_state (null for additions) and new_state (null for deletions)",
|
|
"Records include the acting user's ID and timestamp",
|
|
"Writes are batched/debounced to avoid excessive DB calls (max 1 write per second per entity)",
|
|
"Audit writes do not block the user's editing flow (fire-and-forget with error logging)",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 21,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-043, US-048"
|
|
},
|
|
{
|
|
"id": "US-052",
|
|
"title": "Activity history sidebar",
|
|
"description": "As a user, I want to view a history of all changes made to the project so that I can see what collaborators have done and when.",
|
|
"acceptanceCriteria": [
|
|
"Add 'History' button to editor toolbar that opens a right sidebar panel",
|
|
"Sidebar displays a chronological list of changes with: user name, action type, entity description, timestamp",
|
|
"Entries are grouped by time period (Today, Yesterday, Earlier)",
|
|
"Each entry shows the user's presence color as an accent",
|
|
"Clicking an entry highlights/selects the affected node or edge on the canvas",
|
|
"Paginated loading (20 entries per page) with 'Load more' button",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 22,
|
|
"passes": false,
|
|
"notes": "Dependencies: US-051"
|
|
},
|
|
{
|
|
"id": "US-053",
|
|
"title": "Revert changes from audit trail",
|
|
"description": "As a user, I want to revert a specific change from the history so that I can undo mistakes made by myself or collaborators.",
|
|
"acceptanceCriteria": [
|
|
"Each entry in the activity history sidebar has a 'Revert' button",
|
|
"Clicking 'Revert' shows a confirmation dialog with before/after preview",
|
|
"Reverting a node addition deletes the node",
|
|
"Reverting a node update restores the previous state",
|
|
"Reverting a node deletion re-creates the node with its previous state",
|
|
"Reverting an edge change follows the same add/update/delete logic",
|
|
"The revert itself is recorded as a new audit trail entry",
|
|
"Reverted state is synced to all connected clients via CRDT",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 23,
|
|
<<<<<<< HEAD
|
|
"passes": false,
|
|
"notes": "Dependencies: US-052, US-048"
|
|
=======
|
|
"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": ""
|
|
},
|
|
{
|
|
"id": "US-040",
|
|
"title": "Conditionals on choice options",
|
|
"description": "As a user, I want individual choice options to have variable conditions so that options are only visible when certain conditions are met (e.g., affection > 10).",
|
|
"acceptanceCriteria": [
|
|
"Each ChoiceOption can have optional condition (variableName, operator, value)",
|
|
"Update ChoiceNode UI to show 'Add condition' button per option",
|
|
"Condition editor modal for each option",
|
|
"Visual indicator (icon/badge) on options with conditions",
|
|
"Update TypeScript types: ChoiceOption gets optional condition field",
|
|
"Export includes per-option conditions in Ren'Py JSON",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 40,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-018, US-019, US-025. Complexity: M"
|
|
},
|
|
{
|
|
"id": "US-041",
|
|
"title": "Change password for logged-in user",
|
|
"description": "As a user, I want to change my own password from a settings/profile page so that I can keep my account secure.",
|
|
"acceptanceCriteria": [
|
|
"Settings/profile page accessible from dashboard header",
|
|
"Form with: current password, new password, confirm new password fields",
|
|
"Calls Supabase updateUser with new password",
|
|
"Requires current password verification (re-authenticate)",
|
|
"Shows success/error messages",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 41,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-004. Complexity: S"
|
|
},
|
|
{
|
|
"id": "US-042",
|
|
"title": "Password reset modal on token arrival",
|
|
"description": "As a user, I want a modal to automatically appear when a password reset token is detected so that I can set my new password seamlessly.",
|
|
"acceptanceCriteria": [
|
|
"Detect password reset token in URL (from Supabase email link)",
|
|
"Show modal/dialog automatically when token present",
|
|
"Modal has: new password, confirm password fields",
|
|
"Calls Supabase updateUser with token to complete reset",
|
|
"On success, close modal and redirect to login",
|
|
"On error, show error message",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 42,
|
|
"passes": true,
|
|
"notes": "Dependencies: US-006. Complexity: S"
|
|
>>>>>>> a6a966ce8f445a7ff2c20d92afd65214567eb411
|
|
}
|
|
]
|
|
}
|