Compare commits

..

No commits in common. "3426ed174c9de36d9b676a0fc7cddccbad2cd558" and "4322f3cf634bf89dd1fa78f253e675178c05bbc5" have entirely different histories.

35 changed files with 24413 additions and 64 deletions

99
QUICKSTART.md Normal file
View file

@ -0,0 +1,99 @@
# Quick Start Guide - Constellation Analyzer
## Get Started in 2 Minutes
### 1. Install & Run
```bash
npm install
npm run dev
```
The application will open automatically at **http://localhost:3000**
### 2. Create Your First Constellation
#### Add Actors (Nodes)
1. Click any colored button in the toolbar:
- **Person** (Blue) - Individual people
- **Organization** (Green) - Companies or groups
- **System** (Orange) - Technical systems
- **Concept** (Purple) - Abstract ideas
2. Nodes appear on the canvas - drag them to position
#### Create Relations (Edges)
1. Click and hold on any colored dot (handle) on a node
2. Drag your cursor to another node's handle
3. Release to create a connection
4. The edge appears automatically
#### Edit Your Graph
- **Move nodes**: Click and drag anywhere on the node
- **Delete node**: Click to select, press Delete or Backspace
- **Delete edge**: Click the edge, press Delete or Backspace
- **Pan canvas**: Click and drag on empty space
- **Zoom**: Use mouse wheel or trackpad
- **Clear all**: Click "Clear Graph" button (with confirmation)
### 3. Navigation
- **Controls** (bottom-left corner):
- Zoom in/out buttons
- Fit view button
- Lock/unlock button
- **MiniMap** (bottom-right corner):
- Overview of entire graph
- Click to navigate
- Drag viewport rectangle
### 4. Available Commands
```bash
# Development
npm run dev # Start dev server (http://localhost:3000)
npm run build # Build for production
npm run preview # Preview production build
npm run lint # Run ESLint
# Git
git status # Check current changes
git add . # Stage all changes
git commit -m "msg" # Commit changes
```
## Example: Simple Organization Chart
1. Add a "Person" node (CEO)
2. Add three more "Person" nodes (Managers)
3. Create edges from CEO to each Manager
4. Add "Organization" nodes (Departments)
5. Connect Managers to their Departments
6. Arrange nodes in hierarchy
## Tips
- Use the handles on all four sides of nodes for flexible connections
- Different edge types have different visual styles (solid, dashed, dotted)
- The graph auto-saves in the browser session (lost on page refresh)
- Select multiple nodes by clicking them while dragging
## Next Steps
- Read the full **README.md** for detailed documentation
- Check **PROJECT_SUMMARY.md** for architecture details
- Explore the **src/** folder to understand the code structure
- Start customizing node/edge types in **src/stores/graphStore.ts**
## Need Help?
- Documentation: See README.md
- Architecture: See PROJECT_SUMMARY.md
- Project guidance: See CLAUDE.md
- Issues: Open an issue on the repository
---
**Built with**: React + TypeScript + React Flow + Zustand + Tailwind CSS + Vite
Happy analyzing!

325
README.md
View file

@ -1,89 +1,312 @@
# Constellation Analyzer
A React-based visual editor for Constellation Analysis — mapping actors (nodes) and their relationships (edges) in an interactive graph.
A React-based visual editor for creating and analyzing Constellation Analyses. Build interactive graphs to examine actors (nodes) and their relationships (edges) with a powerful drag-and-drop interface.
> **Vibe-Warning**: This is a testing ground for agent-based LLM coding. The codebase contains no hand-written code. Take it with a grain of salt.
## Vibe-Warning
This is a testing ground for Agent Based LLM Coding. It presently does not contain hand-written code. Hence, please take the whole code-base with a grain of salt.
## Features
- **Multi-document workspace** — open multiple analyses in tabs, persist to localStorage
- **Graph editor** — drag-and-drop actors and relations with custom types, shapes, colors, and directionality
- **Groups** — cluster actors into named, collapsible groups
- **Timeline / States** — branching constellation states within a document (parallel scenarios or time evolution)
- **Presentation mode** — fullscreen view with timeline overlay for presenting analyses
- **Undo / Redo** — per-document history with operation descriptions
- **Bibliography** — citation management via Citation.js (BibTeX, RIS, DOI, CSL)
- **TUIO integration** — tangible token support over WebSocket/OSC for physical interaction
- **Export** — PNG, SVG, JSON (document), ZIP (workspace)
- **Search & filters** — filter graph by actor type, relation type, or label
- **Interactive Graph Visualization**: Built on React Flow for smooth, performant graph editing
- **Customizable Node Types**: Define and configure multiple actor types with distinct visual properties
- **Flexible Edge Types**: Create various relationship categories with different styles and colors
- **Drag-and-Drop Interface**: Intuitive node manipulation and edge creation
- **Real-time Updates**: Instant visual feedback as you build your constellation
- **Type-Safe**: Full TypeScript support for robust development
- **State Management**: Zustand for lightweight, efficient state handling
- **Responsive Design**: Tailwind CSS for modern, adaptive UI
## Tech Stack
## Technology Stack
| | |
|---|---|
| Framework | React 18.2, TypeScript 5.2, Vite 5.1 |
| Graph | @xyflow/react 12.3 |
| State | Zustand 4.5 |
| UI | MUI 5.15, Tailwind CSS 3.4 |
| Bibliography | Citation.js 0.7 |
| TUIO | tuio-client 0.1, osc-js 2.4 |
| Testing | Vitest 3.2, Testing Library 16.3 |
- **React 18.2** - UI framework
- **TypeScript 5.2** - Type safety
- **Vite 5.1** - Build tool and dev server
- **React Flow 11.11** - Graph visualization library
- **Zustand 4.5** - State management
- **Tailwind CSS 3.4** - Styling framework
## Getting Started
### Prerequisites
- Node.js 20.x or higher
- npm 9.x or higher
### Installation
```bash
# Install dependencies
npm install
npm run dev # http://localhost:3000
```
### Development
```bash
# Start development server (opens at http://localhost:3000)
npm run dev
```
### Build
```bash
# Build for production
npm run build
# Preview production build
npm run preview
```
### Lint
```bash
# Run ESLint
npm run lint
npm test
```
## Project Structure
```
src/
├── components/
│ ├── Config/ # Node/edge/tangible/bibliography config dialogs
│ ├── Editor/ # Main graph editor (GraphEditor.tsx)
│ ├── Edges/ # Custom edge renderers
│ ├── Menu/ # Menu bar (File, Edit, View, Help)
│ ├── Nodes/ # CustomNode, GroupNode, shape renderers
│ ├── Panels/ # Left/right side panels, property editors
│ ├── Presentation/ # Fullscreen presentation overlay
│ ├── Timeline/ # Timeline/states UI
│ └── Workspace/ # Document tabs and document manager
├── hooks/ # useGraphWithHistory, useDocumentHistory, useTuioIntegration, …
├── stores/ # Zustand stores (graph, timeline, workspace, history, bibliography, tuio, …)
├── types/ # TypeScript definitions
└── utils/ # Export, graph analysis, bibliography parsing, migrations
constellation-analyzer/
├── src/
│ ├── components/ # React components
│ │ ├── Editor/ # Main graph editor
│ │ │ └── GraphEditor.tsx
│ │ ├── Nodes/ # Custom node components
│ │ │ └── CustomNode.tsx
│ │ ├── Edges/ # Custom edge components
│ │ │ └── CustomEdge.tsx
│ │ └── Toolbar/ # Editor controls
│ │ └── Toolbar.tsx
│ ├── stores/ # Zustand state stores
│ │ ├── graphStore.ts # Graph state (nodes, edges, types)
│ │ └── editorStore.ts # Editor settings
│ ├── types/ # TypeScript definitions
│ │ └── index.ts
│ ├── utils/ # Utility functions
│ │ ├── nodeUtils.ts
│ │ └── edgeUtils.ts
│ ├── styles/ # Global styles
│ │ └── index.css
│ ├── App.tsx # Root component
│ ├── main.tsx # Entry point
│ └── vite-env.d.ts # Vite types
├── public/ # Static assets
├── index.html # HTML template
├── package.json # Dependencies
├── tsconfig.json # TypeScript config
├── vite.config.ts # Vite config
├── tailwind.config.js # Tailwind config
└── README.md # This file
```
## Usage
### Adding Actors (Nodes)
1. Click any of the actor type buttons in the toolbar (Person, Organization, System, Concept)
2. A new node will appear on the canvas
3. Drag the node to position it
### Creating Relations (Edges)
1. Click and drag from any colored handle (circle) on a node
2. Release over a handle on another node to create a connection
3. The edge will automatically appear with default styling
### Deleting Elements
- **Delete Node**: Select a node and press `Delete` or `Backspace`
- **Delete Edge**: Select an edge and press `Delete` or `Backspace`
### Navigation
- **Pan**: Click and drag on empty canvas space
- **Zoom**: Use mouse wheel or pinch gesture
- **Fit View**: Use the controls in bottom-left corner
- **MiniMap**: View overview and navigate in bottom-right corner
## Core Concepts
### Actors (Nodes)
Actors represent entities in your analysis. Each actor has:
- **Type**: Category (person, organization, system, concept)
- **Label**: Display name
- **Description**: Optional details
- **Position**: X/Y coordinates on canvas
- **Metadata**: Custom properties
### Relations (Edges)
Relations connect actors to show relationships. Each relation has:
- **Type**: Category (collaborates, reports-to, depends-on, influences)
- **Label**: Optional description
- **Style**: Visual representation (solid, dashed, dotted)
- **Source/Target**: Connected actors
### Node Types
Pre-configured actor categories:
- **Person**: Individual (Blue)
- **Organization**: Company/group (Green)
- **System**: Technical system (Orange)
- **Concept**: Abstract idea (Purple)
### Edge Types
Pre-configured relationship categories:
- **Collaborates**: Working together (Blue, solid)
- **Reports To**: Hierarchical (Green, solid)
- **Depends On**: Dependency (Orange, dashed)
- **Influences**: Impact (Purple, dotted)
## Customization
### Adding New Node Types
Edit `/src/stores/graphStore.ts`:
```typescript
const defaultNodeTypes: NodeTypeConfig[] = [
// Add your custom type
{
id: 'custom-type',
label: 'Custom Type',
color: '#ff6b6b',
description: 'My custom actor type'
},
];
```
### Adding New Edge Types
Edit `/src/stores/graphStore.ts`:
```typescript
const defaultEdgeTypes: EdgeTypeConfig[] = [
// Add your custom type
{
id: 'custom-relation',
label: 'Custom Relation',
color: '#ff6b6b',
style: 'solid'
},
];
```
## Architecture Decisions
### Why React Flow?
- React-native components for seamless integration
- Excellent performance with large graphs
- Rich API for customization
- Active community and maintenance
### Why Zustand?
- Lightweight (< 1KB)
- Simple, hook-based API
- No boilerplate compared to Redux
- Perfect for graph state management
### Why Vite?
- Lightning-fast HMR (Hot Module Replacement)
- Modern build tool with ES modules
- Optimized production builds
- Better DX than Create React App
### Why Tailwind CSS?
- Rapid UI development
- Consistent design system
- Small production bundle (unused classes purged)
- Easy responsive design
## Development Guidelines
### Graph Mutations — Always Use `useGraphWithHistory`
### ⚠️ Important: Always Use History-Tracked Operations
When modifying graph state in components, **always use `useGraphWithHistory()`** instead of `useGraphStore()` directly:
```typescript
// ✅ Correct — history tracked, undo/redo works
// ✅ CORRECT: Uses history tracking (enables undo/redo)
import { useGraphWithHistory } from '../../hooks/useGraphWithHistory';
const { addNode, updateNode, deleteNode, addEdge, ... } = useGraphWithHistory();
// ❌ Wrong — bypasses history
function MyComponent() {
const { addNode, updateNode, deleteNode } = useGraphWithHistory();
const handleAddNode = () => {
addNode(newNode); // Automatically tracked in history
};
}
```
```typescript
// ❌ WRONG: Bypasses history (undo/redo won't work)
import { useGraphStore } from '../../stores/graphStore';
function MyComponent() {
const graphStore = useGraphStore();
const handleAddNode = () => {
graphStore.addNode(newNode); // History not tracked!
};
}
```
Read-only access in display components (CustomNode, CustomEdge) can use `useGraphStore` directly.
**Exception**: Read-only access in presentation components (CustomNode, CustomEdge) is acceptable since it doesn't modify state.
### Tests
### History-Tracked Operations
```bash
npm run test:unit # Store unit tests (src/stores/*.test.ts)
npm run test:integration # Integration tests (src/__tests__/integration/)
npm test # All tests
```
All these operations automatically create undo/redo history entries:
- Node operations: `addNode`, `updateNode`, `deleteNode`
- Edge operations: `addEdge`, `updateEdge`, `deleteEdge`
- Type operations: `addNodeType`, `updateNodeType`, `deleteNodeType`, `addEdgeType`, `updateEdgeType`, `deleteEdgeType`
- Utility: `clearGraph`
Always update tests when modifying store logic. See `CLAUDE.md` for testing patterns.
See `src/hooks/useGraphWithHistory.ts` for complete documentation.
## Next Steps
### Suggested Enhancements
1. **Data Persistence**
- Save/load graphs to/from JSON
- Local storage integration
- Export to PNG/SVG
2. **Advanced Editing**
- Multi-select nodes
- Copy/paste functionality
- ✅ Undo/redo history (implemented - per-document with 50 action limit)
3. **Node/Edge Properties Panel**
- Edit labels and descriptions
- Change types dynamically
- Add custom metadata
4. **Layout Algorithms**
- Auto-arrange nodes
- Hierarchical layout
- Force-directed layout
5. **Analysis Tools**
- Calculate graph metrics
- Find shortest paths
- Identify clusters
6. **Collaboration**
- Real-time multi-user editing
- Version control
- Comments and annotations
## Contributing
This is a new project. Contributions are welcome!
## License
MIT
## Support
For issues and questions, please open an issue on the repository.

1477
docs/ARCHITECTURE_REVIEW.md Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,791 @@
# Directional Relationships - UX Design Specification
## Executive Summary
This document outlines the UX design for implementing directional relationships in Constellation Analyzer. The design focuses on providing clear visual feedback, intuitive controls, and minimal friction for users working with directed, bidirectional, and undirected relationships.
---
## 1. Visual Representation on Graph Canvas
### 1.1 Arrow Marker Styles
**Directed Relationships (A → B)**
- Single arrowhead at target end
- Standard SVG marker with solid fill matching edge color
- Marker size: 8x8px (scales with zoom but maintains readability)
- Positioned 6px from target node edge to prevent overlap
**Bidirectional Relationships (A ↔ B)**
- Arrowheads at both source and target ends
- Same styling as directed arrows
- Both markers use same color as edge
**Undirected Relationships (A — B)**
- No arrow markers
- Edge styling unchanged from current implementation
- Visual distinction through absence of markers
### 1.2 Edge Rendering Implementation
**Current State:** React Flow's BaseEdge with Bezier curves
**Enhancement:** Add markerStart and markerEnd attributes to SVG path
```typescript
// Marker definitions in SVG defs
<defs>
<marker id="arrow-{edgeColor}" viewBox="0 0 10 10"
refX="8" refY="5" markerWidth="8" markerHeight="8"
orient="auto" fill="{edgeColor}">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
// Applied to edge path
markerEnd: directionality === 'directed' || directionality === 'bidirectional'
? `url(#arrow-${edgeColor})` : undefined
markerStart: directionality === 'bidirectional'
? `url(#arrow-${edgeColor})` : undefined
```
### 1.3 Visual Feedback During Edge Creation
When user drags to create a new edge:
- Show preview with arrow based on default directionality for selected relation type
- Connection line includes appropriate markers in real-time
- Provides immediate feedback about relationship direction
---
## 2. Property Panel Controls
### 2.1 Layout Structure (Edge Properties View)
**Current Layout:**
```
[Relation Type] ← dropdown
[Custom Label] ← text input
[Connection Info] ← From/To display
[Delete Button] ← action button
```
**Enhanced Layout:**
```
[Relation Type] ← dropdown
[Custom Label] ← text input (optional)
--- NEW SECTION ---
[Directionality] ← segmented button group (3 options)
[Direction Controls] ← conditional: show reverse button for directed
--- END NEW ---
[Connection Info] ← From/To display with enhanced directionality info
[Delete Button] ← action button
```
### 2.2 Directionality Control Component
**Component Type:** MUI ToggleButtonGroup (segmented control)
**Visual Design:**
```
┌──────────────────────────────────────────────┐
│ Directionality │
│ ┌────────┬─────────────┬──────────────┐ │
│ │ → │ ↔ │ — │ │
│ │Directed│Bidirectional│ Undirected │ │
│ └────────┴─────────────┴──────────────┘ │
└──────────────────────────────────────────────┘
```
**States:**
- Active: Blue background (#2196F3), white icon/text
- Inactive: White background, gray text (#666)
- Hover: Light gray background (#F5F5F5)
**Accessibility:**
- ARIA labels: "Directed relationship", "Bidirectional relationship", "Undirected relationship"
- Keyboard navigation: Tab to focus, arrow keys to change selection
- Screen reader announces: "Directionality, {current selection}"
### 2.3 Reverse Direction Control
**Display Condition:** Only shown when directionality = "directed"
**Component Type:** IconButton with swap arrow icon
**Visual Design:**
```
┌──────────────────────────────────────────────┐
│ Direction │
│ ┌──────────────────────────────────────┐ │
│ │ [Actor A] → [Actor B] [⇄] │ │
│ └──────────────────────────────────────┘ │
│ "Swap source and target" │
└──────────────────────────────────────────────┘
```
**Behavior:**
- Click to swap source and target
- Triggers smooth animation on canvas (optional enhancement)
- Updates connection info display immediately
- Adds to undo/redo history as "Reverse Relation Direction"
**Accessibility:**
- ARIA label: "Reverse direction, swap source and target"
- Tooltip: "Reverse Direction (R)" - includes keyboard shortcut
- Keyboard shortcut: R (when edge selected)
### 2.4 Enhanced Connection Info Display
**Current Display:**
```
Connection Info
From: actor-1
To: actor-2
```
**Enhanced Display:**
```
┌──────────────────────────────────────────────┐
│ Connection │
│ │
│ [Actor A] → [Actor B] [Reverse ⇄] │
│ │
│ Source: Actor A │
│ Target: Actor B │
└──────────────────────────────────────────────┘
```
For bidirectional:
```
│ [Actor A] ↔ [Actor B] │
```
For undirected:
```
│ [Actor A] — [Actor B] │
```
**Visual Enhancements:**
- Actor names are actual labels, not IDs
- Visual arrow indicator matches canvas representation
- Color-coded background for actor badges matching node type colors
---
## 3. Interaction Patterns
### 3.1 Setting Directionality
**Primary Flow:**
1. User selects an edge (click on edge)
2. Right panel opens showing edge properties
3. User clicks appropriate directionality button
4. Change applies immediately (debounced 500ms for history)
5. Canvas updates arrow markers in real-time
6. No "Save" button needed (live updates)
**Default Behavior:**
- New edges inherit default directionality from edge type config
- If not specified, default to "directed"
### 3.2 Reversing Direction
**Flow:**
1. User has directed edge selected
2. User clicks reverse button (or presses R key)
3. Source and target swap in state
4. Canvas updates immediately
5. Connection info display updates
6. Action added to undo/redo history
**Visual Feedback:**
- Brief highlight animation on edge (optional)
- Reverse button shows brief "pressed" state
- Toast notification: "Direction reversed" (optional, may be too noisy)
### 3.3 Keyboard Shortcuts
**New Shortcuts:**
- `D` - Set selected edge to Directed
- `B` - Set selected edge to Bidirectional
- `U` - Set selected edge to Undirected
- `R` - Reverse direction (directed edges only)
**Shortcut Display:**
- Add to keyboard shortcuts help dialog
- Show in tooltips for directionality buttons
- Disabled state when no edge selected
### 3.4 Bulk Operations (Future Enhancement)
When multiple edges selected:
- Directionality controls affect all selected edges
- Reverse button reverses all directed edges
- Confirmation dialog for bulk changes (>3 edges)
---
## 4. Edge Type Defaults
### 4.1 Data Model Extension
**Current EdgeTypeConfig:**
```typescript
interface EdgeTypeConfig {
id: string;
label: string;
color: string;
style?: 'solid' | 'dashed' | 'dotted';
description?: string;
}
```
**Enhanced EdgeTypeConfig:**
```typescript
interface EdgeTypeConfig {
id: string;
label: string;
color: string;
style?: 'solid' | 'dashed' | 'dotted';
description?: string;
defaultDirectionality?: 'directed' | 'bidirectional' | 'undirected';
}
```
### 4.2 Edge Type Manager UI Enhancement
**Location:** Left Panel > Manage Edge Types dialog
**Addition to Edge Type Form:**
```
┌──────────────────────────────────────────────┐
│ Default Directionality │
│ ┌────────┬─────────────┬──────────────┐ │
│ │ → │ ↔ │ — │ │
│ │Directed│Bidirectional│ Undirected │ │
│ └────────┴─────────────┴──────────────┘ │
│ │
│ New relations of this type will use this │
│ directionality by default │
└──────────────────────────────────────────────┘
```
**Recommended Defaults:**
- "influences" → Directed
- "collaborates" → Bidirectional
- "related to" → Undirected
- "reports to" → Directed
- "partners with" → Bidirectional
### 4.3 Smart Defaults Based on Type Name
System can suggest defaults based on relation type label:
- Words like "leads", "manages", "influences" → Directed
- Words like "collaborates", "partners", "exchanges" → Bidirectional
- Words like "related", "associated", "connected" → Undirected
Display suggestion in UI: "Suggested: Directed (based on type name)"
---
## 5. Information Display
### 5.1 Edge Label Display on Canvas
**Current:** Shows custom label or type label in white box at edge midpoint
**Enhancement:** Add directional indicator in label (optional)
```
┌─────────────────┐
│ influences → │ ← directed
└─────────────────┘
┌─────────────────┐
│ collaborates ↔ │ ← bidirectional
└─────────────────┘
┌─────────────────┐
│ related to │ ← undirected (no indicator)
└─────────────────┘
```
**Implementation Note:** This is subtle and optional - arrows on edge path may be sufficient.
### 5.2 Connection List (Actor Properties)
**Location:** Right Panel > Actor Properties > Connections section
**Current Display:**
```
Connections (3)
• influences → actor-2
• collaborates ← actor-3
• related to → actor-4
```
**Enhanced Display:**
```
┌──────────────────────────────────────────┐
│ Connections (3) │
│ │
│ → influences Developer B │
│ Directed outgoing │
│ │
│ ↔ collaborates with Manager A │
│ Bidirectional │
│ │
│ — related to Stakeholder C │
│ Undirected │
└──────────────────────────────────────────┘
```
**Visual Elements:**
- Leading icon shows directionality type
- Text indicates direction relative to selected node
- Subtle background color per relation type
- Click to select that edge
### 5.3 Graph Metrics Panel
**Location:** Right Panel (when nothing selected)
**Addition to Metrics:**
```
┌──────────────────────────────────────────┐
│ Graph Analysis │
│ │
│ Relations │
│ • Total: 15 │
│ • Directed: 8 (53%) │
│ • Bidirectional: 5 (33%) │
│ • Undirected: 2 (14%) │
│ │
│ [existing metrics...] │
└──────────────────────────────────────────┘
```
---
## 6. User Feedback Mechanisms
### 6.1 Visual Feedback States
**Edge Selection:**
- Selected edge: Thicker stroke (3px → 4px)
- Selected edge with directionality: Arrows slightly larger
- Hover: Subtle glow effect (box-shadow)
**Property Panel:**
- Active directionality button: Blue background with animation
- Saving indicator: "Saving changes..." (existing pattern)
- Success: No notification (silent success for live updates)
### 6.2 Status Indicators
**Edge Creation:**
- As user drags from node handle, preview edge shows default directionality
- Tooltip near cursor: "Creating [EdgeType] relation →"
**Edge Modification:**
- Undo toast: "Changed to bidirectional" with undo link
- Error states: "Cannot reverse undirected relation" (if user attempts)
### 6.3 Help Text
**Property Panel Help:**
- Directionality section includes info icon ()
- Click shows tooltip: "Set how this relationship flows between actors. Directed flows one way, bidirectional flows both ways, and undirected has no specific direction."
**First-Time User Experience:**
- When user creates first edge, show brief highlight on directionality control
- Optional: One-time tooltip "Choose relationship direction"
---
## 7. Accessibility Considerations
### 7.1 Screen Reader Support
**Edge Selection:**
```
"Relation selected: influences, directed from Actor A to Actor B"
```
**Directionality Change:**
```
"Directionality changed to bidirectional. Relation now flows both ways between Actor A and Actor B"
```
**Reverse Action:**
```
"Direction reversed. Relation now flows from Actor B to Actor A"
```
### 7.2 Keyboard Navigation
**Tab Order in Properties Panel:**
1. Relation Type dropdown
2. Custom Label input
3. Directionality toggle group (arrow keys to change)
4. Reverse button (if directed)
5. Delete button
**Focus Indicators:**
- Clear blue outline (2px) on focused elements
- Toggle buttons show focus state distinct from selection
### 7.3 Color Contrast
**Arrow Markers:**
- Maintain sufficient contrast against canvas background
- Minimum 3:1 contrast ratio for graphical objects (WCAG 2.1)
- Consider edge color when rendering markers
**Controls:**
- Active state: Blue (#2196F3) on white - 4.5:1 ratio ✓
- Inactive state: Gray (#666) on white - 5.7:1 ratio ✓
### 7.4 Visual Indicators Beyond Color
**Directionality not solely dependent on color:**
- Arrow shape conveys meaning
- Text labels supplement visual indicators
- Icon + text in toggle buttons
---
## 8. Implementation Priority
### Phase 1: Core Functionality (MVP)
1. Add directionality field to RelationData type
2. Implement arrow markers on canvas (CustomEdge component)
3. Add directionality toggle in property panel
4. Update edge creation to use default directionality
**User Value:** Basic directional relationships working end-to-end
### Phase 2: Enhanced Controls
1. Add reverse direction button
2. Implement keyboard shortcuts (D, B, U, R)
3. Add defaultDirectionality to EdgeTypeConfig
4. Update Edge Type Manager with default setting
**User Value:** Efficient editing and sensible defaults
### Phase 3: Visual Polish
1. Enhanced connection info display with visual indicators
2. Update connections list in actor properties
3. Add directionality breakdown to graph metrics
4. Improve arrow marker styling (size, positioning)
**User Value:** Better information display and understanding
### Phase 4: Advanced Features
1. Bulk directionality operations
2. Smart default suggestions based on type name
3. Visual animations for direction changes
4. Export/import with directionality data
**User Value:** Advanced workflows and refinements
---
## 9. Edge Cases & Error Handling
### 9.1 Self-Referencing Edges
**Issue:** Edge where source === target
**Solution:**
- Allow all directionality types
- Render with loop path (React Flow built-in)
- Arrow direction still meaningful (self-influence)
### 9.2 Duplicate Edges
**Issue:** Multiple edges between same two nodes
**Current:** Already supported (different edge IDs)
**Enhancement:**
- Visual offset for parallel edges (React Flow handles)
- Directionality independent per edge
- Example: A → B (influences) and A ← B (reports to) both valid
### 9.3 Migration of Existing Data
**Issue:** Existing edges have no directionality field
**Solution:**
```typescript
// Default to 'directed' for backwards compatibility
const directionality = edge.data?.directionality || 'directed';
```
**Migration Script (optional):**
- Add directionality field to all existing edges
- Set based on edge type default if available
- Otherwise, default to 'directed'
### 9.4 Invalid States
**Prevention:**
- TypeScript types enforce valid directionality values
- Toggle group only allows 3 options
- Reverse button disabled for non-directed edges
### 9.5 Performance Considerations
**Arrow Markers:**
- Create marker definitions once in SVG defs
- Reference by ID (efficient SVG pattern)
- One marker definition per color (shared across edges)
**Rendering:**
- React Flow handles efficient re-rendering
- Memo CustomEdge component (already implemented)
- No performance impact expected
---
## 10. Testing Checklist
### 10.1 Functional Tests
- [ ] Create directed edge, verify arrow at target
- [ ] Create bidirectional edge, verify arrows at both ends
- [ ] Create undirected edge, verify no arrows
- [ ] Change directionality via toggle buttons
- [ ] Reverse direction, verify source/target swap
- [ ] Edge type default directionality applies to new edges
- [ ] Keyboard shortcuts work (D, B, U, R)
- [ ] Undo/redo preserves directionality changes
- [ ] Export/import preserves directionality data
### 10.2 Visual Tests
- [ ] Arrows render at correct size and position
- [ ] Arrow color matches edge color
- [ ] Selected edge shows enhanced visual feedback
- [ ] Connection info display shows correct arrows
- [ ] Graph metrics show directionality breakdown
- [ ] Edge labels (optional arrows) display correctly
### 10.3 Accessibility Tests
- [ ] Screen reader announces directionality
- [ ] Keyboard navigation through controls works
- [ ] Focus indicators visible on all interactive elements
- [ ] Color contrast meets WCAG 2.1 AA
- [ ] Arrow markers distinguishable without color
### 10.4 Edge Cases
- [ ] Self-referencing edges render correctly
- [ ] Multiple edges between same nodes work
- [ ] Existing data without directionality field loads
- [ ] Very long edge labels don't break layout
- [ ] Rapid directionality changes don't cause issues
---
## 11. User Documentation
### 11.1 Help Dialog Addition
**Section: Editing Relations**
```
Relationship Direction
Constellation Analyzer supports three types of relationship directionality:
• Directed (→): One-way relationships that flow from source to target
Example: "Actor A influences Actor B"
• Bidirectional (↔): Two-way relationships that flow in both directions
Example: "Actor A collaborates with Actor B"
• Undirected (—): Relationships without a specific direction
Example: "Actor A is related to Actor B"
To set directionality:
1. Select a relation on the canvas
2. In the properties panel, choose the directionality type
3. For directed relations, use the Reverse button to swap direction
Keyboard Shortcuts:
D - Set to Directed
B - Set to Bidirectional
U - Set to Undirected
R - Reverse direction
```
### 11.2 Tooltips
**Property Panel:**
- Directionality info icon: "Control how this relationship flows between actors"
- Reverse button: "Reverse Direction (R) - Swap source and target actors"
- Directed button: "Directed (D) - One-way relationship"
- Bidirectional button: "Bidirectional (B) - Two-way relationship"
- Undirected button: "Undirected (U) - No specific direction"
---
## 12. Design Rationale
### 12.1 Why Segmented Control for Directionality?
**Decision:** Use MUI ToggleButtonGroup instead of dropdown or radio buttons
**Rationale:**
- Visual representation of options (icons + labels)
- Common pattern for mutually exclusive choices
- Faster interaction than dropdown (no need to open/close)
- Icons provide immediate recognition (→, ↔, —)
- Fits well within panel width constraints (~320px)
### 12.2 Why Inline Reverse Button?
**Decision:** Place reverse button next to connection info, not in separate section
**Rationale:**
- Contextual to the information being reversed
- Common pattern (Gmail's "Swap" button in email composition)
- Doesn't clutter the main directionality control
- Only appears when relevant (directed edges)
- Visual proximity to source/target display reinforces what it does
### 12.3 Why Live Updates Instead of Save Button?
**Decision:** Maintain existing pattern of live property updates
**Rationale:**
- Consistency with existing edge/node property editing
- Reduces friction (fewer clicks)
- Undo/redo provides safety net for mistakes
- Modern pattern (Google Docs, Figma, etc.)
- Debounced updates prevent history spam
### 12.4 Why Default to Directed?
**Decision:** Default new edges to "directed" when no type default specified
**Rationale:**
- Most common use case in constellation analyses
- Directionality is often meaningful (influence, reports to, etc.)
- Easy to change to bidirectional or undirected if needed
- Backwards compatible with existing mental models
- Forces users to think about relationship direction
### 12.5 Why Show Arrows on Canvas?
**Decision:** Use arrow markers instead of subtle visual indicators
**Rationale:**
- Immediately clear and unambiguous
- Standard graph visualization convention
- Works at all zoom levels
- No learning curve (universal symbol)
- Screen reader compatible (can be described)
---
## 13. Future Enhancements
### 13.1 Conditional Directionality
**Concept:** Directionality that changes based on context or time
**Example:** "influences" might be bidirectional in some scenarios, directed in others
**UI Addition:** "Conditional" option with rule builder
**Priority:** Low (advanced use case)
### 13.2 Weighted Directionality
**Concept:** Different strengths for each direction in bidirectional relationships
**Example:** A → B (strong), B → A (weak) shown as thicker/thinner arrows
**UI Addition:** Slider controls for each direction strength
**Priority:** Medium (useful for advanced analysis)
### 13.3 Visual Edge Routing
**Concept:** Curved paths that better indicate directionality
**Example:** Arcing paths that visually "flow" from source to target
**Implementation:** Custom edge routing algorithm
**Priority:** Low (aesthetic improvement)
### 13.4 Directional Filtering
**Concept:** Filter graph to show only certain directionality types
**Example:** "Show only bidirectional relationships"
**UI Location:** Toolbar filter dropdown
**Priority:** Medium (useful for large graphs)
### 13.5 Directional Analytics
**Concept:** Advanced metrics based on relationship direction
**Example:**
- Actors with most incoming directed edges (influenced by many)
- Actors with most outgoing directed edges (influence many)
- Bidirectional relationship clusters
**UI Location:** Graph Metrics panel, new "Directional Analysis" section
**Priority:** Medium (valuable for analysis)
---
## Files to Modify
### TypeScript Types
- `/home/jbruhn/dev/constellation-analyzer/src/types/index.ts`
- Add `directionality` field to `RelationData`
- Add `defaultDirectionality` field to `EdgeTypeConfig`
### Components
- `/home/jbruhn/dev/constellation-analyzer/src/components/Edges/CustomEdge.tsx`
- Add arrow marker rendering logic
- Handle directionality prop
- `/home/jbruhn/dev/constellation-analyzer/src/components/Panels/RightPanel.tsx`
- Add directionality toggle group
- Add reverse direction button
- Update connection info display
### Stores
- Store files (need to verify exact location)
- Add directionality handling in edge operations
### Utilities
- Edge creation utilities
- Apply default directionality from edge type config
---
## Conclusion
This UX specification provides a comprehensive, user-centered approach to implementing directional relationships in Constellation Analyzer. The design prioritizes:
1. **Clarity**: Visual arrows and clear controls make directionality obvious
2. **Efficiency**: Keyboard shortcuts and live updates reduce friction
3. **Consistency**: Follows existing MUI-based design patterns
4. **Accessibility**: Screen reader support and keyboard navigation throughout
5. **Flexibility**: Supports all three directionality modes with sensible defaults
The phased implementation approach allows for incremental delivery of value while maintaining code quality and user experience standards.

View file

@ -0,0 +1,610 @@
# Edge Overlap UX Design Proposal
## Constellation Analyzer - Handling Overlapping Edges
**Date:** 2026-02-05
**Status:** Proposal
**Problem:** When multiple relations exist between the same two nodes, or when edges cross each other, they overlap and become difficult to distinguish, select, or understand.
---
## Current Implementation Analysis
### What We Have
The codebase uses **@xyflow/react** (React Flow v12) with custom edge rendering:
1. **CustomEdge component** (`src/components/Edges/CustomEdge.tsx`)
- Renders edges as cubic Bezier curves
- Uses `getFloatingEdgeParams()` for calculating intersection points with various node shapes
- Supports directional arrows (directed, bidirectional, undirected)
- Shows edge labels with type indicators and custom text
- Implements visual filtering with opacity changes
2. **Edge Routing** (`src/utils/edgeUtils.ts`)
- Smart shape-aware intersection calculation (circle, ellipse, pill, rounded rectangle)
- Bezier curves with control points at 40% of inter-node distance
- Single path between any two nodes - no multi-edge handling
3. **Edge Aggregation for Groups**
- When groups are minimized, multiple internal edges are aggregated into a single edge
- Shows count badge (e.g., "5 relations")
- Uses neutral gray color for aggregated edges
### Current Gaps
- **No offset for parallel edges**: Multiple edges between same nodes overlap completely
- **No edge crossing detection**: Edges can cross over each other with no visual differentiation
- **Selection challenges**: Overlapping edges are hard to click/select
- **Visual clutter**: Dense graphs become illegible with many crossing edges
---
## Research: Best Practices for Edge Overlap
### Industry Standards
1. **Dagre/Graphviz Approach**
- Hierarchical edge routing with splines
- Edge bundling for crossing edges
- Used by: Mermaid, PlantUML
2. **Force-Directed Graphs (D3, Cytoscape)**
- Physics-based layout to minimize crossings
- Edge bundling for hierarchical structures
- Used by: Neo4j Browser, Gephi
3. **Network Diagram Tools (Draw.io, Lucidchart)**
- Manual routing with waypoints
- Orthogonal connectors (90-degree angles)
- Automatic routing around obstacles
4. **React Flow Patterns**
- Edge offset for parallel edges
- Custom edge components with hover states
- Edge label positioning to avoid overlap
### User Expectations from Similar Tools
**Graph Databases (Neo4j, ArangoDB)**
- Clear visual separation between parallel edges
- Interactive hover to highlight connection paths
- Edge bundling for many-to-many relationships
**Diagramming Tools (Miro, FigJam)**
- Smooth bezier curves with collision avoidance
- Hover states that bring edges to front
- Smart label positioning
**Network Analysis (Gephi, Cytoscape)**
- Edge bundling for dense areas
- Opacity/width to show edge importance
- Interactive filtering to reduce visual noise
---
## Design Solution 1: Parallel Edge Offset (Recommended)
### Visual Approach
**Offset parallel edges** with curved paths that arc away from the center line between nodes.
#### Implementation Details
- When multiple edges exist between same source/target, calculate offset curves
- Use consistent offset distance (e.g., 30px) that scales with zoom
- Maximum of 3 parallel edges visible; beyond that, show aggregation badge
- Bidirectional edges use center position (no offset)
#### Visual Example (ASCII)
```
A ─────────────→ B (Single edge: straight bezier)
A ═══════════⟩ B (Multiple edges: curved offsets)
⟨─────────────
```
#### Interaction Patterns
**Selection**
- Click tolerance increases for offset edges (larger hit area)
- Selected edge highlighted with thicker stroke (3px -> 4px)
- Non-selected parallel edges dim to 50% opacity
- Hover shows all parallel edges with tooltip
**Hover States**
- Individual edge highlight on hover
- Show edge type and label in tooltip
- Dim other edges to 30% opacity
- Bring hovered edge to top layer (z-index manipulation)
**Multi-Edge Badge**
- Show count when 4+ edges between same nodes: "4 relations"
- Click badge to expand into offset view
- Badge position: midpoint of straight line between nodes
- Color: use neutral gray (matches aggregation pattern)
#### Accessibility Considerations
**Keyboard Navigation**
- Tab through edges in document order (source node ID order)
- Arrow keys to navigate between parallel edges
- Space/Enter to select edge
- Screen reader announces: "Relation 2 of 4 from Person A to Organization B, Collaborates type"
**Screen Readers**
- Edge count announced: "4 relations between nodes"
- Each edge individually focusable and describable
- Alternative text includes source, target, type, and label
**Color Contrast**
- Maintain WCAG AA standards (4.5:1 for text, 3:1 for UI components)
- Don't rely solely on color - use patterns (dashed/dotted) and labels
- High contrast mode: increase stroke width and use distinct patterns
**Motor Impairments**
- Larger click targets (minimum 44x44px according to WCAG 2.1 AAA)
- Increase hover tolerance for parallel edges
- Longer hover delay before tooltip appears (300ms)
#### Implementation Complexity
**Effort: Medium (3-5 days)**
**Changes Required:**
1. Modify `getFloatingEdgeParams()` to accept edge index parameter
2. Add offset calculation to bezier control points
3. Update `GraphEditor` to detect parallel edges and pass index
4. Create edge grouping utility function
5. Update CustomEdge to handle offset rendering
6. Add hover state management for edge groups
**Benefits:**
- Clear visual distinction between parallel edges
- Minimal performance impact (mathematical calculation only)
- Consistent with user expectations from diagramming tools
- Works at all zoom levels
- Preserves existing edge aggregation for groups
**Trade-offs:**
- Visual complexity increases with many parallel edges
- Requires recalculation when edges added/removed
- May need edge limit policy (e.g., max 5 visible, then aggregate)
---
## Design Solution 2: Edge Bundling with Interaction
### Visual Approach
**Bundle overlapping edges** into a single visual path that expands on interaction.
#### Implementation Details
- Detect edge clusters (edges that cross within 20px threshold)
- Render as single thick edge with width indicating count
- On hover, "explode" bundle into individual edges with labels
- Use color gradient to show multiple edge types in bundle
#### Visual Example (ASCII)
```
Default State:
A ══════════════⟩ B (Thick bundle: 5 edges)
Hover/Expanded State:
A ═══════════⟩ B
───────────→
─ ─ ─ ─ ─→
· · · · · →
⟨─────────
```
#### Interaction Patterns
**Default State**
- Show edge count badge on bundle
- Use widest stroke width to indicate bundle (4-8px)
- Color: blend of constituent edge types (or neutral gray)
**Hover State**
- Animate expansion into individual offset edges (300ms transition)
- Show all edge labels
- Individual edges selectable in expanded state
- Background blur/dim for focus
**Selection**
- Click bundle to expand permanently until deselected
- Click individual edge when expanded to select it
- Selected edge shows properties panel
- Double-click bundle to "pin" expansion
**Touch Devices**
- Tap bundle to expand
- Tap again to collapse
- Long-press for context menu
- Pinch to zoom focuses on bundle
#### Accessibility Considerations
**Keyboard Navigation**
- Tab to bundle
- Enter/Space to expand bundle
- Arrow keys to navigate within expanded bundle
- Escape to collapse bundle
- Screen reader: "Edge bundle containing 5 relations. Press Enter to expand."
**Visual Indicators**
- Animated expansion provides visual feedback
- Count badge always visible
- Edge labels appear only when expanded
- High contrast mode: use distinct patterns for bundle indicator
**Cognitive Load**
- Progressive disclosure reduces initial complexity
- Expansion animation helps user track state change
- Consistent interaction pattern across all bundles
- Visual hierarchy: bundles stand out in dense graphs
#### Implementation Complexity
**Effort: High (7-10 days)**
**Changes Required:**
1. Create edge clustering algorithm (detect overlapping edges)
2. Build BundledEdge component with expansion animation
3. Add state management for expanded/collapsed bundles
4. Implement hover detection and animation system
5. Create bundle label component with count badge
6. Update selection logic to handle bundle vs individual edge
7. Performance optimization for large graphs (edge clustering can be expensive)
**Benefits:**
- Dramatically reduces visual clutter in dense graphs
- Progressive disclosure matches user intent
- Scalable to very large graphs
- Innovative UX that stands out
- Reduces cognitive load in default state
**Trade-offs:**
- Higher implementation complexity
- Requires state management for bundle expansion
- Animation performance concerns on large graphs
- May confuse users unfamiliar with the pattern
- Edge clustering algorithm is computationally expensive
---
## Design Solution 3: Smart Edge Routing with Collision Avoidance
### Visual Approach
**Automatically route edges** around nodes and other edges to minimize crossings.
#### Implementation Details
- Use A* pathfinding or similar algorithm to route edges
- Create orthogonal or curved paths that avoid node boundaries
- Calculate collision-free paths on layout change
- Option to manually add waypoints for fine-tuning
#### Visual Example (ASCII)
```
Default:
A → B → C
↓ ↓
D → E → F
With Smart Routing:
A → B → C
↓ ↓ ↓
D ←─╯ ↓
↓ ↓
└─→ E → F
```
#### Interaction Patterns
**Automatic Routing**
- Edges automatically reroute when nodes move
- Smooth animation (300ms) when path changes
- Maintain edge label positions at path midpoints
- Option to disable auto-routing (manual mode)
**Manual Waypoints**
- Double-click edge to add waypoint
- Drag waypoint to adjust path
- Right-click waypoint to remove
- Waypoints persist across sessions
**Path Highlighting**
- Hover edge to highlight entire path
- Show direction arrows along path
- Dim other edges when hovering
- Show path length in tooltip (optional)
**Configuration**
- Toggle between "curved" and "orthogonal" routing
- Adjust routing algorithm sensitivity
- Set collision avoidance distance
- Enable/disable automatic rerouting
#### Accessibility Considerations
**Keyboard Navigation**
- Tab to select edge
- Arrow keys to navigate waypoints
- Delete key to remove waypoint
- Screen reader: "Edge with 3 waypoints. From Person A to Organization B."
**Visual Clarity**
- Orthogonal paths easier to follow than curves
- Clear directional indicators
- Path highlighting on focus
- High contrast mode: thicker paths with distinct patterns
**Cognitive Load**
- Auto-routing reduces manual work
- Can be confusing when paths change automatically
- Manual waypoints give user control
- Learning curve for waypoint editing
#### Implementation Complexity
**Effort: Very High (15-20 days)**
**Changes Required:**
1. Implement edge routing algorithm (A*, Dijkstra, or orthogonal routing)
2. Create waypoint system for manual editing
3. Add collision detection for nodes and edges
4. Implement path smoothing and bezier curve generation
5. Add animation system for path updates
6. Create configuration panel for routing options
7. Performance optimization (routing is CPU-intensive)
8. Handle edge cases (loops, self-edges, complex layouts)
**Benefits:**
- Eliminates edge crossings in most cases
- Professional appearance (like diagramming tools)
- User control through manual waypoints
- Scales to complex graphs
- Industry-standard approach
**Trade-offs:**
- Very high implementation complexity
- Significant performance impact on large graphs
- May produce unexpected routing in complex scenarios
- Requires substantial testing and edge case handling
- Can feel "overengineered" for simple graphs
- Breaking change from existing bezier curve UX
---
## Recommendation: Solution 1 (Parallel Edge Offset)
### Rationale
After analyzing the three solutions against project requirements, I recommend **Solution 1: Parallel Edge Offset** for the following reasons:
#### 1. **Best Effort/Value Ratio**
- **Medium complexity** (3-5 days) vs High (7-10 days) or Very High (15-20 days)
- Solves the primary problem: parallel edges between same nodes
- Incremental improvement that doesn't require architectural changes
#### 2. **Preserves Existing UX Patterns**
- Maintains current bezier curve style
- Consistent with existing group aggregation behavior
- No breaking changes to user workflows
- Works within React Flow's existing architecture
#### 3. **User-Centered Design**
- Immediate visual clarity for parallel edges
- Familiar pattern from other diagramming tools (Draw.io, Miro)
- Low learning curve
- Accessible with keyboard and screen readers
#### 4. **Performance**
- Pure mathematical calculation (no expensive algorithms)
- Scales well to large graphs (O(n) complexity)
- No animation/state management overhead
- Works at all zoom levels without recalculation
#### 5. **Accessibility**
- WCAG AA compliant
- Screen reader support straightforward
- Keyboard navigation well-defined
- High contrast mode compatible
#### 6. **Extensibility**
- Foundation for future enhancements
- Can add edge bundling later if needed
- Compatible with future smart routing
- Doesn't preclude other solutions
### Implementation Plan
#### Phase 1: Core Offset Logic (Day 1-2)
1. Create `calculateEdgeOffset()` utility function
2. Detect parallel edges in `GraphEditor`
3. Pass offset index to `CustomEdge` component
4. Modify `getFloatingEdgeParams()` to accept offset parameter
5. Calculate perpendicular offset for bezier control points
#### Phase 2: Visual Refinement (Day 2-3)
1. Implement hover states for parallel edge groups
2. Add selection highlighting
3. Create edge count badge component (for 4+ edges)
4. Test at different zoom levels
5. Ensure labels don't overlap
#### Phase 3: Interaction & Accessibility (Day 3-4)
1. Keyboard navigation for parallel edges
2. Screen reader announcements
3. Click tolerance adjustment
4. Tooltip improvements
5. High contrast mode testing
#### Phase 4: Testing & Documentation (Day 4-5)
1. Unit tests for offset calculation
2. Integration tests for edge groups
3. Visual regression tests
4. User documentation
5. Code review and refinement
### Success Metrics
**Visual Clarity**
- Parallel edges clearly distinguishable at all zoom levels
- No overlap between offset curves
- Labels remain readable
**Interaction Quality**
- Click target accuracy > 95% for offset edges
- Hover states respond within 100ms
- Keyboard navigation covers all edges
**Performance**
- No frame rate impact on graphs up to 500 edges
- Edge offset calculation < 5ms per edge
- Zoom/pan remains smooth
**Accessibility**
- WCAG AA compliance verified
- Screen reader testing with NVDA/JAWS
- Keyboard-only navigation successful
- High contrast mode functional
---
## Future Enhancements
After implementing Solution 1, consider these incremental improvements:
### Short-term (1-3 months)
1. **Edge hover tooltips**: Show full edge information on hover
2. **Edge filtering**: Hide edges by type/label to reduce clutter
3. **Edge path highlighting**: Show full path on selection
4. **Curved edge labels**: Orient labels along curve path
### Medium-term (3-6 months)
1. **Edge bundling** (Solution 2): For dense graphs with many crossings
2. **Edge strength visualization**: Vary width/opacity by strength property
3. **Edge animation**: Flowing particles to show direction/activity
4. **Edge grouping controls**: Manual grouping/ungrouping
### Long-term (6-12 months)
1. **Smart routing** (Solution 3): Optional for complex layouts
2. **Layout algorithms**: Auto-arrange to minimize crossings
3. **Edge styles library**: More edge type options (elbow, stepped, etc.)
4. **3D graph view**: For very complex networks
---
## Appendix: Technical Specifications
### Edge Offset Calculation Algorithm
```typescript
/**
* Calculate perpendicular offset for parallel edges
* @param sourcePos Source node position
* @param targetPos Target node position
* @param edgeIndex Index in parallel edge group (0 = center, 1 = first offset, 2 = second offset)
* @param offsetDistance Base offset distance in pixels (default 30)
* @returns Offset vector { x, y }
*/
function calculateEdgeOffset(
sourcePos: { x: number; y: number },
targetPos: { x: number; y: number },
edgeIndex: number,
offsetDistance: number = 30
): { x: number; y: number } {
// Calculate edge direction vector
const dx = targetPos.x - sourcePos.x;
const dy = targetPos.y - sourcePos.y;
const length = Math.sqrt(dx * dx + dy * dy);
if (length === 0) return { x: 0, y: 0 };
// Normalize
const nx = dx / length;
const ny = dy / length;
// Perpendicular vector (rotate 90 degrees)
const perpX = -ny;
const perpY = nx;
// Alternate sides for even/odd indices
// 0: center (no offset)
// 1: +offset (top/right side)
// 2: -offset (bottom/left side)
// 3: +offset * 2 (further top/right)
// 4: -offset * 2 (further bottom/left)
const side = edgeIndex % 2 === 0 ? -1 : 1;
const magnitude = Math.ceil(edgeIndex / 2);
const offset = side * magnitude * offsetDistance;
return {
x: perpX * offset,
y: perpY * offset
};
}
```
### Edge Grouping Detection
```typescript
/**
* Group edges by source-target pair
* @param edges Array of all edges
* @returns Map of edge groups, keyed by "sourceId_targetId"
*/
function groupParallelEdges(edges: Relation[]): Map<string, Relation[]> {
const groups = new Map<string, Relation[]>();
edges.forEach(edge => {
// Normalize key: always alphabetically sorted for bidirectional grouping
const key = [edge.source, edge.target].sort().join('_');
if (!groups.has(key)) {
groups.set(key, []);
}
groups.get(key)!.push(edge);
});
return groups;
}
```
### Performance Considerations
**Memory:**
- Edge offset calculation: O(1) per edge
- Edge grouping: O(n) space for n edges
- Total memory impact: ~50 bytes per edge
**CPU:**
- Offset calculation: ~0.1ms per edge (pure math)
- Grouping detection: O(n) time for n edges
- Total impact: < 100ms for 1000 edges
**Rendering:**
- No additional DOM nodes
- Same SVG path rendering as current implementation
- Z-index manipulation on hover (no re-render)
---
## Conclusion
Implementing **Parallel Edge Offset** (Solution 1) provides the best balance of:
- User experience improvement
- Implementation complexity
- Performance impact
- Accessibility compliance
- Future extensibility
This solution directly addresses the stated problem of overlapping edges between the same two nodes, while maintaining compatibility with the existing codebase architecture and user expectations.
The implementation can be completed in 3-5 days and provides a solid foundation for future enhancements like edge bundling or smart routing if needed.
---
**Next Steps:**
1. Review this proposal with the team
2. Approve implementation plan and timeline
3. Create implementation tickets
4. Begin Phase 1 development
5. Iterate based on user feedback
**Questions or feedback?** Open an issue or discussion on the repository.

View file

@ -0,0 +1,602 @@
# Edge Overlap Visual Design Guide
## Constellation Analyzer - Visual Specifications for Parallel Edge Offset
**Companion Document to:** EDGE_OVERLAP_UX_PROPOSAL.md
**Date:** 2026-02-05
---
## Visual Design Patterns
### 1. Single Edge (Current State)
```
Node A Node B
┌──────┐ ┌──────┐
│ │ │ │
│ A │ ─────────────→ │ B │
│ │ │ │
└──────┘ └──────┘
Stroke: 2px
Color: Based on edge type
Curve: Cubic Bezier with 40% control point distance
```
**Current Behavior:**
- Clean, simple bezier curve
- Works well for single connections
- Professional appearance
---
### 2. Parallel Edges (Proposed Design)
#### Two Edges Between Same Nodes
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭───────────→ │ │
│ A │ │ B │
│ │ ╰───────────→ │ │
└──────┘ └──────┘
Upper edge: +30px offset
Lower edge: -30px offset
Both: 2px stroke
Curves: Smooth, symmetrical arcs
```
**Visual Properties:**
- Offset: 30px perpendicular to center line
- Arc depth: Proportional to edge length
- Spacing: Consistent at all zoom levels
- Labels: Positioned at curve midpoint
#### Three Edges Between Same Nodes
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭──────────────→│ │
│ A │ ────────────────│ B │ (center, no offset)
│ │ ╰──────────────→│ │
└──────┘ └──────┘
Top edge: +30px offset
Center edge: 0px offset (straight bezier)
Bottom edge: -30px offset
```
**Visual Hierarchy:**
- Center edge is most prominent (straight)
- Offset edges curve away from center
- Equal visual weight for all edges
#### Four+ Edges (Aggregation Badge)
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭──────────────→│ │
│ A │ ─────┌───┐─────│ B │
│ │ │ 4 │ │ │ │
│ │ ╰────└───┘─────→│ │
└──────┘ └──────┘
Top 3 edges: Visible with offsets
Badge: "4 relations" at center
Badge style: Gray pill, white text
Hover: Expand to show all 4 edges
```
**Badge Design:**
- Background: #6b7280 (gray-500)
- Text: White, 12px, medium weight
- Border radius: 12px (pill shape)
- Padding: 4px 8px
- Shadow: 0 2px 4px rgba(0,0,0,0.1)
---
### 3. Hover States
#### Default State
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭───────────→ │ │
│ A │ ────────────→ │ B │
│ │ ╰───────────→ │ │
└──────┘ └──────┘
All edges: 100% opacity
No highlights
```
#### Hover Single Edge
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭───────────→ │ │ (30% opacity, dimmed)
│ A │ ━━━━━━━━━━━━→ │ B │ (100% opacity, 3px stroke, highlighted)
│ │ ╰───────────→ │ │ (30% opacity, dimmed)
└──────┘ └──────┘
┌─────────────┐
│ Collaborates│ (Tooltip)
│ Type: Work │
└─────────────┘
```
**Hover Behavior:**
- Hovered edge: 3px stroke (from 2px)
- Hovered edge: 100% opacity
- Other parallel edges: 30% opacity
- Tooltip appears after 200ms
- Z-index: Bring hovered edge to top layer
#### Selection State
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭───────────→ │ │ (50% opacity, dimmed)
│ A │ ━━━━━━━━━━━━→ │ B │ (4px stroke, blue outline, selected)
│ │ ╰───────────→ │ │ (50% opacity, dimmed)
└──────┘ └──────┘
Selected edge: 4px stroke
Selected edge: Blue glow (#3b82f6)
Other parallel edges: 50% opacity
Selection persists until deselected
```
---
### 4. Bidirectional Edges
#### Bidirectional vs Two Directed Edges
**Bidirectional (Single Edge):**
```
Node A Node B
┌──────┐ ┌──────┐
│ │ │ │
│ A │ ⟨────────────⟩ │ B │
│ │ │ │
└──────┘ └──────┘
Single edge with arrows at both ends
No offset (uses center line)
Marker-start and marker-end
```
**Two Directed Edges:**
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭───────────→ │ │
│ A │ │ B │
│ │ ╰←──────────╯ │ │
└──────┘ └──────┘
Two separate edges with offsets
Offset: ±30px
Each has single arrow
```
**Design Decision:**
- Bidirectional edges: No offset, use center line
- Two separate directed edges: Apply offset
- Visual distinction clear to users
- Preserves semantic meaning
---
### 5. Edge Label Positioning
#### Label on Curved Edge
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭──┌─────────┐→ │ │
│ A │ │Collabora.│ │ B │
│ │ └─────────┘ │ │
└──────┘ └──────┘
Label positioned at bezier t=0.5 (midpoint)
Background: White with border
Padding: 8px 12px
Font: 12px, medium weight
Max-width: 200px (wrap text)
```
**Label Collision Avoidance:**
- Labels offset 5px above curve for top edge
- Labels offset 5px below curve for bottom edge
- Center edge: label on curve (existing behavior)
- Labels never overlap edge paths
#### Multiple Labels on Parallel Edges
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭─┌────────┐──→ │ │
│ A │ │Reports To│ │ B │
│ │ ─┌──────────┐──→│ │
│ │ │Collabora.│ │ │
│ │ ╰┌─────────┐───→│ │
│ │ │Depends On│ │ │
└──────┘ └─────────┘ └──────┘
Labels staggered to prevent overlap
Each label aligned with its edge curve
Smart positioning algorithm
```
---
### 6. Zoom Level Behavior
#### Zoom Out (0.5x)
```
Node A Node B
┌─┐ ┌─┐
│A│ ╭─────→ │B│
│ │ ───────→ │ │
│ │ ╰─────→ │ │
└─┘ └─┘
Offset: 30px (constant, not scaled)
Stroke: 1px (minimum)
Labels: Hidden or summarized
Badge: Visible
```
**Design Note:** Offset distance remains constant in screen pixels, creating proportionally larger curves when zoomed out. This maintains visual separation.
#### Zoom In (2.0x)
```
Node A Node B
┌──────────┐ ┌──────────┐
│ │ ╭────────────────────→ │ │
│ A │ │ B │
│ │ ──────────────────────→ │ │
│ │ │ │
│ │ ╰────────────────────→ │ │
└──────────┘ └──────────┘
Offset: 30px (constant)
Stroke: 3px (scaled up)
Labels: Fully visible with more detail
Curves: More pronounced
```
**Design Note:** At higher zoom, offset appears smaller relative to nodes, but remains visually distinct.
---
### 7. Color and Styling
#### Edge Type Colors (Existing)
```
Collaborates: #3b82f6 (blue)
Reports To: #10b981 (green)
Depends On: #f59e0b (orange)
Influences: #8b5cf6 (purple)
```
#### Edge Styles (Existing)
```
Solid: ────────────
Dashed: ─ ─ ─ ─ ─ ─
Dotted: · · · · · ·
```
#### New States
```
Default: stroke-width: 2px, opacity: 1.0
Hover: stroke-width: 3px, opacity: 1.0
Dimmed: stroke-width: 2px, opacity: 0.3
Selected: stroke-width: 4px, opacity: 1.0, glow: #3b82f6
```
#### Aggregation Badge
```
Background: #6b7280
Text: #ffffff
Border: None
Shadow: 0 2px 4px rgba(0,0,0,0.1)
```
---
### 8. Accessibility Visual Indicators
#### High Contrast Mode
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╔═══════════⟩ │ │ (4px stroke, solid)
│ A │ ═════════════⟩ │ B │ (4px stroke, dashed)
│ │ ╚═══════════⟩ │ │ (4px stroke, dotted)
└──────┘ └──────┘
All strokes: 4px (increased from 2px)
Distinct patterns for each edge type
Colors: High contrast (black/white basis)
```
#### Focus Indicator (Keyboard Navigation)
```
Node A Node B
┌──────┐ ┌──────┐
│ │ ╭───────────→ │ │
│ A │ ┏━━━━━━━━━━━┓→ │ B │ (Focus ring: 2px offset)
│ │ ╰───────────→ │ │
└──────┘ └──────┘
Focus ring: 2px blue outline (#3b82f6)
Offset: 4px from edge path
Visible only when focused via keyboard
```
---
### 9. Animation Specifications
#### Edge Creation Animation
```
Frame 0: Node A · Node B
·
·
Frame 1: Node A ·········· Node B
Frame 2: Node A ─────────────→ Node B
Duration: 300ms
Easing: ease-out
Effect: Draw from source to target
```
#### Hover Transition
```
Frame 0: Normal state (2px, 100% opacity)
Frame 1: Transitioning (2.5px, 100% opacity)
Frame 2: Hover state (3px, 100% opacity)
Duration: 150ms
Easing: ease-in-out
Effect: Smooth width increase
```
#### Selection Transition
```
Frame 0: Normal state
Frame 1: Glow appears (opacity: 0 → 0.5)
Frame 2: Width increases (2px → 4px)
Frame 3: Full selection state
Duration: 200ms
Easing: ease-out
Effect: Blue glow + width increase
```
---
### 10. Responsive Behavior
#### Mobile View (< 768px)
```
- Offset distance: 40px (increased for touch targets)
- Stroke width: 3px (increased for visibility)
- Minimum click target: 44x44px
- Labels: Hidden by default, show on tap
- Badge: Always visible
```
#### Tablet View (768px - 1024px)
```
- Offset distance: 35px
- Stroke width: 2px
- Click target: 44x44px
- Labels: Show on hover
- Badge: Visible when 4+ edges
```
#### Desktop View (> 1024px)
```
- Offset distance: 30px (default)
- Stroke width: 2px
- Click target: natural edge width
- Labels: Always visible
- Badge: Visible when 4+ edges
```
---
### 11. Edge Case Visual Handling
#### Self-Loop Edge
```
Node A
┌──────┐
│ │ ╭─╮
│ A │ │ │ (Loop extends 80px from node)
│ │ ╰─╯
└──────┘
Rendered as circular arc
Extends 80px from node edge
Arrow points back to source
Label positioned outside loop
```
#### Very Short Distance Between Nodes
```
Node A Node B
┌───┐ ┌───┐
│ A │╭→ │ B │
│ │╰→ │ │
└───┘ └───┘
Offset: Reduced to 15px (50% of default)
Curves: Sharper to fit space
Labels: Hidden to prevent overlap
Badge: Positioned above nodes
```
#### Long Distance Between Nodes
```
Node A Node B
┌───┐ ┌───┐
│ A │ ╭───────────────────────────────────────→ │ B │
│ │ ─────────────────────────────────────────→ │ │
│ │ ╰───────────────────────────────────────→ │ │
└───┘ └───┘
Offset: 30px (constant)
Curves: Gentle (control point distance capped at 150px)
Labels: Positioned at midpoint
Visual: Offset less noticeable but still distinct
```
---
## Design Tokens
### Spacing
```typescript
const EDGE_OFFSET_BASE = 30; // Base offset in pixels
const EDGE_OFFSET_MOBILE = 40; // Increased for touch
const EDGE_OFFSET_MIN = 15; // Minimum for close nodes
const LABEL_OFFSET = 5; // Label offset from curve
const BADGE_PADDING = '4px 8px'; // Badge internal padding
```
### Strokes
```typescript
const STROKE_DEFAULT = 2; // Default edge width
const STROKE_HOVER = 3; // Hovered edge width
const STROKE_SELECTED = 4; // Selected edge width
const STROKE_DIMMED = 2; // Width when dimmed (opacity changes)
const STROKE_HIGH_CONTRAST = 4; // Width in high contrast mode
```
### Opacity
```typescript
const OPACITY_DEFAULT = 1.0; // Normal edge visibility
const OPACITY_DIMMED = 0.3; // Non-hovered parallel edges
const OPACITY_SEMI_DIMMED = 0.5; // Non-selected parallel edges
const OPACITY_FILTERED = 0.2; // Edges filtered out by search
```
### Colors
```typescript
const COLOR_SELECTION_GLOW = '#3b82f6'; // Blue focus/selection
const COLOR_BADGE_BG = '#6b7280'; // Gray badge background
const COLOR_BADGE_TEXT = '#ffffff'; // White badge text
const COLOR_LABEL_BG = '#ffffff'; // White label background
const COLOR_LABEL_BORDER = '#d1d5db'; // Gray label border
```
### Timing
```typescript
const DURATION_HOVER = 150; // Hover transition duration (ms)
const DURATION_SELECTION = 200; // Selection animation duration (ms)
const DURATION_CREATION = 300; // Edge creation animation (ms)
const DURATION_TOOLTIP_DELAY = 200; // Delay before tooltip appears (ms)
```
### Bezier Curves
```typescript
const CONTROL_POINT_RATIO = 0.4; // 40% of distance between nodes
const CONTROL_POINT_MIN = 40; // Minimum control point distance (px)
const CONTROL_POINT_MAX = 150; // Maximum control point distance (px)
```
---
## Implementation Reference
### CSS Classes (for styled edges)
```css
.edge-default {
stroke-width: 2px;
opacity: 1;
transition: stroke-width 150ms ease-in-out, opacity 150ms ease-in-out;
}
.edge-hover {
stroke-width: 3px;
opacity: 1;
z-index: 100;
}
.edge-selected {
stroke-width: 4px;
opacity: 1;
filter: drop-shadow(0 0 4px #3b82f6);
}
.edge-dimmed {
opacity: 0.3;
}
.edge-badge {
background: #6b7280;
color: #ffffff;
border-radius: 12px;
padding: 4px 8px;
font-size: 12px;
font-weight: 500;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.edge-label {
background: #ffffff;
border: 1px solid #d1d5db;
border-radius: 4px;
padding: 8px 12px;
font-size: 12px;
font-weight: 500;
max-width: 200px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
/* High Contrast Mode */
@media (prefers-contrast: high) {
.edge-default {
stroke-width: 4px;
}
}
/* Focus indicator for keyboard navigation */
.edge-focused {
outline: 2px solid #3b82f6;
outline-offset: 4px;
}
```
---
## Conclusion
This visual guide provides detailed specifications for implementing parallel edge offset in the Constellation Analyzer. All measurements, colors, and animations are designed to:
1. **Maintain visual consistency** with existing design patterns
2. **Ensure accessibility** across different modes and devices
3. **Scale gracefully** from mobile to desktop
4. **Provide clear interaction feedback** through hover, selection, and focus states
5. **Handle edge cases** without breaking the visual hierarchy
Use this guide alongside the main UX proposal document for implementation.
---
**Related Files:**
- Main proposal: `/home/jbruhn/dev/constellation-analyzer/EDGE_OVERLAP_UX_PROPOSAL.md`
- Current edge implementation: `/home/jbruhn/dev/constellation-analyzer/src/components/Edges/CustomEdge.tsx`
- Edge utilities: `/home/jbruhn/dev/constellation-analyzer/src/utils/edgeUtils.ts`

View file

@ -0,0 +1,755 @@
# Temporal & Scenario Analysis - Implementation Checklist
## Phase 1: Core State Management (Week 1-2)
### Data Model Setup
- [ ] Create `/src/types/temporal.ts`
- [ ] Define `StateType` enum
- [ ] Define `TemporalMetadata` interface
- [ ] Define `ScenarioMetadata` interface
- [ ] Define `StateRelationship` interface
- [ ] Define `AnalysisState` interface
- [ ] Define `StateDiff` interface
- [ ] Define `ActorJourney` interface
- [ ] Define `Timeline` interface
- [ ] Define `ScenarioTree` interface
- [ ] Update `/src/stores/persistence/types.ts`
- [ ] Add `states` property to `ConstellationDocument`
- [ ] Add `supportsStates` to document metadata
- [ ] Ensure backward compatibility
- [ ] Create migration helper
- [ ] Function to enable states for existing documents
- [ ] Function to create initial state from current graph
- [ ] Test migration with sample documents
### State Store Implementation
- [ ] Create `/src/stores/stateStore.ts`
- [ ] Basic store structure with Zustand
- [ ] State CRUD operations
- [ ] `createState()`
- [ ] `loadState()`
- [ ] `deleteState()`
- [ ] `updateStateMetadata()`
- [ ] State retrieval
- [ ] `getState()`
- [ ] `getAllStates()`
- [ ] `getStatesByType()`
- [ ] Navigation helpers
- [ ] `getNextState()`
- [ ] `getPreviousState()`
### Snapshot Functionality
- [ ] Create `/src/utils/stateSnapshot.ts`
- [ ] `captureCurrentGraph()` - serialize current graph state
- [ ] `restoreGraphFromState()` - load state into graph
- [ ] `validateStateData()` - ensure data integrity
- [ ] Handle edge cases (empty graph, large graphs)
### Basic UI Integration
- [ ] Update `/src/components/Toolbar/Toolbar.tsx`
- [ ] Add "Capture State" button
- [ ] Add current state indicator
- [ ] Add loading/saving state indicators
- [ ] Create `/src/components/TemporalAnalysis/StateSelector.tsx`
- [ ] Basic dropdown UI
- [ ] List all states
- [ ] Click to load state
- [ ] Show current state indicator
- [ ] Search/filter functionality
- [ ] Create hooks
- [ ] `/src/hooks/useStateManagement.ts`
- [ ] `useCurrentState()`
- [ ] `useCaptureState()`
- [ ] `useLoadState()`
### Integration with Workspace
- [ ] Update `/src/stores/workspaceStore.ts`
- [ ] Add `captureCurrentState()` action
- [ ] Add `restoreState()` action
- [ ] Ensure states saved with document
- [ ] Handle state data in export/import
### Testing
- [ ] Test state creation
- [ ] Test state loading
- [ ] Test state persistence
- [ ] Test with empty graphs
- [ ] Test with large graphs (100+ nodes)
- [ ] Test edge cases (missing data, corrupted states)
---
## Phase 2: Temporal Analysis (Week 3-4)
### Timeline Data Management
- [ ] Extend `/src/stores/stateStore.ts`
- [ ] Timeline CRUD operations
- [ ] `createTimeline()`
- [ ] `deleteTimeline()`
- [ ] `updateTimeline()`
- [ ] Timeline state management
- [ ] `addStateToTimeline()`
- [ ] `removeStateFromTimeline()`
- [ ] `reorderTimeline()`
- [ ] Timeline queries
- [ ] `getStatesByTimeline()`
- [ ] `getTimelineStates()` (ordered)
### Temporal Metadata
- [ ] Create `/src/components/TemporalAnalysis/StateMetadataEditor.tsx`
- [ ] Temporal metadata form
- [ ] Date/time picker
- [ ] Sequence number input
- [ ] Label input
- [ ] Period range inputs
- [ ] Display format selector
- [ ] Notes/description textarea
- [ ] Tags input
### Timeline Panel UI
- [ ] Create `/src/components/TemporalAnalysis/TimelinePanel.tsx`
- [ ] Horizontal timeline visualization
- [ ] State markers on timeline
- [ ] Click to load state
- [ ] Drag to scrub timeline
- [ ] Zoom in/out on timeline
- [ ] Pan timeline horizontally
- [ ] State creation controls
- [ ] Timeline selector dropdown (multiple timelines)
- [ ] Timeline styling
- [ ] Color-coded state markers
- [ ] Current state highlight
- [ ] Hover effects
- [ ] Responsive design
- [ ] Collapsible panel
### Timeline Navigation
- [ ] Add keyboard shortcuts
- [ ] `←` Previous state in timeline
- [ ] `→` Next state in timeline
- [ ] `Home` First state
- [ ] `End` Last state
- [ ] Navigation buttons
- [ ] Previous/Next buttons
- [ ] Jump to start/end
- [ ] State counter (e.g., "3 of 12")
### Integration
- [ ] Update `/src/App.tsx`
- [ ] Add TimelinePanel to layout
- [ ] Handle panel visibility toggle
- [ ] Handle panel resize
- [ ] Update `/src/components/Menu/MenuBar.tsx`
- [ ] Add "States" menu
- [ ] "View Timeline" action
- [ ] "Create Timeline" action
### Testing
- [ ] Test timeline creation
- [ ] Test state ordering
- [ ] Test timeline navigation
- [ ] Test keyboard shortcuts
- [ ] Test with multiple timelines
- [ ] Test timeline visualization with many states (20+)
---
## Phase 3: Comparison & Diff Analysis (Week 5-6)
### Diff Calculation Engine
- [ ] Create `/src/utils/stateDiff.ts`
- [ ] `calculateStateDiff()` function
- [ ] Actor comparison logic
- [ ] Detect added actors
- [ ] Detect removed actors
- [ ] Detect modified actors (label, type, position, metadata)
- [ ] Relation comparison logic
- [ ] Detect added relations
- [ ] Detect removed relations
- [ ] Detect modified relations (type, directionality, strength)
- [ ] Summary statistics calculation
- [ ] Performance optimization for large graphs
- [ ] Create `/src/hooks/useStateDiff.ts`
- [ ] `useComparison()` hook
- [ ] `useDiffCalculation()` hook
- [ ] Memoization for expensive calculations
### Visual Diff on Graph
- [ ] Create `/src/components/Editor/DiffOverlay.tsx`
- [ ] Overlay mode component
- [ ] Color coding for changes
- [ ] Green for added (actors/relations)
- [ ] Red for removed (actors/relations)
- [ ] Yellow/orange for modified
- [ ] Change badges/icons on nodes
- [ ] Toggle overlay on/off
- [ ] Opacity control for overlay
- [ ] Update `/src/components/Editor/GraphEditor.tsx`
- [ ] Integrate DiffOverlay
- [ ] Apply diff styling to nodes/edges
- [ ] Animated transitions for diff highlights
### Comparison View UI
- [ ] Create `/src/components/TemporalAnalysis/ComparisonView.tsx`
- [ ] Modal/panel for comparison
- [ ] State selectors (From/To)
- [ ] Comparison mode selector
- [ ] Side-by-side
- [ ] Overlay
- [ ] Tabbed
- [ ] Graph visualization for both states
- [ ] Synchronized panning/zooming
- [ ] Difference highlighting
- [ ] Summary statistics panel
- [ ] Create `/src/components/TemporalAnalysis/StateDiffViewer.tsx`
- [ ] List of changes (actors/relations)
- [ ] Filter by change type (added/removed/modified)
- [ ] Click to highlight on graph
- [ ] Export changes as report
### Change Summary
- [ ] Create `/src/components/TemporalAnalysis/ChangeSummary.tsx`
- [ ] Statistics dashboard
- [ ] Total actors (before/after)
- [ ] Total relations (before/after)
- [ ] Added/removed/modified counts
- [ ] Change breakdown by type
- [ ] Visual charts (pie chart, bar chart)
- [ ] Export to CSV/JSON
### Quick Compare
- [ ] Add to TimelinePanel
- [ ] "Compare" button on state markers
- [ ] Right-click context menu "Compare with..."
- [ ] Select two states to compare
- [ ] Add to state selector
- [ ] Checkbox mode to select multiple states
- [ ] "Compare Selected" button
### Export Comparison Report
- [ ] Report generation
- [ ] PDF export with diff summary
- [ ] JSON export of diff data
- [ ] HTML report with interactive visualization
- [ ] Include screenshots of both states
### Testing
- [ ] Test diff calculation accuracy
- [ ] Test with various graph sizes
- [ ] Test comparison view UI
- [ ] Test visual diff overlay
- [ ] Test export functionality
- [ ] Performance test with large diffs
---
## Phase 4: Scenario Branching (Week 7-8)
### Scenario Data Model
- [ ] Extend `/src/stores/stateStore.ts`
- [ ] Scenario tree management
- [ ] `createScenarioBranch()`
- [ ] `addStateToScenario()`
- [ ] `deleteScenarioBranch()`
- [ ] Scenario queries
- [ ] `getStatesByScenario()`
- [ ] `getScenarioTree()`
- [ ] `getScenarioBranches()`
### Scenario Creation UI
- [ ] Create `/src/components/TemporalAnalysis/ScenarioCreator.tsx`
- [ ] "Branch from here" button/dialog
- [ ] Scenario metadata form
- [ ] Label input
- [ ] Description textarea
- [ ] Assumptions list input
- [ ] Probability/confidence selector
- [ ] Color picker for branch
- [ ] Parent state selection
- [ ] Create and switch to scenario
### Scenario Tree Visualization
- [ ] Extend TimelinePanel for scenarios
- [ ] Vertical branching layout
- [ ] Branch lines/connectors
- [ ] Branch labels
- [ ] Branch color coding
- [ ] Collapse/expand branches
- [ ] Scenario navigation controls
- [ ] Alternative: Tree view component
- [ ] Hierarchical tree visualization
- [ ] Collapsible nodes
- [ ] Click to load state
- [ ] Branch context menu (edit, delete, compare)
### Scenario Metadata Editor
- [ ] Update StateMetadataEditor
- [ ] Scenario-specific fields
- [ ] Assumptions editor (add/remove/edit)
- [ ] Probability slider
- [ ] Confidence level selector
- [ ] Branch color picker
### Scenario Navigation
- [ ] Scenario switcher
- [ ] Dropdown to select branch
- [ ] Filter timeline by scenario
- [ ] Visual indicator of current branch
- [ ] Branch comparison
- [ ] "Compare branches" action
- [ ] Select multiple scenarios
- [ ] Side-by-side comparison
- [ ] Outcome analysis
### Integration
- [ ] Update menu bar
- [ ] "Create Scenario" menu item
- [ ] "Manage Scenarios" menu item
- [ ] Update state selector
- [ ] Group states by scenario
- [ ] Scenario branch indicators
### Testing
- [ ] Test scenario creation
- [ ] Test branch visualization
- [ ] Test scenario navigation
- [ ] Test with multiple branches
- [ ] Test nested scenarios (if supported)
- [ ] Test scenario deletion
---
## Phase 5: Actor Tracking & Journeys (Week 9-10)
### Journey Calculation
- [ ] Create `/src/utils/actorJourney.ts`
- [ ] `getActorJourney()` function
- [ ] Track actor across states
- [ ] Detect first/last appearance
- [ ] Calculate property changes
- [ ] Track relationship evolution
- [ ] Performance optimization
- [ ] Create `/src/hooks/useActorJourney.ts`
- [ ] `useActorJourney()` hook
- [ ] `useMultiActorJourney()` hook
- [ ] Memoization
### Journey Viewer UI
- [ ] Create `/src/components/TemporalAnalysis/ActorJourneyViewer.tsx`
- [ ] Actor selection interface
- [ ] Dropdown or autocomplete
- [ ] Search by label
- [ ] Select from graph click
- [ ] Timeline visualization
- [ ] Horizontal timeline
- [ ] Actor appearance markers
- [ ] Property change indicators
- [ ] Property evolution display
- [ ] Label changes
- [ ] Type changes
- [ ] Position changes
- [ ] Relationship changes display
- [ ] Relations added/removed
- [ ] Relation type changes
- [ ] Relation strength changes
### Multi-Actor Comparison
- [ ] Select multiple actors
- [ ] Overlay journeys on same timeline
- [ ] Compare property evolution
- [ ] Compare relationship dynamics
- [ ] Identify interaction points
### Journey Export
- [ ] Export journey data
- [ ] CSV export
- [ ] JSON export
- [ ] PDF report with visualizations
- [ ] Include:
- [ ] Actor metadata
- [ ] State sequence
- [ ] Property changes
- [ ] Relationship changes
- [ ] Summary statistics
### Integration
- [ ] Add to right panel
- [ ] "View Journey" button on actor selection
- [ ] Quick journey view
- [ ] Add to menu bar
- [ ] "Actor Journeys" menu item
- [ ] Keyboard shortcut (Ctrl+J)
### Testing
- [ ] Test journey calculation
- [ ] Test with various actor types
- [ ] Test with actors that appear/disappear
- [ ] Test multi-actor comparison
- [ ] Test export functionality
---
## Phase 6: Animation & Presentation (Week 11-12)
### Animation Engine
- [ ] Create `/src/utils/stateAnimation.ts`
- [ ] `interpolateStates()` function
- [ ] Position interpolation
- [ ] Opacity interpolation (fade in/out)
- [ ] Size interpolation
- [ ] Color interpolation
- [ ] Easing functions (linear, ease-in-out, etc.)
- [ ] Create `/src/hooks/useStateAnimation.ts`
- [ ] `useAnimation()` hook
- [ ] Animation state management
- [ ] Frame rate control
- [ ] Performance optimization
### Animation Controls
- [ ] Create `/src/components/TemporalAnalysis/StateAnimator.tsx`
- [ ] Play/pause button
- [ ] Step forward/backward buttons
- [ ] Speed control slider
- [ ] Loop toggle
- [ ] Progress bar
- [ ] Frame counter
- [ ] Quality settings (performance vs. smoothness)
- [ ] Integrate with TimelinePanel
- [ ] Animation controls bar
- [ ] Visual playhead on timeline
- [ ] Click timeline to jump to state
### Animation Modes
- [ ] Sequential (state A → B → C)
- [ ] Comparison (fade between two states)
- [ ] Journey (follow actor across states)
- [ ] Custom sequence (user-selected states)
### Presentation Mode
- [ ] Create `/src/components/TemporalAnalysis/PresentationMode.tsx`
- [ ] Full-screen mode
- [ ] Slideshow interface
- [ ] State sequence selector
- [ ] Auto-advance with timer
- [ ] Manual navigation (arrow keys)
- [ ] Annotation overlays
- [ ] Title for each state
- [ ] Notes/narration text
- [ ] Key insights callouts
- [ ] Exit presentation (Esc key)
### Export Capabilities (Stretch Goal)
- [ ] Export animation
- [ ] Animated GIF export
- [ ] Video export (WebM/MP4) - may require server-side
- [ ] Frame sequence export (PNG images)
- [ ] Interactive HTML export
### Integration
- [ ] Add to menu bar
- [ ] "Animate Timeline" menu item
- [ ] "Presentation Mode" menu item
- [ ] Keyboard shortcut (Ctrl+Shift+P)
- [ ] Add to timeline panel
- [ ] Play button
- [ ] Presentation mode button
### Testing
- [ ] Test animation smoothness
- [ ] Test with various animation speeds
- [ ] Test with large state transitions
- [ ] Test presentation mode navigation
- [ ] Performance test with complex graphs
- [ ] Test on different screen sizes
---
## Phase 7: ChromaDB Integration (Week 13-14)
### ChromaDB Setup
- [ ] Install ChromaDB dependencies
- [ ] Add to package.json
- [ ] Configure ChromaDB client
- [ ] Create `/src/utils/chromaIntegration.ts`
- [ ] Initialize ChromaDB client
- [ ] Connection management
- [ ] Error handling
### Collection Setup
- [ ] Create collections
- [ ] `constellation_states` - state metadata
- [ ] `actor_journeys` - actor trajectories
- [ ] `state_comparisons` - cached comparisons
- [ ] `annotations` - user notes and insights
- [ ] Define schemas
- [ ] Metadata fields
- [ ] Embedding strategies
- [ ] Query filters
### State Indexing
- [ ] Create indexing functions
- [ ] `indexState()` - index single state
- [ ] `batchIndexStates()` - index multiple states
- [ ] `updateStateIndex()` - update existing index
- [ ] `removeStateIndex()` - remove from index
- [ ] Generate embeddings
- [ ] Combine label, description, notes, assumptions
- [ ] Use ChromaDB's built-in embedding
- [ ] Handle long text (truncation/summarization)
### Semantic Search
- [ ] Create search functions
- [ ] `searchStates()` - general search
- [ ] `findSimilarStates()` - similarity search
- [ ] `searchByTags()` - tag-based search
- [ ] `searchByTimeRange()` - temporal search
- [ ] Create `/src/components/TemporalAnalysis/StateSearch.tsx`
- [ ] Search input
- [ ] Search filters (type, timeline, scenario, tags)
- [ ] Results list
- [ ] Click to load state
- [ ] Relevance scoring display
### Pattern Recognition
- [ ] Implement pattern detection
- [ ] Identify similar network structures
- [ ] Find recurring patterns
- [ ] Detect anomalies
- [ ] Trend analysis
- [ ] Create pattern visualization
- [ ] Display pattern clusters
- [ ] Highlight similar states
- [ ] Generate insights
### Annotation Storage
- [ ] Store annotations in ChromaDB
- [ ] Link to specific states
- [ ] Link to specific changes
- [ ] Support rich text
- [ ] Support tags
- [ ] Create annotation search
- [ ] Search within annotations
- [ ] Find states by annotation content
### Caching Strategy
- [ ] Cache diff calculations
- [ ] Store diff results in ChromaDB
- [ ] Retrieve cached diffs
- [ ] Invalidate cache on state changes
- [ ] Cache journey calculations
- [ ] Store journey data
- [ ] Update on relevant state changes
### Integration
- [ ] Add to state store
- [ ] `indexStateForSearch()` action
- [ ] `searchStates()` action
- [ ] Add to UI
- [ ] Search box in state selector
- [ ] "Find similar" button on states
- [ ] Pattern insights panel
### Testing
- [ ] Test indexing performance
- [ ] Test search accuracy
- [ ] Test similarity detection
- [ ] Test caching effectiveness
- [ ] Test with large state collections (100+ states)
---
## Phase 8: Advanced Features (Week 15-16)
### Automatic State Capture
- [ ] Implement auto-capture
- [ ] Periodic snapshots (e.g., every 10 minutes)
- [ ] Significant change detection (threshold-based)
- [ ] User-configurable triggers
- [ ] Auto-cleanup of old snapshots
- [ ] Settings UI
- [ ] Enable/disable auto-capture
- [ ] Configure frequency
- [ ] Configure retention policy
### State Templates
- [ ] Template creation
- [ ] Save state as template
- [ ] Template metadata (name, description, category)
- [ ] Template preview
- [ ] Template application
- [ ] Browse template library
- [ ] Apply template to create new state
- [ ] Customize template on application
- [ ] Template management
- [ ] Edit templates
- [ ] Delete templates
- [ ] Import/export templates
### Collaborative Features (Stretch Goal)
- [ ] Sharing
- [ ] Export shareable link to timeline
- [ ] Export shareable link to scenario
- [ ] Embed code for presentations
- [ ] Comments
- [ ] Comment on specific states
- [ ] Reply to comments
- [ ] @mentions
- [ ] Resolve comments
- [ ] Approvals (Stretch Goal)
- [ ] Submit state for review
- [ ] Approve/reject states
- [ ] Review workflow
### Advanced Analytics
- [ ] Network metrics over time
- [ ] Density evolution
- [ ] Centrality changes
- [ ] Clustering coefficient
- [ ] Path lengths
- [ ] Statistical analysis
- [ ] Correlation analysis
- [ ] Regression models
- [ ] Predictive analytics
- [ ] Export to analysis tools
- [ ] Export time-series data
- [ ] Export to CSV for Excel/R/Python
- [ ] API for external tools
### Testing
- [ ] Test auto-capture functionality
- [ ] Test template system
- [ ] Test collaborative features
- [ ] Test analytics calculations
- [ ] Integration testing with all phases
---
## Final Polish & Documentation
### Performance Optimization
- [ ] Profile performance bottlenecks
- [ ] Optimize diff calculation
- [ ] Optimize rendering for many states
- [ ] Lazy loading for large timelines
- [ ] Implement virtualization where needed
### Error Handling
- [ ] Graceful degradation for missing data
- [ ] User-friendly error messages
- [ ] Rollback on failed operations
- [ ] Data validation throughout
### Accessibility
- [ ] Keyboard navigation for all features
- [ ] Screen reader support
- [ ] High contrast mode support
- [ ] Focus indicators
- [ ] ARIA labels
### Documentation
- [ ] User guide (see TEMPORAL_QUICK_START.md)
- [ ] Getting started tutorial
- [ ] Feature walkthroughs
- [ ] Best practices
- [ ] FAQ
- [ ] Developer documentation
- [ ] API reference
- [ ] Type definitions
- [ ] Architecture overview
- [ ] Extension guide
- [ ] Video tutorials
- [ ] Overview video
- [ ] Feature-specific videos
- [ ] Advanced use cases
### Testing
- [ ] Unit tests for all utilities
- [ ] Integration tests for stores
- [ ] Component tests for UI
- [ ] E2E tests for workflows
- [ ] Performance benchmarks
- [ ] User acceptance testing
### Release
- [ ] Version bump
- [ ] Changelog
- [ ] Migration guide for existing users
- [ ] Announcement post/blog
- [ ] Update README
---
## Success Metrics
Track these metrics post-release:
- [ ] Feature adoption rate
- [ ] % of users who enable states
- [ ] % of documents with states
- [ ] Average states per document
- [ ] Usage patterns
- [ ] Temporal vs. scenario usage
- [ ] Most used features (comparison, animation, journeys)
- [ ] Average session time with states
- [ ] Performance
- [ ] State creation time
- [ ] Diff calculation time
- [ ] Animation frame rate
- [ ] ChromaDB query latency
- [ ] User satisfaction
- [ ] User feedback/ratings
- [ ] Support tickets related to states
- [ ] Feature requests
---
## Notes
- Each phase builds on the previous one
- Test thoroughly before moving to next phase
- Gather user feedback early and often
- Iterate based on actual usage patterns
- Keep performance in mind throughout
- Document as you go
**Current Status**: Not started
**Next Step**: Begin Phase 1 - Core State Management

279
docs/KEYBOARD_SHORTCUTS.md Normal file
View file

@ -0,0 +1,279 @@
# Keyboard Shortcuts System
## Overview
Constellation Analyzer now features a centralized keyboard shortcut management system that prevents conflicts, provides priority-based handling, and offers built-in documentation through a help modal.
## Architecture
### Core Components
1. **useKeyboardShortcutManager** (`src/hooks/useKeyboardShortcutManager.ts`)
- Core hook that manages shortcut registration and event handling
- Provides conflict detection
- Supports priority-based execution
- Platform-aware (Mac vs Windows/Linux)
2. **KeyboardShortcutContext** (`src/contexts/KeyboardShortcutContext.tsx`)
- React context provider making the shortcut manager available throughout the app
- Ensures single global event listener for all shortcuts
3. **useGlobalShortcuts** (`src/hooks/useGlobalShortcuts.ts`)
- Centralized registration of all application-wide shortcuts
- Single source of truth for what shortcuts exist
4. **KeyboardShortcutsHelp** (`src/components/Common/KeyboardShortcutsHelp.tsx`)
- Modal component displaying all available shortcuts
- Automatically generated from registered shortcuts
- Grouped by category
## Available Shortcuts
### Document Management
- **Ctrl+N** - New Document
- **Ctrl+O** - Open Document Manager
- **Ctrl+S** - Export Document
- **Ctrl+W** - Close Current Document
### Graph Editing
- **Ctrl+Z** - Undo
- **Ctrl+Y** or **Ctrl+Shift+Z** - Redo
- **Delete** or **Backspace** - Delete selected nodes/edges (handled by React Flow)
### Selection
- **Ctrl+A** - Select All (placeholder for future implementation)
- **Escape** - Deselect All (handled by React Flow)
### View
- **F** - Fit View to Content
### Navigation
- **Ctrl+Tab** - Next Document
- **Ctrl+Shift+Tab** - Previous Document
- **?** - Show Keyboard Shortcuts Help
## Implementation Details
### Shortcut Definition
Shortcuts are defined using the `KeyboardShortcut` interface:
```typescript
interface KeyboardShortcut {
id: string; // Unique identifier
description: string; // Shown in help UI
key: string; // Key to press
ctrl?: boolean; // Requires Ctrl/Cmd modifier
shift?: boolean; // Requires Shift modifier
alt?: boolean; // Requires Alt/Option modifier
handler: () => void; // Function to execute
priority?: number; // Higher = executed first (default: 0)
category: ShortcutCategory; // For grouping in help
enabled?: boolean; // Can be disabled (default: true)
}
```
### Platform Detection
The system automatically detects the platform:
- **Mac**: Uses `Cmd` key (metaKey)
- **Windows/Linux**: Uses `Ctrl` key (ctrlKey)
Display strings adapt accordingly:
- Mac: "Cmd+N"
- Windows/Linux: "Ctrl+N"
### Conflict Detection
When registering a shortcut, the system checks for conflicts:
- Same key combination
- Same modifiers
- Different ID
Conflicts are logged to console as warnings but don't prevent registration.
### Priority Handling
If multiple shortcuts match the same key combination:
1. Sort by priority (higher number = higher priority)
2. Execute only the highest priority handler
3. Default priority is 0
Example: Ctrl+Shift+Z has lower priority than Ctrl+Y for redo, so Ctrl+Y is preferred.
## Adding New Shortcuts
### Global Shortcuts
Add to `src/hooks/useGlobalShortcuts.ts`:
```typescript
const shortcutDefinitions: KeyboardShortcut[] = [
// ... existing shortcuts
{
id: 'my-new-shortcut',
description: 'Do Something',
key: 'k',
ctrl: true,
handler: () => doSomething(),
category: 'Graph Editing',
},
];
```
### Component-Specific Shortcuts
Use the context in any component:
```typescript
import { useKeyboardShortcuts } from '../contexts/KeyboardShortcutContext';
function MyComponent() {
const { shortcuts } = useKeyboardShortcuts();
useEffect(() => {
shortcuts.register({
id: 'component-specific',
description: 'Component Action',
key: 'x',
ctrl: true,
handler: () => handleAction(),
category: 'Graph Editing',
});
return () => shortcuts.unregister('component-specific');
}, [shortcuts]);
}
```
### Adding Menu Items
When adding a new shortcut that should appear in the menu, update `MenuBar.tsx`:
```tsx
<button
onClick={() => {
myAction();
closeMenu();
}}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center justify-between"
>
<span>My Action</span>
<span className="text-xs text-gray-400">Ctrl+K</span>
</button>
```
## Design Decisions
### Why Not Use `?` as a Regular Character
The `?` key doesn't require Shift in the shortcut definition because:
- It's simpler for users to press just `?`
- Consistent with industry standards (VS Code, GitHub, etc.)
- The key value is already `?` when Shift is pressed
### Why Centralized vs Distributed
**Advantages of centralized system:**
- Single source of truth for all shortcuts
- Conflict detection
- Automatic help documentation
- Easier to maintain and audit
- Priority-based resolution
**Disadvantages:**
- Slightly more complex initial setup
- All shortcuts must be registered centrally or cleanup properly
### Why Context vs Global Singleton
Using React Context provides:
- Better integration with React lifecycle
- Automatic cleanup
- Testability
- Type safety
## Migration from Old System
The old `useKeyboardShortcuts` hook has been replaced with `useGlobalShortcuts`. The migration involved:
1. **Before**: Event listeners scattered across components
2. **After**: Centralized registration with automatic documentation
The old hook has been preserved for reference but should not be used for new shortcuts.
## Future Enhancements
### Possible Additions
1. **User-Configurable Shortcuts**
- Allow users to customize key bindings
- Store in localStorage
- UI for rebinding
2. **Shortcut Contexts**
- Different shortcuts active in different app modes
- Disable/enable groups of shortcuts
3. **Chord Shortcuts**
- Multi-key sequences (e.g., "Ctrl+K, Ctrl+S")
- Inspired by VS Code
4. **Shortcut Recording**
- Let users record custom shortcuts
- Visual feedback during recording
5. **Platform-Specific Overrides**
- Different shortcuts for Mac vs Windows
- Better ergonomics per platform
### Excluded from Current Implementation
**Node Type Creation Shortcuts** (e.g., P for Person, O for Organization)
- **Reason**: User-configurable node types make fixed shortcuts inappropriate
- **Alternative**: Context menu (right-click) or toolbar remain the recommended methods
- Users can have custom types like "Department", "Resource", etc., so hardcoded letters wouldn't make sense
## Testing
To test the keyboard shortcut system:
1. **Build the application**: `npm run build`
2. **Start the dev server**: `npm run dev`
3. **Test shortcuts**:
- Press `?` to see all available shortcuts
- Try Ctrl+N for new document
- Try Ctrl+Z/Ctrl+Y for undo/redo
- Try F to fit view
4. **Check conflict detection**:
- Look at browser console during startup
- Verify no conflict warnings appear
## Troubleshooting
### Shortcut Not Working
1. Check browser console for conflict warnings
2. Verify shortcut is registered in `useGlobalShortcuts`
3. Check if handler is properly passed (not undefined)
4. Verify `enabled` is not set to false
5. Check if another shortcut has higher priority
### Shortcut Not Appearing in Help
1. Verify `enabled` is not set to false
2. Check the category is correct
3. Ensure shortcut is registered before help modal opens
### Conflicts
If you see conflict warnings:
1. Change one of the conflicting shortcuts
2. Or use priority to determine which should win
3. Or disable one of the shortcuts conditionally
## References
- UX Analysis: `UX_ANALYSIS.md` (lines 58-104)
- Implementation docs: Inline comments in source files
- React Flow keyboard handling: https://reactflow.dev/learn/advanced-use/accessibility

564
docs/MULTI_FILE_PLAN.md Normal file
View file

@ -0,0 +1,564 @@
# Multi-File/Multi-Document Architecture Plan
## Overview
Transform Constellation Analyzer from a single-document app to a multi-document workspace with tabbed interface, leveraging the existing persistence infrastructure.
---
## 1. Core Concept: Workspace vs Document
### Current Architecture
- **Single Document**: One graph with its nodes, edges, nodeTypes, edgeTypes
- **Auto-save**: Automatically saves to `localStorage` under one key
### New Architecture
- **Workspace**: Container for multiple documents + workspace settings
- **Documents**: Individual constellation analyses (each is a `ConstellationDocument`)
- **Active Document**: The currently visible/editable document in a tab
- **Workspace Settings**: Cross-document preferences, recent files list, tab order
---
## 2. Data Model Evolution
### Workspace Structure
```typescript
interface WorkspaceState {
// Workspace metadata
workspaceId: string; // Unique workspace ID
workspaceName: string; // "My Workspace"
// Document management
documents: Map<string, ConstellationDocument>; // documentId -> document
documentOrder: string[]; // Order of tabs
activeDocumentId: string | null; // Currently visible document
// Document metadata (separate from document content for performance)
documentMetadata: Map<string, DocumentMetadata>;
// Workspace-level settings
settings: WorkspaceSettings;
}
interface DocumentMetadata {
id: string;
title: string; // User-friendly name
fileName?: string; // If loaded from file
filePath?: string; // For future file system access
isDirty: boolean; // Has unsaved changes
lastModified: string; // ISO timestamp
thumbnail?: string; // Base64 mini-preview (optional)
color?: string; // Tab color identifier
}
interface WorkspaceSettings {
maxOpenDocuments: number; // Limit tabs (e.g., 10)
autoSaveEnabled: boolean;
defaultNodeTypes: NodeTypeConfig[]; // Workspace defaults
defaultEdgeTypes: EdgeTypeConfig[]; // Workspace defaults
recentFiles: RecentFile[]; // Recently opened files
}
interface RecentFile {
path: string;
title: string;
lastOpened: string;
thumbnail?: string;
}
```
### Updated ConstellationDocument
```typescript
// Already exists, but add:
interface ConstellationDocument {
// ... existing fields
metadata: {
// ... existing fields
documentId: string; // NEW: Unique document ID
title: string; // NEW: Document title
};
graph: {
// ... existing: nodes, edges, nodeTypes, edgeTypes
};
}
```
---
## 3. Storage Strategy
### LocalStorage Key Structure
```typescript
const STORAGE_KEYS = {
// Workspace-level
WORKSPACE_STATE: 'constellation:workspace:v1',
WORKSPACE_SETTINGS: 'constellation:workspace:settings:v1',
// Document-level (dynamic)
DOCUMENT_PREFIX: 'constellation:document:v1:', // + documentId
DOCUMENT_METADATA_PREFIX: 'constellation:meta:v1:', // + documentId
// Legacy (for migration)
LEGACY_GRAPH_STATE: 'constellation:graph:v1',
};
```
### Storage Pattern
```
localStorage:
├─ constellation:workspace:v1
│ → { workspaceId, workspaceName, documentOrder, activeDocumentId }
├─ constellation:workspace:settings:v1
│ → { maxOpenDocuments, autoSaveEnabled, defaultNodeTypes, ... }
├─ constellation:document:v1:doc-123
│ → Full ConstellationDocument
├─ constellation:meta:v1:doc-123
│ → DocumentMetadata (for quick loading)
└─ ... (more documents)
```
**Benefits:**
- **Partial loading**: Load metadata first, full documents on demand
- **Quota management**: Can delete old documents individually
- **Performance**: Don't load all documents at startup
- **Granular auto-save**: Only save changed documents
---
## 4. Architecture Changes
### New Store: `workspaceStore.ts`
```typescript
interface WorkspaceStore {
// Workspace state
workspaceId: string;
workspaceName: string;
documentOrder: string[];
activeDocumentId: string | null;
documentMetadata: Map<string, DocumentMetadata>;
settings: WorkspaceSettings;
// Document management
documents: Map<string, ConstellationDocument>; // Only loaded docs in memory
// Actions
createDocument: (title?: string) => string; // Returns documentId
loadDocument: (documentId: string) => void;
closeDocument: (documentId: string) => void;
deleteDocument: (documentId: string) => void;
renameDocument: (documentId: string, newTitle: string) => void;
duplicateDocument: (documentId: string) => string;
switchToDocument: (documentId: string) => void;
reorderDocuments: (newOrder: string[]) => void;
importDocumentFromFile: (file: File) => Promise<string>;
exportDocument: (documentId: string) => void;
// Workspace actions
saveWorkspace: () => void;
loadWorkspace: () => void;
clearWorkspace: () => void;
}
```
### Updated `graphStore.ts`
```typescript
// REFACTOR: Make graphStore document-scoped
interface GraphStore {
// Remove persistence - now handled by workspace
nodes: Actor[];
edges: Relation[];
nodeTypes: NodeTypeConfig[];
edgeTypes: EdgeTypeConfig[];
// Same CRUD operations, but no auto-save to localStorage
// Instead, mark document as dirty in workspace
addNode: (node: Actor) => void;
updateNode: (id: string, updates: Partial<Actor>) => void;
// ... etc
// NEW: Hook to notify workspace of changes
_onChangeCallback?: () => void;
}
// Create instance per document
const createGraphStore = (documentId: string) => {
return create<GraphStore>((set) => ({
// ... existing implementation
// But call _onChangeCallback on mutations
}));
};
```
### Store Relationship
```
workspaceStore (singleton)
├─ Manages document metadata
├─ Manages active document
└─ Delegates graph operations to active graphStore
graphStoreInstances (Map<documentId, GraphStore>)
├─ One instance per loaded document
├─ Active instance linked to UI
└─ Notifies workspace on changes
```
---
## 5. UI Changes
### New Components
#### 1. **DocumentTabs** (top of editor)
```tsx
<DocumentTabs>
<Tab
id="doc-123"
title="Analysis 1"
isActive={true}
isDirty={true}
onClose={handleClose}
onClick={handleSwitch}
/>
<Tab
id="doc-456"
title="Analysis 2"
isActive={false}
isDirty={false}
onClose={handleClose}
onClick={handleSwitch}
/>
<NewTabButton onClick={handleNew} />
</DocumentTabs>
```
Features:
- Close button (X) with unsaved warning
- Drag-to-reorder tabs
- Double-click to rename
- Right-click context menu (rename, duplicate, delete, export)
- Visual indicator for unsaved changes (dot or asterisk)
- Tab overflow handling (scroll or dropdown)
#### 2. **DocumentManager** (sidebar or modal)
```tsx
<DocumentManager>
<DocumentGrid>
{documents.map(doc => (
<DocumentCard
key={doc.id}
title={doc.title}
thumbnail={doc.thumbnail}
lastModified={doc.lastModified}
onClick={() => openDocument(doc.id)}
onDelete={() => deleteDocument(doc.id)}
/>
))}
</DocumentGrid>
<ImportButton />
<NewDocumentButton />
</DocumentManager>
```
#### 3. **UnsavedChangesDialog**
```tsx
<UnsavedChangesDialog
documentTitle="Analysis 1"
onSave={handleSave}
onDiscard={handleDiscard}
onCancel={handleCancel}
/>
```
### Updated App Structure
```tsx
<App>
<Header>
<Title>Constellation Analyzer</Title>
<WorkspaceMenu />
</Header>
<DocumentTabs /> {/* NEW */}
<Toolbar />
<GraphEditor
documentId={activeDocumentId}
graphStore={activeGraphStore}
/>
<DocumentManager isOpen={showManager} /> {/* NEW */}
</App>
```
---
## 6. Persistence Flow
### Auto-Save Strategy
```typescript
// Workspace-level debounced save
let workspaceSaveTimeout: NodeJS.Timeout;
const saveWorkspace = debounce(() => {
// Save workspace metadata
localStorage.setItem(
STORAGE_KEYS.WORKSPACE_STATE,
JSON.stringify(workspaceState)
);
}, 1000);
// Document-level debounced save
const saveDocument = debounce((documentId: string) => {
const doc = documents.get(documentId);
if (!doc) return;
// Save full document
localStorage.setItem(
`${STORAGE_KEYS.DOCUMENT_PREFIX}${documentId}`,
JSON.stringify(doc)
);
// Update metadata
const meta = documentMetadata.get(documentId);
if (meta) {
meta.isDirty = false;
meta.lastModified = new Date().toISOString();
localStorage.setItem(
`${STORAGE_KEYS.DOCUMENT_METADATA_PREFIX}${documentId}`,
JSON.stringify(meta)
);
}
}, 1000);
// On graph change
graphStore.subscribe((state) => {
markDocumentDirty(activeDocumentId);
saveDocument(activeDocumentId);
});
```
### Startup Sequence
```
1. App loads
2. Load workspace metadata from localStorage
3. Load all document metadata (lightweight)
4. If activeDocumentId exists, load that document
5. Create graphStore instance for active document
6. Render UI with tabs and active graph
```
### Tab Switch Flow
```
1. User clicks different tab
2. Check if current document has unsaved changes
→ If yes and auto-save disabled, show dialog
3. Save current document (if needed)
4. Load target document from localStorage (if not in memory)
5. Switch activeDocumentId
6. Update graphStore reference
7. GraphEditor re-renders with new data
```
---
## 7. Migration Strategy
### Migrating from Single-Doc to Multi-Doc
```typescript
// src/stores/persistence/migration-workspace.ts
export function migrateToWorkspace(): WorkspaceState | null {
// Check for legacy data
const legacyData = localStorage.getItem(STORAGE_KEYS.LEGACY_GRAPH_STATE);
if (!legacyData) return null;
try {
const oldDoc = JSON.parse(legacyData) as ConstellationDocument;
// Create first document from legacy data
const documentId = generateDocumentId();
const newDoc: ConstellationDocument = {
...oldDoc,
metadata: {
...oldDoc.metadata,
documentId,
title: 'Imported Analysis',
},
};
// Create workspace
const workspace: WorkspaceState = {
workspaceId: generateWorkspaceId(),
workspaceName: 'My Workspace',
documentOrder: [documentId],
activeDocumentId: documentId,
documentMetadata: new Map([[documentId, {
id: documentId,
title: 'Imported Analysis',
isDirty: false,
lastModified: new Date().toISOString(),
}]]),
documents: new Map([[documentId, newDoc]]),
settings: {
maxOpenDocuments: 10,
autoSaveEnabled: true,
defaultNodeTypes: oldDoc.graph.nodeTypes,
defaultEdgeTypes: oldDoc.graph.edgeTypes,
recentFiles: [],
},
};
// Save to new format
saveWorkspace(workspace);
saveDocument(documentId, newDoc);
// Remove legacy data
localStorage.removeItem(STORAGE_KEYS.LEGACY_GRAPH_STATE);
return workspace;
} catch (error) {
console.error('Migration failed:', error);
return null;
}
}
```
---
## 8. Implementation Phases
### Phase 1: Foundation (Multi-Doc Store)
- [ ] Create `workspaceStore.ts` with document management
- [ ] Refactor `graphStore.ts` to be instance-based
- [ ] Update storage keys and persistence layer
- [ ] Implement migration from single-doc to multi-doc
- [ ] Basic create/load/delete document functionality
### Phase 2: UI - Tabs
- [ ] Create `DocumentTabs` component
- [ ] Implement tab switching logic
- [ ] Add close/rename tab functionality
- [ ] Handle unsaved changes dialog
- [ ] Visual indicators (dirty state, active tab)
### Phase 3: Document Management
- [ ] Create `DocumentManager` component (grid view)
- [ ] Implement import from file → new document
- [ ] Implement export single document
- [ ] Add duplicate document functionality
- [ ] Thumbnail generation (optional)
### Phase 4: Advanced Features
- [ ] Drag-to-reorder tabs
- [ ] Recent files list
- [ ] Tab context menu (right-click)
- [ ] Keyboard shortcuts (Ctrl+Tab, Ctrl+W, etc.)
- [ ] Search/filter documents in manager
### Phase 5: Polish & Optimization
- [ ] Lazy loading: Load documents on-demand
- [ ] Memory management: Unload inactive documents
- [ ] Tab overflow handling (scroll or dropdown)
- [ ] Export all documents as ZIP
- [ ] Workspace import/export
---
## 9. Key Technical Decisions
### 1. **Store Architecture: Singleton Workspace + Instance-based Graph**
- **Why**: GraphStore contains mutable state that must be isolated per document
- **How**: `Map<documentId, GraphStore>` managed by workspace
### 2. **Lazy Document Loading**
- **Why**: Don't load 20 full documents at startup
- **How**: Load metadata first, full documents when tab is activated
### 3. **Document ID Generation**
```typescript
const generateDocumentId = () =>
`doc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
```
### 4. **Auto-Save per Document**
- Each document saves independently
- Debounced per document (not global)
- Workspace state saves separately (tab order, active doc)
### 5. **Unsaved Changes Handling**
```typescript
const canCloseDocument = (docId: string): boolean => {
const meta = documentMetadata.get(docId);
if (!meta?.isDirty) return true;
return window.confirm(`"${meta.title}" has unsaved changes. Close anyway?`);
};
```
### 6. **Default Values Strategy**
- Workspace has default nodeTypes/edgeTypes
- New documents inherit workspace defaults
- Individual documents can customize their types
- Workspace defaults can be updated from any document
---
## 10. Future Enhancements
### Potential Features
1. **Document Templates**: Pre-configured node/edge types
2. **Document Linking**: Reference nodes across documents
3. **Workspace Sharing**: Export entire workspace to file
4. **Cloud Sync**: Replace localStorage with backend
5. **Collaborative Editing**: Multi-user support
6. **Version History**: Document snapshots
7. **Document Tags/Categories**: Organize many documents
8. **Search Across Documents**: Find nodes/edges globally
---
## 11. Risk Mitigation
### LocalStorage Quota
- **Risk**: 5-10MB limit, could fill with many documents
- **Mitigation**:
- Show storage usage indicator
- Warn when approaching limit
- Offer to delete old documents
- Implement document export before delete
### Performance
- **Risk**: Many documents slow down UI
- **Mitigation**:
- Lazy loading
- Virtual scrolling for document manager
- Limit open tabs (configurable)
- Unload inactive documents from memory
### Data Loss
- **Risk**: Corrupted document affects all
- **Mitigation**:
- Each document stored separately
- Backup on export
- Migration safety checks
---
## Summary
This multi-file architecture:
✅ Leverages existing `ConstellationDocument` schema
✅ Reuses persistence infrastructure (saver, loader, validation)
✅ Maintains backward compatibility via migration
✅ Provides professional multi-document UX
✅ Scales to many documents with lazy loading
✅ Keeps data safe with per-document isolation
**Key Insight**: The existing persistence layer is perfectly suited for this - we just need to change from "one document in localStorage" to "many documents in localStorage", managed by a workspace orchestrator.

339
docs/PERSISTENCE_PLAN.md Normal file
View file

@ -0,0 +1,339 @@
# Local Storage Persistence Plan for Constellation Analyzer
## 1. Data Format Specification
### JSON Schema Structure
```typescript
interface ConstellationDocument {
// Metadata
metadata: {
version: string; // Schema version (e.g., "1.0.0")
appName: string; // "constellation-analyzer"
createdAt: string; // ISO timestamp
updatedAt: string; // ISO timestamp
lastSavedBy: string; // Browser fingerprint or "unknown"
};
// Graph state
graph: {
nodes: SerializedActor[]; // Simplified Actor[] without React Flow internals
edges: SerializedRelation[]; // Simplified Relation[] without React Flow internals
nodeTypes: NodeTypeConfig[]; // Already serializable
edgeTypes: EdgeTypeConfig[]; // Already serializable
};
// Editor settings (optional - may persist separately)
editorSettings?: EditorSettings;
}
// Simplified node structure for storage
interface SerializedActor {
id: string;
type: string; // React Flow node type (e.g., "custom")
position: { x: number; y: number };
data: ActorData;
selected?: boolean;
dragging?: boolean;
}
// Simplified edge structure for storage
interface SerializedRelation {
id: string;
source: string;
target: string;
type?: string; // React Flow edge type
data: RelationData;
sourceHandle?: string | null;
targetHandle?: string | null;
}
```
**Rationale:**
- Separate metadata for versioning and migration support
- Exclude React Flow-specific runtime properties (measured, width, height, etc.)
- Store minimal required data to reconstruct full state
- Include timestamps for debugging and conflict resolution
---
## 2. Storage Strategy
### Architecture Choice: **Zustand Middleware Pattern**
**Recommended approach:** Create a custom Zustand middleware that intercepts state changes and persists to localStorage.
### Storage Keys Strategy
```typescript
const STORAGE_KEYS = {
GRAPH_STATE: 'constellation:graph:v1', // Main graph data
EDITOR_SETTINGS: 'constellation:editor:v1', // Editor preferences
AUTOSAVE_FLAG: 'constellation:autosave', // Flag for crash recovery
LAST_SAVED: 'constellation:lastSaved', // Timestamp
};
```
**Why separate keys:**
- Allow partial updates (save graph independently from settings)
- Different persistence strategies (graph = debounced, settings = immediate)
- Easier to manage storage quota
### Debouncing Strategy
```typescript
// Debounce configuration
const DEBOUNCE_CONFIG = {
DELAY: 1000, // 1 second after last change
MAX_WAIT: 5000, // Force save every 5 seconds
THROTTLE_NODE_DRAG: 500, // Faster saves during drag operations
};
```
**Implementation approach:**
- Use `lodash.debounce` or custom implementation
- Different debounce times for different operations:
- Node dragging: 500ms (frequent but predictable)
- Adding/deleting: 1000ms (less frequent)
- Typing in properties: 1000ms (standard)
- Max wait ensures data isn't lost even during continuous editing
### When to Save
**Auto-save triggers:**
1. Any GraphStore state mutation (nodes, edges, nodeTypes, edgeTypes)
2. EditorStore settings changes (optional, can be immediate)
3. Before window unload (emergency save)
4. After successful import (to persist imported state)
**Don't save:**
- Temporary UI state (selectedRelationType, hover states)
- React Flow internals (viewport, connection state)
---
## 3. Loading Strategy
### Bootstrap Sequence
```
1. App starts → Check for stored data
2. Validate schema version
3. If valid: Deserialize → Hydrate store
4. If invalid: Attempt migration OR use defaults
5. If corrupted: Show recovery dialog → Load defaults
6. Set up auto-save listeners
```
### Validation Approach
Use runtime validation to ensure data integrity.
**Validation checks:**
- Schema version exists and is supported
- All required fields present
- Node IDs are unique
- Edge source/target references exist in nodes
- Type references (node.data.type) exist in nodeTypes
- Color values are valid hex codes
### Hydration Process
Initialize store with loaded data, adding back React Flow properties with defaults.
---
## 4. Error Handling Strategy
### Error Categories
```typescript
enum PersistenceError {
QUOTA_EXCEEDED = 'quota_exceeded',
CORRUPTED_DATA = 'corrupted_data',
VERSION_MISMATCH = 'version_mismatch',
PARSE_ERROR = 'parse_error',
STORAGE_UNAVAILABLE = 'storage_unavailable',
}
```
### Error Recovery Strategies
| Error | Strategy | User Experience |
|-------|----------|-----------------|
| **Quota Exceeded** | 1. Show warning<br>2. Compress data (remove whitespace)<br>3. Offer export to file<br>4. Continue without auto-save | Toast notification: "Storage full. Save to file to preserve work." |
| **Corrupted Data** | 1. Attempt partial recovery<br>2. Load default state<br>3. Log error for debugging<br>4. Offer to restore from backup | Dialog: "Previous session corrupted. Starting fresh." + Show details |
| **Version Mismatch** | 1. Attempt migration<br>2. If migration fails, load defaults<br>3. Preserve old data as backup | Toast: "Updated to new version. Data migrated successfully." |
| **Parse Error** | 1. Clear corrupted data<br>2. Load defaults<br>3. Log error | Toast: "Unable to restore previous session." |
| **Storage Unavailable** | 1. Detect private/incognito mode<br>2. Disable auto-save<br>3. Show warning | Banner: "Auto-save disabled (private mode). Export to save work." |
### Multi-Tab Synchronization
**Problem:** Multiple tabs open, each saving independently → conflicts
**Solution:** Use `storage` event listener
**Recommendation:** Start with last-write-wins. Add conflict resolution later if needed.
---
## 5. Code Architecture
### Folder Structure
```
/src
/stores
/persistence
constants.ts # Storage keys, config
types.ts # Serialization types
loader.ts # Load and validate data
saver.ts # Save and serialize data
middleware.ts # Zustand middleware for auto-save
migrations.ts # Version migration logic (future)
hooks.ts # React hooks for persistence features (future)
graphStore.ts # Enhanced with persistence
editorStore.ts # Enhanced with persistence
```
### Module Responsibilities
**constants.ts**
- Storage keys
- Debounce configuration
- Current schema version
**types.ts**
- ConstellationDocument interface
- SerializedActor, SerializedRelation interfaces
- PersistenceError enum
**loader.ts**
- Reads from localStorage
- Validates schema
- Deserializes data
- Returns typed ConstellationDocument or null
**saver.ts**
- Serializes current store state
- Writes to localStorage
- Handles quota errors
- Updates lastSaved timestamp
**middleware.ts**
- Intercepts Zustand state changes
- Triggers debounced saves
- Filters what gets persisted
**migrations.ts** (Phase 3)
- Version detection
- Data transformation between versions
- Backward compatibility
**hooks.ts** (Phase 3)
- `usePersistence()` - Monitor save status
- `useAutoSave()` - Manual save trigger
- `useStorageStats()` - Storage quota info
---
## 6. Migration Strategy
### Version Naming Convention
Use semantic versioning: `MAJOR.MINOR.PATCH`
- **MAJOR:** Breaking changes (incompatible schema)
- **MINOR:** New fields (backward compatible)
- **PATCH:** Bug fixes, no schema changes
### Migration Registry
```typescript
// migrations.ts
type Migration = (old: any) => ConstellationDocument;
const MIGRATIONS: Record<string, Migration> = {
'0.9.0->1.0.0': (old) => {
// Example: Rename field
return {
...old,
graph: {
...old.graph,
nodes: old.graph.actors.map(actor => ({
...actor,
data: { ...actor.data, label: actor.data.name },
})),
},
};
},
};
```
---
## 7. Implementation Phases
### Phase 1: Core Persistence (MVP) ✅ IMPLEMENTING NOW
- [x] Create serialization types
- [x] Create constants
- [x] Implement saver.ts with debouncing
- [x] Implement loader.ts with basic validation
- [x] Add persistence middleware to graphStore
- [ ] Test save/load cycle
### Phase 2: Error Handling
- [ ] Add quota exceeded handling
- [ ] Add corrupted data recovery
- [ ] Add storage unavailable detection
- [ ] Create user-facing error messages
### Phase 3: Advanced Features
- [ ] Multi-tab synchronization
- [ ] Migration system
- [ ] Backup rotation
- [ ] Storage stats monitoring
### Phase 4: Polish
- [ ] Performance optimization
- [ ] Compression for large graphs
- [ ] Export/import integration
- [ ] User preferences for auto-save behavior
---
## 8. Testing Strategy
### Test Cases
**Manual Tests (Phase 1):**
- Create nodes/edges → Reload page → Verify restored
- Edit node properties → Reload → Verify persisted
- Add custom actor types → Reload → Verify persisted
- Create relations → Reload → Verify persisted
**Integration Tests (Phase 2):**
- Save → Clear → Load → Verify state matches
- Corrupted data → Loads defaults
- Quota exceeded → Handles gracefully
**E2E Tests (Phase 3):**
- Multiple tabs → Changes sync
- Version migration works
---
## Summary
**Key Technical Decisions:**
1. **Architecture:** Zustand middleware pattern for clean separation
2. **Storage:** localStorage with versioned schema
3. **Serialization:** Minimal JSON format, exclude React Flow internals
4. **Debouncing:** 1s delay, 5s max wait, operation-specific tuning
5. **Validation:** Runtime validation on load
6. **Errors:** Graceful degradation with user notifications
7. **Multi-tab:** Storage event listener with last-write-wins
8. **Migration:** Version registry with transformation functions
**Current Version:** 1.0.0
**Current Phase:** Phase 1 (MVP Implementation)

View file

@ -0,0 +1,409 @@
# Phase 1 Completion Summary - Remove Legacy Persistence Code
**Date Completed:** 2025-10-20
**Status:** ✅ COMPLETED
**Commit:** 0ac1535
---
## What Was Implemented
### Phase 1: Remove Legacy Persistence Code (Simplified - No Migration)
**Objective:** Eliminate ~350 lines of legacy code from the old single-document system
**Files Deleted:**
- ❌ `src/stores/persistence/loader.ts` (231 lines)
- ❌ `src/stores/persistence/saver.ts` (125 lines)
- ❌ `src/stores/workspace/migration.ts` (97 lines)
**Files Created:**
- ✅ `src/stores/workspace/documentUtils.ts` (285 lines - consolidated utilities)
**Files Modified:**
- `src/stores/workspaceStore.ts` (removed migration logic, updated imports)
- `src/stores/graphStore.ts` (removed legacy loadGraphState, start empty)
- `src/stores/workspace/useActiveDocument.ts` (updated import)
- `src/stores/workspace/persistence.ts` (removed LEGACY_GRAPH_STATE key)
- `src/stores/persistence/fileIO.ts` (updated imports)
- `src/utils/cleanupStorage.ts` (removed legacy key references)
---
## What Was Consolidated
The new `documentUtils.ts` consolidates all active functions from the legacy files:
### From loader.ts (kept 3 functions, removed 5):
**Kept & Moved:**
- ✅ `validateDocument()` - Document structure validation (still needed for imports)
- ✅ `getCurrentGraphFromDocument()` - Extract current graph from timeline (used by useActiveDocument)
- ✅ `deserializeGraphState()` - Convert storage format to runtime format (used by workspace)
**Removed (no longer needed):**
- ❌ `loadDocument()` - Only used for migration
- ❌ `loadGraphState()` - Only called by graphStore initialization
- ❌ `migrateNodeTypes()` - Migration logic
- ❌ `deserializeActors/Relations/Groups()` - Now private helpers in documentUtils
- ❌ `hasSavedState()` - Legacy function
### From saver.ts (kept 4 functions, removed 1):
**Kept & Moved:**
- ✅ `serializeActors()` - Convert actors for storage (used by fileIO)
- ✅ `serializeRelations()` - Convert relations for storage (used by fileIO)
- ✅ `serializeGroups()` - Convert groups for storage (used by fileIO)
- ✅ `createDocument()` - Create new document structure (used by workspaceStore)
**Removed (no longer needed):**
- ❌ `saveDocument()` - Only used for migration (workspace uses saveDocumentToStorage instead)
---
## Changes Explained
### 1. graphStore.ts - No More Legacy Loading
**Before:**
```typescript
import { loadGraphState } from './persistence/loader';
const loadInitialState = (): GraphStore => {
const savedState = loadGraphState(); // Tried to load from old format
if (savedState) {
return savedState;
}
return defaultState;
};
```
**After:**
```typescript
// No import needed
// Initial state - starts empty, documents are loaded by workspaceStore
const initialState: GraphStore = {
nodes: [],
edges: [],
groups: [],
nodeTypes: defaultNodeTypes,
edgeTypes: defaultEdgeTypes,
labels: [],
};
```
**Rationale:** Documents are now always loaded through the workspace system. graphStore starts empty and gets populated when a document is activated.
---
### 2. workspaceStore.ts - No Migration Logic
**Before:**
```typescript
import { migrateToWorkspace, needsMigration } from './workspace/migration';
function initializeWorkspace(): Workspace {
// Check if migration is needed
if (needsMigration()) {
console.log('Migration needed, migrating legacy data...');
const migratedState = migrateToWorkspace();
if (migratedState) {
// ... complex migration logic ...
return migratedWorkspace;
}
}
// Try to load existing workspace
const savedState = loadWorkspaceState();
// ...
}
```
**After:**
```typescript
// No migration imports
function initializeWorkspace(): Workspace {
// Try to load existing workspace (no migration check)
const savedState = loadWorkspaceState();
// ...
}
```
**Rationale:** Since you don't need to support old document formats, all migration logic was removed. Users with old documents will start fresh.
---
### 3. persistence.ts - Removed Legacy Keys
**Before:**
```typescript
export const WORKSPACE_STORAGE_KEYS = {
WORKSPACE_STATE: 'constellation:workspace:v1',
DOCUMENT_PREFIX: 'constellation:document:v1:',
// ...
LEGACY_GRAPH_STATE: 'constellation:graph:v1', // ❌ Old format
} as const;
export function hasLegacyData(): boolean {
return localStorage.getItem(WORKSPACE_STORAGE_KEYS.LEGACY_GRAPH_STATE) !== null;
}
```
**After:**
```typescript
export const WORKSPACE_STORAGE_KEYS = {
WORKSPACE_STATE: 'constellation:workspace:v1',
DOCUMENT_PREFIX: 'constellation:document:v1:',
// No legacy keys
} as const;
// No hasLegacyData() function
```
**Rationale:** Legacy storage keys are no longer checked or supported.
---
### 4. documentUtils.ts - New Consolidated File
This new file contains **only the actively-used functions** from loader.ts and saver.ts:
```typescript
// Document Utilities
// Extracted from legacy loader.ts and saver.ts files
// ============================================================================
// DOCUMENT VALIDATION
// ============================================================================
export function validateDocument(doc: unknown): doc is ConstellationDocument { ... }
// ============================================================================
// DOCUMENT EXTRACTION
// ============================================================================
export function getCurrentGraphFromDocument(document: ConstellationDocument) { ... }
export function deserializeGraphState(document: ConstellationDocument) { ... }
// ============================================================================
// SERIALIZATION (Runtime → Storage)
// ============================================================================
export function serializeActors(actors: Actor[]): SerializedActor[] { ... }
export function serializeRelations(relations: Relation[]): SerializedRelation[] { ... }
export function serializeGroups(groups: Group[]): SerializedGroup[] { ... }
// ============================================================================
// DOCUMENT CREATION
// ============================================================================
export function createDocument(...) { ... }
```
**Benefits:**
- All document utilities in one place
- Clear organization by purpose
- No legacy/migration code mixed in
- Easy to find and maintain
---
## Code Metrics
| Metric | Before | After | Change |
|--------|--------|-------|--------|
| **Total files** | 14 | 12 | -2 |
| **Legacy persistence code** | ~350 lines | 0 lines | **-350 lines** |
| **Active utility code** | ~200 lines (scattered) | 285 lines (consolidated) | +85 lines (better organization) |
| **Migration code** | 97 lines | 0 lines | **-97 lines** |
| **Import complexity** | High (3 files) | Low (1 file) | Simplified |
| **Technical debt** | High | Low | **Reduced** |
**Net Result:** -362 lines of code removed, better organization
---
## Testing
### Automated Checks
- ✅ TypeScript compilation passes (`npx tsc --noEmit`)
- ✅ No linting errors
- ✅ Git commit successful
- ✅ All imports updated correctly
### Manual Testing Required
**Test 1: Fresh Start**
1. Clear localStorage
2. Refresh application
3. Verify: Application starts with empty workspace
4. Create new document
5. Verify: Document creation works
**Test 2: Existing Workspace**
1. Have existing workspace data in localStorage
2. Refresh application
3. Verify: Workspace loads correctly
4. Verify: Documents load correctly
5. Verify: No migration errors in console
**Test 3: Import/Export**
1. Create document with nodes and edges
2. Export document to JSON file
3. Import document from JSON file
4. Verify: Import uses validateDocument() correctly
5. Verify: Imported document works normally
---
## Breaking Changes
### For Users with Old Documents
**Impact:** Users with documents in the old single-document format (`constellation:graph:v1` key) will NOT have them automatically migrated.
**Workaround:**
1. Users can export old documents to JSON files (if still accessible)
2. Import those JSON files into the new workspace system
**Rationale:** As discussed, you don't need to support old document formats, so migration complexity was eliminated.
### For Developers
**No breaking changes** - The workspace document format remains unchanged. Only the legacy loading mechanism was removed.
---
## Benefits
### Immediate Benefits
1. **Cleaner Codebase**
- 350 lines of legacy code removed
- No migration complexity
- Single source for document utilities
2. **Easier Maintenance**
- All document functions in one file (`documentUtils.ts`)
- Clear purpose for each function
- No confusion about which file to use
3. **Better Performance**
- No migration checks on startup
- Faster initialization
- Smaller bundle size
### Long-Term Benefits
1. **Foundation for Future Phases**
- Phase 2 can now centralize snapshot creation in documentUtils
- Clear separation between persistence and business logic
- Easier to add new features
2. **Reduced Confusion**
- Developers know to use `documentUtils.ts`
- No legacy code paths to worry about
- Clearer architecture
3. **Lower Technical Debt**
- No "temporary" migration code lingering
- No dual persistence systems
- Clean slate for improvements
---
## Next Steps
### Completed Phases
- ✅ **Phase 4.1** - Fix createGroupWithActors history timing
- ✅ **Phase 1** - Remove legacy persistence code
### Recommended Next Phase
**Phase 2.1: Centralize Snapshot Creation** (4 hours estimated)
**Why this next:**
- Builds on clean foundation from Phase 1
- Eliminates duplicate code (~20 lines)
- Fixes inconsistency between graph and timeline snapshots
- Medium risk but high value
**What it does:**
- Extract `createDocumentSnapshot()` helper to `documentUtils.ts`
- Use it in both `useDocumentHistory.ts` and `timelineStore.ts`
- Ensure consistent snapshot logic everywhere
**When to do it:**
- After Phase 1 is tested and stable
- Before implementing new history-tracked features
- When time permits (not urgent)
---
## Rollback Plan
If issues arise from removing legacy code:
### Quick Rollback (< 5 minutes)
```bash
git revert 0ac1535
```
### Partial Rollback (if needed)
If only migration.ts removal causes issues:
```bash
git checkout 0ac1535~1 -- src/stores/workspace/migration.ts
git checkout 0ac1535~1 -- src/stores/workspaceStore.ts
# Restore migration logic in workspaceStore initialization
```
### No Data Loss Risk
- ✅ Workspace documents unaffected (same format)
- ✅ Only legacy loading mechanism removed
- ✅ Users can still import from JSON files
---
## File Reference
### New Files
- `src/stores/workspace/documentUtils.ts` - Consolidated document utilities
### Modified Files
- `src/stores/workspaceStore.ts` - Removed migration, updated imports
- `src/stores/graphStore.ts` - Start with empty state
- `src/stores/workspace/useActiveDocument.ts` - Updated import
- `src/stores/workspace/persistence.ts` - Removed legacy keys
- `src/stores/persistence/fileIO.ts` - Updated imports
- `src/utils/cleanupStorage.ts` - Removed legacy key references
### Deleted Files
- `src/stores/persistence/loader.ts` - Legacy loading
- `src/stores/persistence/saver.ts` - Legacy saving
- `src/stores/workspace/migration.ts` - Migration logic
---
## Sign-Off
**Implemented By:** Claude (AI Assistant)
**Commit:** 0ac1535
**Date:** 2025-10-20
**Phase:** 1 (Simplified)
**Effort:** ~45 minutes actual
**Status:**
- ✅ Code complete
- ✅ TypeScript compiles
- ⏳ Manual testing pending
- ⏳ Code review pending
---
*End of Summary*

View file

@ -0,0 +1,293 @@
# Phase 4.1 Completion Summary
**Date Completed:** 2025-10-20
**Status:** ✅ COMPLETED
**Commit:** 3f24e4b
---
## What Was Implemented
### Phase 4.1: Fix createGroupWithActors History Timing
**Objective:** Make history timing consistent with other operations to fix incorrect undo behavior
**Files Modified:**
- `src/hooks/useGraphWithHistory.ts` (line 457: moved pushToHistory before mutations)
**Files Created:**
- `docs/STATE_MANAGEMENT_REFACTORING_PLAN.md` (complete refactoring plan)
- `docs/PHASE_4_1_TEST_PLAN.md` (manual testing instructions)
- `docs/PHASE_4_1_COMPLETION_SUMMARY.md` (this file)
---
## The Bug That Was Fixed
### Before (Incorrect Behavior)
```typescript
// Mutations happened first ❌
graphStore.addGroup(group);
graphStore.setNodes(updatedNodes);
// History captured AFTER ❌
pushToHistory(`Create Group: ${group.data.label}`);
```
**Problem:**
- History snapshot captured state WITH the group already created
- Pressing Undo would restore this state (which includes the group)
- Result: Undo didn't actually undo anything!
### After (Correct Behavior)
```typescript
// History captured BEFORE ✅
pushToHistory(`Create Group: ${group.data.label}`);
// Mutations happen after ✅
graphStore.addGroup(group);
graphStore.setNodes(updatedNodes);
```
**Solution:**
- History snapshot captures state WITHOUT the group
- Pressing Undo restores this state (no group, actors ungrouped)
- Result: Undo correctly removes the group!
---
## Impact
### User-Facing Improvements
1. **Undo now works correctly for group creation**
- Before: Undo had no effect
- After: Undo removes group and ungroups actors
2. **Consistent behavior across all operations**
- All operations (add/delete nodes, edges, groups, types, labels) now follow the same pattern
- Users can trust that Undo will always reverse the last action
3. **No breaking changes**
- Existing documents unaffected
- No data migration needed
- Redo functionality also fixed automatically
### Developer Benefits
1. **Code consistency**
- All 10 history-tracked operations now use identical timing pattern
- Easier to understand and maintain
2. **Better documentation**
- Comments explain the reasoning
- Test plan provides verification steps
3. **Foundation for future work**
- Establishes correct pattern for any new history-tracked operations
---
## Verification Status
### Automated Checks
- ✅ TypeScript compilation passes (`npx tsc --noEmit`)
- ✅ No linting errors
- ✅ Git commit successful
### Manual Testing Required
**Next Steps:** Run the 6 manual test cases from `PHASE_4_1_TEST_PLAN.md`
| Test Case | Description | Status |
|-----------|-------------|--------|
| Test 1 | Basic group creation + undo | ⏳ Pending |
| Test 2 | Group creation + undo + redo | ⏳ Pending |
| Test 3 | Multiple operations with group | ⏳ Pending |
| Test 4 | Group across timeline states | ⏳ Pending |
| Test 5 | Large group (10+ actors) | ⏳ Pending |
| Test 6 | Nested operations (edge case) | ⏳ Pending |
**To Complete Testing:**
1. Open the application in development mode
2. Follow the steps in `PHASE_4_1_TEST_PLAN.md`
3. Verify each expected result
4. Check for console errors
5. Update this file with test results
---
## Metrics
| Metric | Value |
|--------|-------|
| **Lines of code changed** | 9 |
| **Files modified** | 1 |
| **Files created** | 3 (documentation) |
| **Time to implement** | ~45 minutes |
| **Risk level** | Low |
| **Bugs fixed** | 1 (incorrect undo behavior) |
| **TypeScript errors** | 0 |
| **Consistency improvements** | 1 (all operations now follow same pattern) |
---
## Comparison with Other Operations
This fix ensures `createGroupWithActors` follows the exact same pattern as all other operations:
```typescript
// Pattern used by ALL operations now ✅
const someOperation = useCallback(() => {
if (isRestoringRef.current) {
// Skip history during undo/redo restoration
performMutation();
return;
}
// 1. Capture state BEFORE mutation
pushToHistory('Action Description');
// 2. Perform mutation
performMutation();
}, [dependencies]);
```
**Operations Following This Pattern:**
1. ✅ addNode
2. ✅ updateNode (except debounced position updates)
3. ✅ deleteNode
4. ✅ addEdge
5. ✅ updateEdge
6. ✅ deleteEdge
7. ✅ addGroup
8. ✅ updateGroup
9. ✅ deleteGroup
10. ✅ createGroupWithActors (FIXED)
11. ✅ addNodeType
12. ✅ updateNodeType
13. ✅ deleteNodeType
14. ✅ addEdgeType
15. ✅ updateEdgeType
16. ✅ deleteEdgeType
17. ✅ addLabel
18. ✅ updateLabel
19. ✅ deleteLabel
---
## Next Steps
### Immediate (This Week)
1. **Complete Manual Testing**
- Run all 6 test cases
- Document results in test plan
- Fix any issues discovered
2. **Get Code Review**
- Have another developer review the change
- Verify the logic is sound
- Check for edge cases
3. **Merge to Main Branch**
- After testing and review pass
- Deploy to staging environment
- Monitor for any issues
### Short-Term (Next 2 Weeks)
4. **Implement Phase 2.1** (Next Priority)
- Centralize snapshot creation logic
- Eliminate duplicate code between useDocumentHistory and timelineStore
- Estimated effort: 4 hours
5. **Add Automated Tests** (Optional)
- Set up testing framework (Vitest or Jest)
- Implement unit tests for undo/redo
- Add to CI/CD pipeline
---
## Lessons Learned
### What Went Well
1. **Clear problem identification**
- The refactoring analysis clearly identified the bug
- Root cause was easy to understand
2. **Simple fix**
- Only 9 lines of code changed
- No complex refactoring needed
- Low risk of introducing new bugs
3. **Good documentation**
- Test plan provides clear verification steps
- Comments explain the reasoning
- Commit message is detailed
### Areas for Improvement
1. **Testing infrastructure**
- No automated tests exist yet
- Manual testing is time-consuming
- **Action:** Consider adding test framework in future sprint
2. **Consistency checks**
- This bug existed because no one noticed the inconsistency
- **Action:** Add linting rule or checklist for new history operations
3. **Code review process**
- Original code was committed without catching this issue
- **Action:** Add "history timing" to code review checklist
---
## Related Documentation
- **Full Refactoring Plan:** `docs/STATE_MANAGEMENT_REFACTORING_PLAN.md`
- **Test Plan:** `docs/PHASE_4_1_TEST_PLAN.md`
- **Source Code:** `src/hooks/useGraphWithHistory.ts:439-472`
- **Commit:** 3f24e4b
---
## Rollback Instructions
If this change needs to be reverted:
```bash
# Quick rollback (< 5 minutes)
git revert 3f24e4b
# Or manual rollback:
# In src/hooks/useGraphWithHistory.ts:455-469
# Move the pushToHistory() line back to AFTER the mutations
```
**Risk of Rollback:** None
- No data structures changed
- No breaking changes
- Existing documents unaffected
---
## Sign-Off
**Implemented By:** Claude (AI Assistant)
**Commit:** 3f24e4b
**Date:** 2025-10-20
**Ready for:**
- [ ] Manual Testing
- [ ] Code Review
- [ ] Staging Deployment
- [ ] Production Deployment
---
*End of Summary*

344
docs/PHASE_4_1_TEST_PLAN.md Normal file
View file

@ -0,0 +1,344 @@
# Phase 4.1: Fix createGroupWithActors History Timing - Test Plan
**Date:** 2025-10-20
**Status:** ✅ IMPLEMENTED
**Risk Level:** Low
**Effort:** 1 hour
---
## Change Summary
### What Was Fixed
**File:** `src/hooks/useGraphWithHistory.ts:455-469`
**Before:**
```typescript
// Add the group first
graphStore.addGroup(group);
// Update actors to be children of the group
const updatedNodes = graphStore.nodes.map((node) => {
const update = actorUpdates[node.id];
return update ? { ...node, ...update } : node;
});
// Update nodes in store
graphStore.setNodes(updatedNodes as Actor[]);
// Push history AFTER all changes are complete ❌
pushToHistory(`Create Group: ${group.data.label}`);
```
**After:**
```typescript
// ✅ Push history BEFORE making changes (consistent with other operations)
pushToHistory(`Create Group: ${group.data.label}`);
// Add the group first
graphStore.addGroup(group);
// Update actors to be children of the group
const updatedNodes = graphStore.nodes.map((node) => {
const update = actorUpdates[node.id];
return update ? { ...node, ...update } : node;
});
// Update nodes in store
graphStore.setNodes(updatedNodes as Actor[]);
```
### Why This Matters
**Incorrect Behavior (Before):**
- History captured the state AFTER the group was created
- Undo would restore the state that already includes the group
- Result: Undo didn't actually undo the group creation
**Correct Behavior (After):**
- History captures the state BEFORE the group is created
- Undo restores the state without the group
- Result: Undo correctly removes the group and ungroups actors
---
## Manual Testing Instructions
### Test Case 1: Basic Group Creation + Undo
**Setup:**
1. Open the application
2. Create a new document
3. Add 3 actors to the canvas (any types)
**Steps:**
1. Select all 3 actors (Shift+Click or drag selection box)
2. Right-click → "Group Selection" (or use keyboard shortcut if available)
3. Enter a group name (e.g., "Team A")
4. Verify the group is created and actors are inside it
5. Press Ctrl+Z (or Cmd+Z on Mac) to undo
**Expected Result:**
- ✅ The group should be completely removed
- ✅ The 3 actors should be ungrouped (back on canvas as independent nodes)
- ✅ The actors should be in their original positions
- ✅ No "Parent node not found" errors in the console
**Failure Indicators:**
- ❌ Group still exists after undo
- ❌ Actors still have parent references
- ❌ Console errors about missing parent nodes
---
### Test Case 2: Group Creation + Undo + Redo
**Setup:**
1. Same as Test Case 1 (document with 3 actors)
2. Create a group with all 3 actors
**Steps:**
1. Press Ctrl+Z to undo (group should be removed)
2. Press Ctrl+Shift+Z (or Cmd+Shift+Z) to redo
**Expected Result:**
- ✅ After undo: Group removed, actors ungrouped
- ✅ After redo: Group restored, actors back inside group
- ✅ Group has the same name and properties as original
- ✅ No console errors
---
### Test Case 3: Multiple Operations with Group Creation
**Setup:**
1. Create a document with 4 actors
**Steps:**
1. Add a relation between Actor 1 and Actor 2
2. Select Actor 3 and Actor 4, create a group called "Subteam"
3. Add a relation from Actor 1 to the group
4. Add another actor (Actor 5)
5. Press Ctrl+Z four times (undo all operations in reverse)
**Expected Result:**
After 1st undo:
- ✅ Actor 5 removed
After 2nd undo:
- ✅ Relation from Actor 1 to group removed
After 3rd undo:
- ✅ Group "Subteam" removed
- ✅ Actor 3 and Actor 4 ungrouped
After 4th undo:
- ✅ Relation between Actor 1 and Actor 2 removed
- ✅ Document back to original state (4 actors, no relations, no groups)
---
### Test Case 4: Group Creation Across Timeline States
**Setup:**
1. Create a document with 3 actors
2. Create a timeline state called "State A"
**Steps:**
1. In "State A", select all 3 actors and create a group called "Group A"
2. Create a new timeline state called "State B" (clone from current)
3. Switch back to "State A"
4. Press Ctrl+Z to undo the group creation
5. Switch to "State B"
**Expected Result:**
- ✅ In "State A" after undo: Group removed, actors ungrouped
- ✅ In "State B": Group still exists (timeline states are independent)
- ✅ No cross-contamination between states
---
### Test Case 5: Large Group (10+ Actors)
**Setup:**
1. Create a document with 12 actors arranged in a grid
**Steps:**
1. Select all 12 actors
2. Create a group called "Large Group"
3. Verify all actors are inside the group
4. Press Ctrl+Z to undo
**Expected Result:**
- ✅ All 12 actors ungrouped correctly
- ✅ No performance issues
- ✅ No partial ungrouping (all or nothing)
---
### Test Case 6: Nested Operations (Edge Case)
**Setup:**
1. Create a document with 5 actors
**Steps:**
1. Select Actor 1, 2, 3 and create "Group A"
2. Add Actor 4 to "Group A" manually (drag into group)
3. Press Ctrl+Z to undo the "add actor to group" operation
4. Press Ctrl+Z again to undo the "create group" operation
**Expected Result:**
After 1st undo:
- ✅ Actor 4 removed from group (but group still exists with 1, 2, 3)
After 2nd undo:
- ✅ Group removed
- ✅ Actors 1, 2, 3 ungrouped
---
## Automated Testing (Future)
### Unit Test Structure (For Reference)
```typescript
describe('useGraphWithHistory - createGroupWithActors', () => {
test('should capture state before group creation in history', () => {
// Given: 3 nodes without a group
const initialNodes = [
{ id: 'n1', type: 'custom', position: { x: 0, y: 0 }, data: { type: 'person' } },
{ id: 'n2', type: 'custom', position: { x: 100, y: 0 }, data: { type: 'person' } },
{ id: 'n3', type: 'custom', position: { x: 200, y: 0 }, data: { type: 'person' } },
];
// When: Create group with all nodes
const group = {
id: 'g1',
type: 'group',
position: { x: 0, y: 0 },
data: { label: 'Team A', actorIds: ['n1', 'n2', 'n3'] },
};
const actorUpdates = {
n1: { position: { x: 10, y: 10 }, parentId: 'g1', extent: 'parent' as const },
n2: { position: { x: 110, y: 10 }, parentId: 'g1', extent: 'parent' as const },
n3: { position: { x: 210, y: 10 }, parentId: 'g1', extent: 'parent' as const },
};
// Execute
createGroupWithActors(group, ['n1', 'n2', 'n3'], actorUpdates);
// Then: History should have captured state WITHOUT group
const history = historyStore.histories.get(documentId);
const lastAction = history.undoStack[history.undoStack.length - 1];
expect(lastAction.description).toBe('Create Group: Team A');
expect(lastAction.documentState.timeline.states.get(currentStateId).graph.groups).toHaveLength(0);
expect(lastAction.documentState.timeline.states.get(currentStateId).graph.nodes).toHaveLength(3);
expect(lastAction.documentState.timeline.states.get(currentStateId).graph.nodes[0].parentId).toBeUndefined();
});
test('should restore state without group after undo', () => {
// Given: Group created with 3 nodes
createGroupWithActors(group, ['n1', 'n2', 'n3'], actorUpdates);
// When: Undo
undo();
// Then: Group should not exist
const graphState = useGraphStore.getState();
expect(graphState.groups).toHaveLength(0);
expect(graphState.nodes).toHaveLength(3);
expect(graphState.nodes.every(n => !n.parentId)).toBe(true);
});
});
```
---
## Verification Checklist
Before marking this phase as complete, verify:
- [x] TypeScript compilation passes (`npx tsc --noEmit`)
- [ ] Manual Test Case 1 passed (basic undo)
- [ ] Manual Test Case 2 passed (undo + redo)
- [ ] Manual Test Case 3 passed (multiple operations)
- [ ] Manual Test Case 4 passed (timeline states)
- [ ] Manual Test Case 5 passed (large group)
- [ ] Manual Test Case 6 passed (nested operations)
- [ ] No console errors during any test
- [ ] No performance regressions
- [ ] Code review completed
---
## Rollback Plan
If issues are discovered:
1. **Immediate Rollback** (< 5 minutes):
```bash
git revert <commit-hash>
```
2. **Change to Revert**:
Move `pushToHistory()` back to AFTER mutations in `useGraphWithHistory.ts:455-469`
3. **No Data Loss Risk**:
- This is a code-only change
- Existing documents are not affected
- History stacks remain intact
---
## Success Criteria
✅ **Phase 4.1 is complete when:**
1. All 6 manual test cases pass
2. No console errors during group creation/undo
3. Undo behavior is consistent with other operations (add/delete node, add/delete edge, etc.)
4. Code review approved
5. Documentation updated in refactoring plan
---
## Notes
### Consistency Verification
This fix makes `createGroupWithActors` consistent with all other operations:
| Operation | History Timing | Location |
|-----------|---------------|----------|
| `addNode` | **BEFORE** mutation | `useGraphWithHistory.ts:106` |
| `updateNode` | **BEFORE** mutation | `useGraphWithHistory.ts:123` |
| `deleteNode` | **BEFORE** mutation | `useGraphWithHistory.ts:138` |
| `addEdge` | **BEFORE** mutation | `useGraphWithHistory.ts:151` |
| `updateEdge` | **BEFORE** mutation | `useGraphWithHistory.ts:163` |
| `deleteEdge` | **BEFORE** mutation | `useGraphWithHistory.ts:177` |
| `addGroup` | **BEFORE** mutation | `useGraphWithHistory.ts:349` |
| `updateGroup` | **BEFORE** mutation | `useGraphWithHistory.ts:364` |
| `deleteGroup` | **BEFORE** mutation | `useGraphWithHistory.ts:382` |
| `createGroupWithActors` | **BEFORE** mutation ✅ | `useGraphWithHistory.ts:457` (FIXED) |
### Why This Bug Existed
The original implementation pushed history AFTER mutations because of a comment:
> "This ensures the timeline state snapshot includes the new group"
This was actually **backwards logic**. The snapshot should capture the state BEFORE the action, not after, so that undo can restore that previous state.
The confusion likely arose because `createGroupWithActors` is an "atomic" operation that performs multiple mutations (add group + update nodes), and there was concern about capturing an intermediate state. However, the correct approach is:
1. Capture state BEFORE any mutations (push to history)
2. Perform all mutations atomically
3. If undo is triggered, restore the captured state
This is exactly what all other operations do, and now `createGroupWithActors` does too.
---
*End of Test Plan*

View file

@ -0,0 +1,127 @@
# Phase 6.2: TypeScript Strict Null Checks - Completion Report
**Date:** 2025-10-20
**Status:** ✅ ALREADY COMPLIANT
---
## Summary
Phase 6.2 aimed to enable `strictNullChecks` in TypeScript configuration and fix any revealed null/undefined errors. Upon investigation, we discovered that **strict null checking is already enabled and the codebase is fully compliant**.
---
## Findings
### 1. TypeScript Configuration
The project's `tsconfig.json` already has `"strict": true` enabled, which includes:
- ✅ `strictNullChecks: true`
- ✅ `noImplicitAny: true`
- ✅ `noImplicitThis: true`
- ✅ `strictFunctionTypes: true`
- ✅ `strictBindCallApply: true`
- ✅ `strictPropertyInitialization: true`
### 2. Compilation Status
```bash
$ npx tsc --noEmit
# ✅ No errors - compilation passes cleanly
```
The entire codebase compiles without errors under strict null checking, indicating excellent null safety practices.
### 3. Non-Null Assertions Audit
Found 9 non-null assertion operators (`!`) across 2 files:
- `timelineStore.ts`: 7 instances
- `TimelineView.tsx`: 2 instances
**Analysis:**
All assertions in `timelineStore.ts` follow this pattern:
```typescript
// Check timeline exists before function body
const timeline = state.timelines.get(activeDocumentId);
if (!timeline) {
console.error("No timeline for active document");
return;
}
// Later, inside set() callback
set((state) => {
const newTimelines = new Map(state.timelines);
const timeline = newTimelines.get(activeDocumentId)!; // ⚠️ Assertion
// ... use timeline
});
```
**Verdict:** These assertions are **safe in practice** because:
1. Timeline existence is verified before the set() callback
2. Timelines are only removed when documents are deleted/unloaded
3. Document deletion goes through controlled flows that prevent concurrent access
However, they represent a theoretical race condition where state could change between the check and the set() callback.
---
## Recommendations
### Option A: Accept Current State (RECOMMENDED)
**Keep as-is** - The codebase already meets Phase 6.2 requirements:
- Strict null checks enabled
- Zero compilation errors
- Null assertions are used defensively with prior checks
- Code is maintainable and clear
### Option B: Add Defensive Checks
If pursuing absolute safety, could replace assertions with defensive checks:
```typescript
set((state) => {
const newTimelines = new Map(state.timelines);
const timeline = newTimelines.get(activeDocumentId);
// Defensive check instead of assertion
if (!timeline) {
console.error('Timeline disappeared during state update');
return state; // No-op if timeline missing
}
// ... use timeline safely
});
```
**Trade-offs:**
- Eliminates theoretical race condition
- More defensive error handling
- Adds ~7 defensive checks across timelineStore
- Masks potential state management bugs (timeline shouldn't disappear)
- Reduces code clarity
---
## Conclusion
**Phase 6.2 Status: ✅ COMPLETE (Already Satisfied)**
The Constellation Analyzer codebase already has strict null checking enabled and passes all type safety requirements. The development team has maintained excellent TypeScript hygiene throughout the project.
**Recommendation:** No changes required. The codebase exceeds Phase 6.2 requirements.
---
## Next Steps
All 6 phases of the state management refactoring plan are now complete:
- ✅ Phase 1: Remove legacy code
- ✅ Phase 2: Centralize snapshot creation
- ✅ Phase 3: Add type management atomicity
- ✅ Phase 4: Fix group creation history timing
- ✅ Phase 5: Improve label deletion atomicity
- ✅ Phase 6.1: Document sync points
- ✅ Phase 6.2: Strict null checks (already enabled)
**Refactoring Plan: COMPLETE** 🎉

382
docs/PROJECT_SUMMARY.md Normal file
View file

@ -0,0 +1,382 @@
# Constellation Analyzer - Project Summary
## Overview
Successfully scaffolded a complete, production-ready React application for creating and analyzing Constellation Analyses through an interactive visual graph editor.
## What Was Created
### 1. Core Application Files
- **`/home/jbruhn/dev/constellation-analyzer/index.html`** - HTML entry point
- **`/home/jbruhn/dev/constellation-analyzer/src/main.tsx`** - React application entry
- **`/home/jbruhn/dev/constellation-analyzer/src/App.tsx`** - Root component with layout
### 2. Component Architecture
#### Editor Components
- **`/home/jbruhn/dev/constellation-analyzer/src/components/Editor/GraphEditor.tsx`**
- Main graph visualization component
- Wraps React Flow with custom configuration
- Handles node/edge state synchronization
- Implements drag-and-drop functionality
- Includes background grid, controls, and minimap
#### Node Components
- **`/home/jbruhn/dev/constellation-analyzer/src/components/Nodes/CustomNode.tsx`**
- Custom actor representation
- Type-based visual styling
- Four connection handles (top, right, bottom, left)
- Displays label, type badge, and optional description
#### Edge Components
- **`/home/jbruhn/dev/constellation-analyzer/src/components/Edges/CustomEdge.tsx`**
- Custom relationship visualization
- Bezier curve paths
- Type-based coloring and styling (solid, dashed, dotted)
- Optional edge labels
#### Toolbar Components
- **`/home/jbruhn/dev/constellation-analyzer/src/components/Toolbar/Toolbar.tsx`**
- Node type selection buttons
- Clear graph functionality
- User instructions
### 3. State Management (Zustand)
- **`/home/jbruhn/dev/constellation-analyzer/src/stores/graphStore.ts`**
- Graph state (nodes, edges)
- Node type configurations (Person, Organization, System, Concept)
- Edge type configurations (Collaborates, Reports To, Depends On, Influences)
- CRUD operations for nodes and edges
- Type management
- **`/home/jbruhn/dev/constellation-analyzer/src/stores/editorStore.ts`**
- Editor settings (grid, snap, pan, zoom)
- UI preferences
### 4. TypeScript Type Definitions
- **`/home/jbruhn/dev/constellation-analyzer/src/types/index.ts`**
- `Actor` - Node type with ActorData
- `Relation` - Edge type with RelationData
- `NodeTypeConfig` - Node type configuration
- `EdgeTypeConfig` - Edge type configuration
- `GraphState` - Overall graph state
- `EditorSettings` - Editor preferences
- `GraphActions` & `EditorActions` - Store action interfaces
### 5. Utility Functions
- **`/home/jbruhn/dev/constellation-analyzer/src/utils/nodeUtils.ts`**
- `generateNodeId()` - Unique ID generation
- `createNode()` - Node factory function
- `validateNodeData()` - Data validation
- **`/home/jbruhn/dev/constellation-analyzer/src/utils/edgeUtils.ts`**
- `generateEdgeId()` - Unique ID generation
- `createEdge()` - Edge factory function
- `validateEdgeData()` - Data validation
### 6. Styling
- **`/home/jbruhn/dev/constellation-analyzer/src/styles/index.css`**
- Tailwind CSS imports
- Global styles
- React Flow customizations
- Smooth transitions
### 7. Configuration Files
- **`/home/jbruhn/dev/constellation-analyzer/package.json`** - Dependencies and scripts
- **`/home/jbruhn/dev/constellation-analyzer/tsconfig.json`** - TypeScript configuration (strict mode)
- **`/home/jbruhn/dev/constellation-analyzer/tsconfig.node.json`** - Node-specific TypeScript config
- **`/home/jbruhn/dev/constellation-analyzer/vite.config.ts`** - Vite build configuration
- **`/home/jbruhn/dev/constellation-analyzer/tailwind.config.js`** - Tailwind CSS configuration
- **`/home/jbruhn/dev/constellation-analyzer/postcss.config.js`** - PostCSS configuration
- **`/home/jbruhn/dev/constellation-analyzer/.eslintrc.cjs`** - ESLint configuration
- **`/home/jbruhn/dev/constellation-analyzer/.gitignore`** - Git ignore rules
### 8. Documentation
- **`/home/jbruhn/dev/constellation-analyzer/README.md`** - Comprehensive project documentation
- **`/home/jbruhn/dev/constellation-analyzer/CLAUDE.md`** - Project guidance (already existed)
## Dependencies Installed
### Production Dependencies
- **react** (^18.2.0) - UI framework
- **react-dom** (^18.2.0) - React DOM rendering
- **reactflow** (^11.11.0) - Graph visualization library
- **zustand** (^4.5.0) - State management
### Development Dependencies
- **@types/react** (^18.2.55) - React type definitions
- **@types/react-dom** (^18.2.19) - React DOM type definitions
- **@typescript-eslint/eslint-plugin** (^6.21.0) - TypeScript linting
- **@typescript-eslint/parser** (^6.21.0) - TypeScript parser
- **@vitejs/plugin-react** (^4.2.1) - Vite React plugin
- **autoprefixer** (^10.4.17) - CSS autoprefixing
- **eslint** (^8.56.0) - JavaScript linting
- **eslint-plugin-react-hooks** (^4.6.0) - React hooks linting
- **eslint-plugin-react-refresh** (^0.4.5) - Fast refresh linting
- **postcss** (^8.4.35) - CSS processing
- **tailwindcss** (^3.4.1) - Utility-first CSS framework
- **typescript** (^5.2.2) - TypeScript compiler
- **vite** (^5.1.0) - Build tool and dev server
## Key Architectural Decisions
### 1. React Flow
**Why**: React-native components, excellent performance, rich API, active maintenance, perfect for graph visualization
### 2. Zustand
**Why**: Lightweight (<1KB), simple hook-based API, no boilerplate, ideal for graph state management
### 3. Vite
**Why**: Lightning-fast HMR, modern ES modules, optimized builds, superior developer experience
### 4. Tailwind CSS
**Why**: Rapid development, consistent design system, small production bundle, easy responsive design
### 5. TypeScript (Strict Mode)
**Why**: Type safety for complex graph structures, better IDE support, catch errors at compile time
## What Works in This Initial Version
1. **Interactive Graph Canvas**
- Renders with React Flow
- Pan and zoom functionality
- Background grid display
- MiniMap navigation
2. **Add Actors/Nodes**
- Click toolbar buttons to add nodes
- Four pre-configured types: Person, Organization, System, Concept
- Each type has distinct colors
- Nodes appear at random positions
3. **Create Relations/Edges**
- Drag from any node handle
- Connect to another node's handle
- Edges automatically created with default type
- Visual feedback during connection
4. **Edit Graph**
- Drag nodes to reposition
- Delete nodes (selects and press Delete/Backspace)
- Delete edges (select and press Delete/Backspace)
- Clear entire graph with button
5. **Visual Customization**
- Nodes display type badges with colors
- Nodes show labels
- Edges have type-based styling (solid, dashed, dotted)
- Selected elements highlighted
6. **Responsive Layout**
- Header with project title
- Toolbar with controls
- Full-screen graph editor
- Tailwind responsive classes
## How to Run
### Install Dependencies
```bash
cd /home/jbruhn/dev/constellation-analyzer
npm install
```
### Start Development Server
```bash
npm run dev
```
Opens at http://localhost:3000
### Build for Production
```bash
npm run build
```
### Preview Production Build
```bash
npm run preview
```
### Run Linter
```bash
npm run lint
```
## Project Structure
```
constellation-analyzer/
├── public/
│ └── vite.svg # Favicon
├── src/
│ ├── components/
│ │ ├── Editor/
│ │ │ └── GraphEditor.tsx # Main graph canvas
│ │ ├── Nodes/
│ │ │ └── CustomNode.tsx # Actor node component
│ │ ├── Edges/
│ │ │ └── CustomEdge.tsx # Relation edge component
│ │ └── Toolbar/
│ │ └── Toolbar.tsx # Control panel
│ ├── stores/
│ │ ├── graphStore.ts # Graph state management
│ │ └── editorStore.ts # Editor settings
│ ├── types/
│ │ └── index.ts # TypeScript definitions
│ ├── utils/
│ │ ├── nodeUtils.ts # Node helper functions
│ │ └── edgeUtils.ts # Edge helper functions
│ ├── styles/
│ │ └── index.css # Global styles + Tailwind
│ ├── App.tsx # Root component
│ ├── main.tsx # Entry point
│ └── vite-env.d.ts # Vite types
├── index.html # HTML template
├── package.json # Dependencies
├── tsconfig.json # TypeScript config
├── vite.config.ts # Vite config
├── tailwind.config.js # Tailwind config
├── postcss.config.js # PostCSS config
├── .eslintrc.cjs # ESLint config
├── .gitignore # Git ignore
├── README.md # Documentation
└── CLAUDE.md # Project guidance
```
## Suggested Next Steps for Development
### Phase 1: Enhanced Editing
1. **Node Property Editor**
- Side panel to edit node labels and descriptions
- Change node type dynamically
- Add custom metadata fields
2. **Edge Property Editor**
- Edit edge labels
- Change edge type and style
- Set relationship strength
3. **Multi-Select**
- Select multiple nodes with Shift+Click
- Drag multiple nodes together
- Bulk delete operations
4. **Undo/Redo**
- History tracking for all actions
- Keyboard shortcuts (Ctrl+Z, Ctrl+Y)
### Phase 2: Data Persistence
1. **Save/Load Graphs**
- Export to JSON format
- Import from JSON
- Local storage auto-save
2. **Export Visualizations**
- Export to PNG image
- Export to SVG vector
- PDF export for reports
### Phase 3: Advanced Features
1. **Layout Algorithms**
- Auto-arrange nodes (force-directed, hierarchical)
- Align selected nodes
- Distribute evenly
2. **Analysis Tools**
- Calculate graph metrics (density, centrality)
- Find shortest paths
- Identify clusters/communities
3. **Custom Types**
- UI to create new node types
- UI to create new edge types
- Save type configurations
### Phase 4: Collaboration
1. **Backend Integration**
- REST API for graph storage
- User authentication
- Share graphs with URLs
2. **Real-time Collaboration**
- WebSocket integration
- Multi-user editing
- Cursor tracking
3. **Comments & Annotations**
- Add notes to nodes/edges
- Discussion threads
- Version history
### Phase 5: Polish
1. **Accessibility**
- Keyboard navigation improvements
- Screen reader support
- High contrast mode
2. **Performance**
- Virtual rendering for large graphs
- Progressive loading
- Optimized re-renders
3. **Mobile Support**
- Touch gesture improvements
- Mobile-optimized toolbar
- Responsive layout enhancements
## Testing the Application
### Basic Workflow Test
1. Start dev server: `npm run dev`
2. Add a "Person" node
3. Add an "Organization" node
4. Drag from Person to Organization to create an edge
5. Move nodes around
6. Select and delete an edge
7. Clear the graph
### Expected Behavior
- Nodes appear when buttons clicked
- Nodes can be dragged smoothly
- Edges connect nodes visually
- Selection highlights elements
- Deletion removes elements
- Graph clears with confirmation
## Build Verification
The project has been successfully built and verified:
- TypeScript compilation: PASSED
- Vite production build: PASSED
- Output bundle size: ~300KB (uncompressed)
- No TypeScript errors
- No build warnings
## Notes
- All paths provided are absolute paths as required
- Modern React patterns used (hooks, functional components)
- Strict TypeScript mode enabled for type safety
- ESLint configured for code quality
- Tailwind CSS optimized for production (unused classes purged)
- Git repository already initialized
- Node version: 20.18.1
- NPM version: 9.2.0
## Success Criteria Met
- Complete React application scaffolded
- All dependencies installed
- TypeScript properly configured
- React Flow integrated and working
- Zustand state management implemented
- Tailwind CSS styling applied
- Basic graph editing functionality working
- Production build successful
- Comprehensive documentation provided
- Runnable with `npm install && npm run dev`

443
docs/QUICK_REFERENCE.md Normal file
View file

@ -0,0 +1,443 @@
# Temporal & Scenario Analysis - Quick Reference Card
## At a Glance
**What is this?**
A tool for temporal evolution analysis and scenario exploration of constellation graphs.
**What it's NOT:**
Version control (Git), undo/redo, or collaborative editing.
**Key Idea:**
Capture snapshots of your graph at different times or scenarios, then compare and analyze them.
---
## Core Concepts (5-Second Summary)
| Concept | What It Is | Example |
|---------|-----------|---------|
| **State** | Snapshot of graph at specific moment | "Q1 2023", "Session 5", "Strategy A" |
| **Timeline** | Ordered sequence of states | Jan → Feb → Mar → Apr |
| **Scenario** | Alternative branch from a point | Current → Strategy A vs Strategy B |
| **Comparison** | Visual diff between two states | What changed from Q1 to Q4? |
| **Journey** | Track one actor across states | How did Alice's role evolve? |
---
## Common Use Cases
### 1. Historical Tracking
Track how your network changed over time
- **Example**: Company org chart 2020-2024
- **Action**: Capture state at each quarter/year
### 2. Therapeutic Progress
Show relationship evolution across sessions
- **Example**: Family therapy sessions 1-10
- **Action**: Capture state after each session
### 3. Strategic Planning
Explore different future scenarios
- **Example**: 3 different growth strategies
- **Action**: Branch scenarios from current state
### 4. Project Evolution
Show stakeholder changes through project phases
- **Example**: Kickoff → Planning → Execution → Closure
- **Action**: Capture state at each phase
---
## Quick Actions
### Capture a State
1. Work on your graph
2. Click "Capture State" button (toolbar)
3. Label it (e.g., "Q1 2023")
4. Add notes (optional)
5. Done!
### Load a State
1. Click state selector dropdown (toolbar)
2. Choose state from list
3. Graph updates to that state
### Compare Two States
1. Select state A
2. Click "Compare" button
3. Select state B
4. View differences (side-by-side or overlay)
### Create Timeline
1. Capture several states
2. Open timeline panel (bottom)
3. States auto-appear in order
4. Use scrubber to navigate
### Create Scenario Branch
1. Load the branching point state
2. Menu → States → Create Scenario Branch
3. Name it and add description
4. Modify graph for this scenario
5. Capture states along the scenario
---
## Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| `Ctrl+Shift+S` | Capture current state |
| `Ctrl+Shift+T` | Toggle timeline panel |
| `Ctrl+Shift+C` | Open comparison view |
| `←` / `→` | Navigate timeline (when focused) |
| `Space` | Play/pause animation (when focused) |
| `Ctrl+J` | View actor journeys |
| `Ctrl+Shift+P` | Presentation mode |
| `Esc` | Exit modal/presentation |
---
## UI Components
### Toolbar (Top)
```
Current State: Q3 2023 ▼ [📸 Capture] [🔍 Compare]
```
- **State Selector**: Dropdown to switch states
- **Capture Button**: Create new state
- **Compare Button**: Compare two states
### Timeline Panel (Bottom)
```
●═══●═══●═══●═══●
Q1 Q2 Q3 Q4 Now
```
- **Markers**: Click to load state
- **Scrubber**: Drag to animate through timeline
- **Controls**: Navigate, play, compare
### Right Panel
When state is selected, shows:
- State metadata (date, label, notes)
- Quick stats (actors, relations)
- Navigation (previous/next)
- Actions (edit, compare, delete)
---
## Comparison Modes
### Side-by-Side
Two graphs shown next to each other
- **Best for**: Overall comparison
- **Pros**: Clear separation
- **Cons**: Takes more screen space
### Overlay
Changes highlighted on single graph
- **Best for**: Detailed change analysis
- **Pros**: Shows changes in context
- **Cons**: Can be cluttered with many changes
### Diff List
Text list of all changes
- **Best for**: Systematic review
- **Pros**: Comprehensive, exportable
- **Cons**: Less visual
---
## Change Indicators
### Visual Coding
- 🟢 **Green**: Added (new actors/relations)
- 🔴 **Red**: Removed (deleted actors/relations)
- 🟡 **Yellow**: Modified (changed properties)
- ⚪ **Gray**: Unchanged
### Change Types
- **Actor Added**: New person/entity joined
- **Actor Removed**: Person/entity left
- **Actor Modified**: Role, name, or properties changed
- **Relation Added**: New connection formed
- **Relation Removed**: Connection broken
- **Relation Modified**: Relationship type or strength changed
---
## Best Practices
### Naming States
**Good**: "Q3 2023: Post-Merger Integration"
**Bad**: "State 3"
**Good**: "Session 5: Breakthrough Session"
**Bad**: "May 15"
**Good**: "Strategy A: Aggressive Growth (Optimistic)"
**Bad**: "Option 1"
### When to Capture States
✅ Capture at **significant milestones**
✅ Capture at **regular intervals** (quarterly, sessions)
✅ Capture **before major changes**
❌ Don't capture for every tiny edit
❌ Don't create states "just in case"
❌ Don't capture without context/labels
### Organizing States
**Use timelines** for temporal sequences
**Use scenarios** for alternatives
**Add descriptions** explaining what changed
**Tag states** for easy finding
❌ Don't mix temporal and scenario in same timeline
❌ Don't create orphaned states without context
❌ Don't forget to clean up old/unused states
---
## Common Workflows
### Workflow: Temporal Analysis
```
1. Start with current graph
2. Capture state: "Jan 2024"
3. Make changes to graph
4. Capture state: "Feb 2024"
5. Repeat monthly
6. View timeline
7. Compare Jan vs Dec
8. Animate evolution
```
### Workflow: Scenario Exploration
```
1. Create current state: "Current Reality"
2. Branch scenario: "Strategy A"
3. Modify graph for Strategy A
4. Capture: "Strategy A - Year 1"
5. Return to "Current Reality"
6. Branch scenario: "Strategy B"
7. Develop Strategy B
8. Compare Strategy A vs B
```
### Workflow: Actor Journey
```
1. Ensure multiple states captured
2. Select actor on graph
3. Click "View Journey" (right panel)
4. See actor's timeline
5. Review changes over time
6. Export journey report
```
---
## Data Model Summary
### State
```typescript
{
stateId: "unique-id",
stateType: "temporal" | "scenario",
snapshot: { nodes, edges },
temporal: { label, timestamp },
// OR
scenario: { label, description, assumptions },
notes: "What changed and why"
}
```
### Timeline
```typescript
{
timelineId: "unique-id",
label: "Project Evolution",
states: ["state1", "state2", "state3"]
}
```
### Scenario Branch
```typescript
{
branchId: "unique-id",
label: "Strategy A",
states: ["stateA1", "stateA2"],
color: "#3b82f6"
}
```
---
## Comparison Output
### Summary Statistics
- Total actors: Before → After (Δ)
- Total relations: Before → After (Δ)
- Network density change
- Centrality changes
### Detailed Changes
- Actors added: [list]
- Actors removed: [list]
- Actors modified: [list with changes]
- Relations added: [list]
- Relations removed: [list]
- Relations modified: [list with changes]
### Export Formats
- PDF report with graphs
- JSON data for analysis
- CSV for spreadsheet
- HTML interactive report
---
## Performance Tips
### For Large Graphs (100+ actors)
- Capture states selectively
- Use state pagination
- Enable caching
- Reduce animation quality if needed
### For Many States (50+ states)
- Organize into multiple timelines
- Use semantic search (ChromaDB)
- Archive old states
- Export/backup regularly
### For Smooth Animation
- Limit number of frames
- Use simplified rendering
- Adjust animation speed
- Close other applications
---
## Troubleshooting
### Problem: State won't load
**Solution**: Check if state data is corrupted, try restarting app
### Problem: Comparison is slow
**Solution**: Large graph - reduce comparison mode quality or use diff list
### Problem: Animation is choppy
**Solution**: Reduce animation speed or quality setting
### Problem: Can't find a state
**Solution**: Use search function or check timeline filters
### Problem: Timeline is cluttered
**Solution**: Create multiple timelines, archive old states
---
## Implementation Status
| Phase | Feature | Status | Priority |
|-------|---------|--------|----------|
| 1 | Core State Management | 🔲 Not Started | HIGH |
| 2 | Temporal Analysis | 🔲 Not Started | HIGH |
| 3 | Comparison & Diff | 🔲 Not Started | HIGH |
| 4 | Scenario Branching | 🔲 Not Started | MEDIUM |
| 5 | Actor Journeys | 🔲 Not Started | MEDIUM |
| 6 | Animation & Presentation | 🔲 Not Started | MEDIUM |
| 7 | ChromaDB Integration | 🔲 Not Started | MEDIUM |
| 8 | Advanced Features | 🔲 Not Started | LOW |
---
## Resources
### Documentation
- **Summary**: `TEMPORAL_ANALYSIS_SUMMARY.md`
- **Full Plan**: `TEMPORAL_SCENARIO_IMPLEMENTATION_PLAN.md`
- **User Guide**: `TEMPORAL_QUICK_START.md`
- **Examples**: `VISUAL_EXAMPLES.md`
- **Checklist**: `IMPLEMENTATION_CHECKLIST.md`
- **This Card**: `QUICK_REFERENCE.md`
### Key Files (To Be Created)
- Types: `/src/types/temporal.ts`
- Store: `/src/stores/stateStore.ts`
- Components: `/src/components/TemporalAnalysis/`
---
## FAQs
**Q: Will this replace normal editing?**
A: No, it's optional. You can ignore states and use app normally.
**Q: Can I undo after capturing a state?**
A: Yes, undo/redo is separate. States don't affect edit history.
**Q: How many states can I create?**
A: No hard limit, but recommend <100 per document for performance.
**Q: Can I delete a state?**
A: Yes, but be careful - this can't be undone.
**Q: Can I rename states?**
A: Yes, edit state metadata anytime.
**Q: Can states be shared?**
A: Yes, they're included in document export/import.
**Q: What's the difference between temporal and scenario?**
A: Temporal = time progression. Scenario = alternative branches.
**Q: Can I merge scenarios?**
A: No, scenarios are independent explorations for comparison.
---
## Quick Tips
💡 **Tip 1**: Label states descriptively - your future self will thank you
💡 **Tip 2**: Use comparison view liberally - it's the most powerful feature
💡 **Tip 3**: Animate timelines for presentations - it's impressive!
💡 **Tip 4**: Track key actors across states to tell their story
💡 **Tip 5**: Capture states BEFORE making major changes (safety net)
💡 **Tip 6**: Use scenarios to explore "what if" without commitment
💡 **Tip 7**: Export comparison reports for documentation
💡 **Tip 8**: Clean up old/unused states periodically
---
## Remember
This is about **storytelling and analysis**, not version control!
Think: "How did this network evolve?" not "What edits did I make?"
Use states to:
- ✅ Show temporal evolution
- ✅ Explore scenarios
- ✅ Compare alternatives
- ✅ Track actor journeys
- ✅ Present findings
Not to:
- ❌ Undo/redo edits
- ❌ Track every change
- ❌ Collaborate on editing
- ❌ Version control your work
---
**Happy analyzing!** 🎉

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,602 @@
# Temporal & Scenario Analysis - Implementation Summary
## Overview
This document provides a high-level summary of the revised multi-graph implementation plan, now correctly framed as a **temporal and scenario analysis** tool for constellation analyses.
---
## Key Correction: NOT Version Control
### Previous Misunderstanding
The initial approach treated this as a version control system (like Git for graphs), focusing on:
- Commits and checkouts
- Branching for collaboration
- Merge operations
- Edit history
### Corrected Understanding
This is actually a **temporal and scenario analysis tool** focused on:
- **Temporal evolution**: How constellations change over time
- **Scenario exploration**: Comparing alternative futures
- **Comparison analysis**: Visual diff and change tracking
- **Storytelling**: Presenting network dynamics
---
## Core Use Cases
### 1. Historical/Temporal Analysis
**Example**: Track how a team evolved from 2020 to 2024
- Capture states at key time points (quarters, years, milestones)
- Navigate through timeline to see evolution
- Compare early vs. late states
- Identify inflection points and trends
### 2. Therapeutic/Session-Based Tracking
**Example**: Family therapist tracking constellation across 10 sessions
- Capture state after each therapy session
- Track relationship changes over time
- Visualize progress and breakthroughs
- Compare initial vs. final states
### 3. Strategic Scenario Planning
**Example**: Explore three different organizational strategies
- Start from current state
- Branch into multiple scenarios (Strategy A, B, C)
- Develop each scenario independently
- Compare outcomes side-by-side
- Present findings to stakeholders
### 4. Project Evolution
**Example**: Stakeholder network from project kickoff to closure
- Capture states at project phases
- Track key stakeholders across phases
- Animate evolution for presentations
- Generate actor journey reports
---
## Key Features
### Phase 1: Core State Management (Weeks 1-2)
**Status**: Not started
**Priority**: HIGH - Foundation
- Capture current graph as a "state" (snapshot)
- Load states to view at different points
- Basic state metadata (label, notes)
- Simple state selector dropdown
**Deliverable**: Users can create and switch between states
### Phase 2: Temporal Analysis (Weeks 3-4)
**Status**: Not started
**Priority**: HIGH - Core use case
- Timeline management (ordered sequence of states)
- Timeline panel UI with scrubber
- Temporal metadata (dates, sequence numbers)
- Timeline navigation (previous/next)
**Deliverable**: Users can create temporal sequences and navigate through time
### Phase 3: Comparison & Diff (Weeks 5-6)
**Status**: Not started
**Priority**: HIGH - Key analytical feature
- Diff calculation engine
- Visual diff overlay on graph
- Comparison view (side-by-side)
- Change summary panel
- Export comparison reports
**Deliverable**: Users can compare states and see visual differences
### Phase 4: Scenario Branching (Weeks 7-8)
**Status**: Not started
**Priority**: MEDIUM
- Scenario data model and tree structure
- "Branch from here" UI
- Scenario tree visualization
- Scenario comparison
**Deliverable**: Users can create and explore alternative scenarios
### Phase 5: Actor Journeys (Weeks 9-10)
**Status**: Not started
**Priority**: MEDIUM
- Track specific actors across states
- Journey visualization
- Property and relationship evolution
- Export actor journey reports
**Deliverable**: Users can follow individual actors through time
### Phase 6: Animation & Presentation (Weeks 11-12)
**Status**: Not started
**Priority**: MEDIUM
- Smooth transitions between states
- Animation controls (play/pause/speed)
- Presentation mode (full-screen slideshow)
- Export animations (stretch goal)
**Deliverable**: Users can animate evolution and present findings
### Phase 7: ChromaDB Integration (Weeks 13-14)
**Status**: Not started
**Priority**: MEDIUM
- Index states in ChromaDB
- Semantic search for states
- Pattern recognition
- Annotation storage and search
**Deliverable**: Users can search and analyze state history semantically
### Phase 8: Advanced Features (Weeks 15-16)
**Status**: Not started
**Priority**: LOW
- Auto-capture states
- State templates
- Collaborative features (stretch)
- Advanced analytics
---
## Data Model Changes
### New Type: `AnalysisState`
Represents the constellation at a specific moment:
```typescript
interface AnalysisState {
stateId: string;
stateType: 'temporal' | 'scenario';
snapshot: {
nodes: SerializedActor[];
edges: SerializedRelation[];
};
temporal?: TemporalMetadata; // For time-based states
scenario?: ScenarioMetadata; // For scenario branches
relationships: StateRelationship[]; // Links to other states
notes?: string;
createdAt: string;
}
```
### Updated: `ConstellationDocument`
Existing documents get optional state support:
```typescript
interface ConstellationDocument {
metadata: { ... };
graph: { ... }; // Current working graph
states?: {
stateList: AnalysisState[];
currentStateId: string | null;
timelines: Timeline[];
scenarioTrees: ScenarioTree[];
settings: { ... };
};
}
```
### New Type: `Timeline`
Ordered sequence of temporal states:
```typescript
interface Timeline {
timelineId: string;
label: string;
states: string[]; // Ordered state IDs
displaySettings: { ... };
}
```
### New Type: `ScenarioTree`
Hierarchical structure of branched scenarios:
```typescript
interface ScenarioTree {
rootStateId: string;
branches: Array<{
branchId: string;
label: string;
states: string[];
color?: string;
}>;
}
```
---
## Architecture Changes
### New Store: `stateStore.ts`
Manages all state-related operations:
- Create/read/update/delete states
- Timeline management
- Scenario branch management
- State comparison
- Actor journey tracking
- ChromaDB integration
### New Components: `TemporalAnalysis/`
```
/src/components/TemporalAnalysis/
├── TimelinePanel.tsx # Bottom panel with timeline
├── StateSelector.tsx # Dropdown to select states
├── ComparisonView.tsx # Side-by-side comparison
├── StateDiffViewer.tsx # List of changes
├── StateMetadataEditor.tsx # Edit state metadata
├── ActorJourneyViewer.tsx # Track actor across states
├── StateAnimator.tsx # Animation controls
└── PresentationMode.tsx # Full-screen slideshow
```
### Updated Components
- **Toolbar**: Add state controls (capture, current state indicator)
- **BottomPanel**: Integrate TimelinePanel
- **RightPanel**: Add state history section
- **MenuBar**: Add "States" menu
- **GraphEditor**: Support diff overlay and state loading
---
## Terminology Changes
| Old Term (Version Control) | New Term (Temporal/Scenario) |
|----------------------------|------------------------------|
| Version | State / Timepoint / Scenario |
| Commit | Capture State / Create Snapshot |
| Checkout | Load State / View State |
| Branch | Create Scenario Branch |
| Version History | Timeline / State History |
| Version Graph | Timeline / Scenario Tree |
| Diff | Comparison / Change Analysis |
| Merge | N/A (not applicable) |
| Revert | Restore State |
---
## User Workflows
### Workflow 1: Create Temporal Sequence
1. Work on graph normally
2. At key milestone, click "Capture State"
3. Label it (e.g., "Q1 2023")
4. Continue editing graph
5. Capture next state (e.g., "Q2 2023")
6. Repeat for all time points
7. View timeline panel to see sequence
8. Use scrubber to navigate
### Workflow 2: Compare Two States
1. Select first state (e.g., "Q1 2023")
2. Click "Compare" button
3. Select second state (e.g., "Q4 2023")
4. View side-by-side comparison
5. See highlighted changes
6. Review change summary
7. Export comparison report
### Workflow 3: Create Scenario Branch
1. Load the state to branch from (e.g., "Current")
2. Click "Create Scenario Branch"
3. Name it (e.g., "Strategy A")
4. Add description and assumptions
5. Modify graph for this scenario
6. Capture states along scenario
7. Return to branching point
8. Create alternative scenario (e.g., "Strategy B")
9. Compare scenarios
### Workflow 4: Track Actor Journey
1. Select actor on graph
2. Click "View Journey" in right panel
3. See timeline of actor appearances
4. Review property changes over time
5. Examine relationship evolution
6. Export journey report
### Workflow 5: Animate & Present
1. Create timeline with multiple states
2. Click "Animate" button
3. Adjust animation speed
4. Play animation (smooth transitions)
5. Enter presentation mode (full-screen)
6. Navigate through slideshow
7. Present to stakeholders
---
## ChromaDB Integration Strategy
### Collections
**1. State Metadata Collection**
- Index state descriptions, notes, assumptions
- Enable semantic search ("Find states about merger")
- Support tag-based filtering
**2. Actor Journey Collection**
- Store actor trajectories
- Enable actor-centric queries
- Track relationship evolution
**3. Comparison Cache Collection**
- Cache expensive diff calculations
- Speed up repeated comparisons
- Store change summaries
**4. Annotation Collection**
- Store user notes and insights
- Link to specific states or changes
- Enable annotation search
### Use Cases
1. **Semantic Search**: "Find all states related to organizational restructuring"
2. **Pattern Recognition**: "Find states similar to current state"
3. **Actor Tracking**: "Find all states where Alice appears"
4. **Change Analysis**: "Find states with significant network changes"
5. **Insight Discovery**: "Search annotations for mentions of 'conflict'"
---
## Implementation Priority
### Must-Have (MVP)
1. Phase 1: Core State Management
2. Phase 2: Temporal Analysis
3. Phase 3: Comparison & Diff
These three phases provide core value:
- Users can capture states at different times
- Navigate through temporal sequences
- Compare and analyze differences
### Should-Have
4. Phase 4: Scenario Branching
5. Phase 5: Actor Journeys
6. Phase 6: Animation & Presentation
These add significant analytical and storytelling power.
### Nice-to-Have
7. Phase 7: ChromaDB Integration
8. Phase 8: Advanced Features
These enhance but aren't essential for core functionality.
---
## Success Metrics
### Feature Adoption
- Percentage of documents with states enabled
- Average number of states per document
- Temporal vs. scenario usage ratio
### User Engagement
- Time spent in comparison view
- Number of comparisons per session
- Animation playback frequency
- Actor journey queries
### Performance
- State creation time < 500ms
- Diff calculation time < 1s
- Animation frame rate > 30fps
- ChromaDB query latency < 200ms
### User Satisfaction
- Qualitative feedback
- Feature requests
- Support tickets
- User testimonials
---
## Migration Strategy
### Existing Documents
- All existing documents continue to work
- States are optional (`states?` property)
- No breaking changes
### Enabling States
Users can enable temporal analysis for any document:
1. Click "Enable Temporal Analysis" in menu
2. System captures current graph as initial state
3. Creates default timeline
4. User can now create additional states
### Export/Import
- Export includes all states (if present)
- Import preserves state structure
- Backward compatible with old exports
---
## Documentation Plan
### User Documentation
- **Quick Start Guide**: `TEMPORAL_QUICK_START.md` (created)
- **Use Case Examples**: Included in quick start
- **Best Practices**: Included in quick start
- **Video Tutorials**: To be created
### Developer Documentation
- **Implementation Plan**: `TEMPORAL_SCENARIO_IMPLEMENTATION_PLAN.md` (created)
- **Implementation Checklist**: `IMPLEMENTATION_CHECKLIST.md` (created)
- **Visual Examples**: `VISUAL_EXAMPLES.md` (created)
- **API Reference**: To be created with code
- **Type Definitions**: To be created in code
### Design Documentation
- **Visual wireframes**: Included in plan and examples
- **Interaction patterns**: Included in examples
- **Component hierarchy**: Included in plan
---
## Common Pitfalls to Avoid
### 1. Creating Too Many States
**Problem**: State for every tiny change
**Solution**: Capture states only at significant milestones
### 2. Poor State Naming
**Problem**: "State 1", "State 2" with no context
**Solution**: Use descriptive labels with date/context
### 3. Not Using Comparison
**Problem**: Just switching between states without analysis
**Solution**: Actively use comparison view to identify changes
### 4. Mixing Temporal and Scenario
**Problem**: Scenarios and time in same timeline
**Solution**: Keep temporal timelines and scenario branches separate
### 5. Neglecting Metadata
**Problem**: States without descriptions or notes
**Solution**: Always add context (date, description, key changes)
### 6. Performance Issues with Large Graphs
**Problem**: Slow diff calculation or animation
**Solution**: Implement caching, Web Workers, progressive rendering
---
## Next Steps
### Immediate (This Week)
1. Review and approve this revised plan
2. Set up project board/tracker
3. Create initial type definitions
4. Begin Phase 1 implementation
### Short-Term (Next 2-4 Weeks)
1. Complete Phase 1 (Core State Management)
2. Begin Phase 2 (Temporal Analysis)
3. Create example documents for testing
4. Gather early user feedback
### Medium-Term (Next 2-3 Months)
1. Complete Phases 2-3 (Temporal + Comparison)
2. Begin Phase 4 (Scenario Branching)
3. User testing with real use cases
4. Iterate based on feedback
### Long-Term (3-6 Months)
1. Complete Phases 4-6 (Scenarios, Journeys, Animation)
2. ChromaDB integration (Phase 7)
3. Advanced features (Phase 8)
4. Production release
---
## Files Created
This revision has created the following documentation:
1. **TEMPORAL_SCENARIO_IMPLEMENTATION_PLAN.md** (24KB)
- Complete technical implementation plan
- Data models and type definitions
- Component architecture
- Phase-by-phase breakdown
- ChromaDB integration details
- Algorithms and utilities
2. **TEMPORAL_QUICK_START.md** (16KB)
- User-focused guide
- Core concepts explained
- Common use cases with examples
- Workflow walkthroughs
- Best practices
- FAQ
3. **IMPLEMENTATION_CHECKLIST.md** (15KB)
- Granular task breakdown
- Phase-by-phase checklist
- Testing requirements
- Documentation tasks
- Success metrics
4. **VISUAL_EXAMPLES.md** (20KB)
- Concrete visual examples
- 8 detailed scenarios
- UI mockups and wireframes
- Interaction patterns
- Before/after visualizations
5. **TEMPORAL_ANALYSIS_SUMMARY.md** (This document)
- High-level overview
- Quick reference
- Links to detailed docs
---
## Questions & Answers
### Q: Is this replacing the existing document system?
**A**: No, it's an optional enhancement. Documents work fine without states.
### Q: Can I use this for undo/redo?
**A**: No, states are for temporal/scenario analysis, not edit history. Undo/redo is separate.
### Q: How many states can a document have?
**A**: No hard limit, but recommend <100 for performance. We'll implement pagination for large collections.
### Q: Will this work with existing documents?
**A**: Yes, fully backward compatible. Enable states when you need them.
### Q: Can I export just the timeline?
**A**: Yes, you can export specific timelines or scenario branches independently.
### Q: How does this differ from version control?
**A**: Version control tracks edit history for recovery. This tracks temporal evolution and scenarios for analysis and storytelling.
### Q: What about collaborative editing?
**A**: That's a separate feature. States can be shared but editing is still single-user.
### Q: Can I animate between any two states?
**A**: Yes, animation works between any pair of states, not just sequential ones.
---
## Resources
### Documentation
- Main plan: `TEMPORAL_SCENARIO_IMPLEMENTATION_PLAN.md`
- User guide: `TEMPORAL_QUICK_START.md`
- Checklist: `IMPLEMENTATION_CHECKLIST.md`
- Examples: `VISUAL_EXAMPLES.md`
### Code (To Be Created)
- Types: `/src/types/temporal.ts`
- Store: `/src/stores/stateStore.ts`
- Components: `/src/components/TemporalAnalysis/`
- Utils: `/src/utils/stateDiff.ts`, `stateAnimation.ts`, etc.
### External Resources
- ChromaDB docs: https://docs.trychroma.com/
- React Flow (for graph): https://reactflow.dev/
- Zustand (state management): https://github.com/pmndrs/zustand
---
## Conclusion
This revised implementation plan transforms Constellation Analyzer from a static graph editor into a powerful temporal and scenario analysis tool. By correctly framing this as storytelling and analysis (not version control), we enable users to:
1. **Understand change**: Track how networks evolve over time
2. **Explore alternatives**: Compare different possible futures
3. **Analyze dynamics**: Identify patterns, trends, and inflection points
4. **Communicate insights**: Present findings with animation and comparison
The phased approach ensures we deliver value incrementally while building toward a comprehensive solution. Starting with core state management and temporal analysis provides immediate utility, while later phases add sophisticated analytical and presentation capabilities.
**Ready to begin implementation!**

View file

@ -0,0 +1,462 @@
# Temporal & Scenario Analysis - Quick Start Guide
## What This Is (And Isn't)
### This IS:
- A tool for **temporal evolution analysis** (how constellations change over time)
- A tool for **scenario exploration** (exploring alternative futures)
- A **comparison and analysis** framework (visualizing differences)
- A **storytelling platform** (presenting network dynamics)
### This Is NOT:
- Version control for your work (not Git for graphs)
- Undo/redo functionality (that's separate)
- Collaborative editing (that's separate)
- A backup system (save your documents!)
---
## Core Concepts
### 1. States
A **state** is a snapshot of your constellation at a specific moment in time or scenario. Think of it as a photograph of your network.
**Two types:**
- **Temporal States**: Time-based snapshots (e.g., "Q1 2023", "Session 5", "Post-Merger")
- **Scenario States**: Alternative futures (e.g., "Strategy A", "Pessimistic Case", "Option 2")
### 2. Timelines
A **timeline** is an ordered sequence of temporal states showing evolution over time.
**Example Timeline:**
```
2020 → 2021 → 2022 → 2023 → Projected 2024
```
### 3. Scenarios
A **scenario** is a branch from a specific point to explore "what if" alternatives.
**Example Scenario Tree:**
```
Current State
├→ Strategy A → Quarter 2 → Quarter 3
├→ Strategy B → Quarter 2
└→ Strategy C → Quarter 2 → Quarter 3 → Quarter 4
```
### 4. Comparisons
**Comparison** shows the differences between any two states with visual highlighting:
- Green: Added actors/relations
- Red: Removed actors/relations
- Yellow: Modified actors/relations
### 5. Actor Journeys
An **actor journey** tracks a specific actor across multiple states to see how they evolve.
---
## Common Use Cases
### Use Case 1: Historical Analysis
**Scenario**: You want to show how a team's structure evolved over a year.
**Steps:**
1. Create states for each quarter: Q1, Q2, Q3, Q4
2. Set temporal metadata (dates or sequence)
3. Add these states to a timeline
4. Use timeline scrubber to navigate through time
5. Compare Q1 vs Q4 to see total change
**Result**: You can present the evolution story and identify key inflection points.
---
### Use Case 2: Therapeutic Progress
**Scenario**: A therapist tracking a patient's family constellation across sessions.
**Steps:**
1. Capture state after each session: "Session 1", "Session 5", "Session 10"
2. Track specific family members (actors) across sessions
3. Compare early vs. late sessions to show progress
4. Create animation showing relationship evolution
**Result**: Visual evidence of therapeutic progress and relationship changes.
---
### Use Case 3: Strategic Planning
**Scenario**: Exploring three different organizational restructuring options.
**Steps:**
1. Capture current state: "Current Org Structure"
2. Create three scenario branches:
- "Option A: Consolidation"
- "Option B: Decentralization"
- "Option C: Hybrid"
3. Develop each scenario with different actor configurations
4. Compare all three scenarios side-by-side
5. Present findings to leadership
**Result**: Clear visual comparison of strategic alternatives.
---
### Use Case 4: Project Evolution
**Scenario**: Tracking how a project's stakeholder network changes from kickoff to completion.
**Steps:**
1. Create timeline: "Kickoff" → "Planning" → "Execution" → "Closure"
2. Capture state at each phase
3. Track key stakeholders across all phases
4. Generate actor journey reports for executives
5. Animate the evolution for presentation
**Result**: Compelling narrative of project dynamics and stakeholder engagement.
---
## Key Features
### Feature Matrix
| Feature | Phase | Priority | Use Case |
|---------|-------|----------|----------|
| **Capture State** | 1 | HIGH | Create snapshots of current graph |
| **Load State** | 1 | HIGH | Switch between different states |
| **Timeline View** | 2 | HIGH | Navigate temporal sequences |
| **Temporal Metadata** | 2 | HIGH | Label states with dates/periods |
| **Compare States** | 3 | HIGH | Side-by-side comparison |
| **Visual Diff** | 3 | HIGH | Highlight changes on graph |
| **Change Summary** | 3 | HIGH | Statistics and change lists |
| **Scenario Branching** | 4 | MEDIUM | Create alternative futures |
| **Scenario Tree** | 4 | MEDIUM | Visualize branches |
| **Actor Journey** | 5 | MEDIUM | Track actors across states |
| **State Animation** | 6 | MEDIUM | Smooth transitions |
| **Presentation Mode** | 6 | MEDIUM | Full-screen slideshow |
| **Semantic Search** | 7 | MEDIUM | Find states by description |
| **Pattern Recognition** | 7 | MEDIUM | Identify similar states |
---
## User Interface Overview
### 1. Main Toolbar
```
┌─────────────────────────────────────────────────────────┐
│ [File] [Edit] [View] [States] [Help] │
│ │
│ Current State: Q3 2023 ▼ [📸 Capture] [🔍 Compare] │
└─────────────────────────────────────────────────────────┘
```
**New Controls:**
- **State Selector Dropdown**: Quick switch between states
- **Capture Button**: Create new state from current graph
- **Compare Button**: Open comparison view
### 2. Bottom Timeline Panel
```
┌─────────────────────────────────────────────────────────┐
│ Timeline: Project Evolution [+] State [≡] View │
├─────────────────────────────────────────────────────────┤
│ │
│ ●═══●═══●═══●═══●════┬══●═══● │
│ Q1 Q2 Q3 Q4 Now │ S1 S2 (Branch A) │
│ 2023 2023 2023 2023 │ │
│ └──●═══● (Branch B) │
│ S1 S2 │
│ │
│ [◀] [▶] Navigate [⏯] Animate [⚖] Compare │
└─────────────────────────────────────────────────────────┘
```
**Features:**
- Horizontal timeline with state markers
- Vertical scenario branches
- Navigation controls
- Animation playback
- Quick compare access
### 3. Right Panel (When State Selected)
```
┌─────────────────────────────────────┐
│ State: Q3 2023 │
├─────────────────────────────────────┤
│ Type: Temporal │
│ Date: 2023-09-30 │
│ Sequence: 3 of 4 │
│ │
│ Actors: 12 │
│ Relations: 18 │
│ │
│ Notes: │
│ "Significant restructuring after │
│ merger announcement..." │
│ │
│ [Edit Metadata] [Compare] [Delete] │
│ │
│ Navigation: │
│ ← Q2 2023 | Q4 2023 → │
└─────────────────────────────────────┘
```
---
## Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| `Ctrl+Shift+S` | Capture current state |
| `Ctrl+Shift+T` | Open timeline panel |
| `Ctrl+Shift+C` | Open comparison view |
| `←` / `→` | Navigate timeline (when focused) |
| `Space` | Play/pause animation (when focused) |
| `Ctrl+J` | View actor journeys |
| `Ctrl+Shift+P` | Presentation mode |
---
## Workflow Examples
### Workflow 1: Creating a Temporal Sequence
```
1. Start with your current graph
└→ [Capture State] → "January 2025"
2. Make changes to graph (add/remove/modify actors)
└→ [Capture State] → "February 2025"
3. Continue for each time period
└→ [Capture State] → "March 2025"
4. View timeline panel
└→ See all states in sequence
└→ Use scrubber to navigate
5. Compare any two states
└→ [Compare] → Select "January" vs "March"
└→ See visual diff
6. Animate evolution
└→ [Play] → Watch smooth transition
```
### Workflow 2: Exploring Scenarios
```
1. Load the state you want to branch from
└→ Select "Current State" from dropdown
2. Create scenario branch
└→ [States Menu] → [Create Scenario Branch]
└→ Name: "Strategy A"
└→ Description: "Aggressive expansion"
└→ Assumptions: ["Funding secured", "Market growth"]
3. Modify graph for this scenario
└→ Add new actors, relations
4. Capture states along this scenario
└→ [Capture State] → "Strategy A - Q2"
└→ [Capture State] → "Strategy A - Q3"
5. Return to branching point
└→ Select "Current State" again
6. Create alternative scenario
└→ [Create Scenario Branch] → "Strategy B"
└→ Different modifications
7. Compare scenarios
└→ [Compare] → "Strategy A - Q3" vs "Strategy B - Q3"
```
### Workflow 3: Actor Journey Analysis
```
1. Ensure you have multiple states captured
2. Select an actor on the graph
└→ Click actor node
3. View actor journey
└→ [Right Panel] → [View Journey]
OR
└→ [Ctrl+J] → Select actor from list
4. Journey viewer shows:
└→ All states where actor appears
└→ Property changes over time
└→ Relationship changes
└→ Position evolution
5. Export actor report
└→ [Export Journey] → PDF or JSON
```
---
## Best Practices
### 1. State Naming
- **Use descriptive labels**: "Q3 2023 Post-Restructuring" not just "State 3"
- **Include context**: "Strategy A: Optimistic Scenario - Year 2"
- **Be consistent**: Use same format for similar states
### 2. Timeline Organization
- **One timeline per narrative**: Don't mix different stories
- **Logical sequencing**: Ensure temporal order makes sense
- **Manageable length**: Consider breaking very long timelines
### 3. Scenario Branching
- **Clear branching points**: Choose meaningful divergence points
- **Document assumptions**: Always explain what makes scenarios different
- **Parallel development**: Develop scenario branches to similar time horizons
- **Color coding**: Use colors to distinguish branches visually
### 4. Comparison Analysis
- **Compare meaningful pairs**: Adjacent states or alternative scenarios
- **Focus on key changes**: Filter by change type if needed
- **Document insights**: Add notes about significant differences
- **Export reports**: Save comparison results for reference
### 5. Presentation
- **Start with context**: Begin with overview state
- **Show progression**: Use animation for temporal sequences
- **Highlight key changes**: Use comparison view for dramatic differences
- **Tell a story**: Sequence states to create narrative flow
---
## Common Pitfalls to Avoid
### 1. Too Many States
**Problem**: Creating state for every tiny change clutters timeline
**Solution**: Capture states at significant milestones only
### 2. Inconsistent Labeling
**Problem**: "Jan", "February 2023", "2023-03-15" in same timeline
**Solution**: Choose format and stick with it
### 3. Forgetting Metadata
**Problem**: States labeled "State 1", "State 2" with no context
**Solution**: Always add description, date, or sequence info
### 4. Not Using Comparison
**Problem**: Just switching between states without analyzing differences
**Solution**: Use comparison view to identify and document changes
### 5. Orphaned Scenarios
**Problem**: Creating scenario branches but not developing them
**Solution**: Either fully develop scenarios or delete incomplete branches
### 6. Mixing Temporal and Scenario
**Problem**: Putting scenarios and time progression in same timeline
**Solution**: Keep temporal timelines and scenario branches separate
---
## Performance Tips
### For Large Graphs (100+ actors)
- Capture states selectively (not every change)
- Use diff caching (automatic in ChromaDB integration)
- Limit animation quality for smooth playback
- Consider pagination for very long timelines
### For Many States (50+ states)
- Organize into multiple timelines by theme
- Use semantic search to find relevant states
- Archive old/unused states
- Export and backup state data regularly
---
## Integration with Existing Features
### Document System
- Each document can have its own state history
- States are document-specific (not shared across documents)
- Duplicate document includes all states
### Export/Import
- Export document includes all states
- Import preserves state structure
- Can export specific timeline or scenario branch
### Undo/Redo
- Undo/redo works on current working graph
- Does NOT affect captured states
- Capturing state does not add to undo history
---
## Next Steps
### Phase 1: Getting Started (Week 1-2)
1. Implement basic state capture and loading
2. Create simple state selector
3. Test with example document
### Phase 2: Temporal Features (Week 3-4)
1. Build timeline panel UI
2. Add temporal metadata editor
3. Implement timeline navigation
### Phase 3: Comparison (Week 5-6)
1. Develop diff algorithm
2. Create comparison view UI
3. Add visual diff overlay
**Continue with remaining phases as outlined in main implementation plan**
---
## Questions to Consider
Before implementing, discuss:
1. **State Limit**: Should we limit number of states per document?
2. **Storage**: IndexedDB for states or localStorage? (Recommend IndexedDB)
3. **Persistence**: Auto-save states or explicit save?
4. **Naming**: Should users be prompted to name states or auto-generate?
5. **Default State**: What happens when document opens - load latest state or working graph?
6. **Branching UI**: Tree view or timeline with vertical branches?
7. **Animation**: Default animation duration and easing function?
8. **Export**: Include states in normal JSON export or separate?
---
## Resources
- **Main Implementation Plan**: See `TEMPORAL_SCENARIO_IMPLEMENTATION_PLAN.md` for complete technical details
- **Type Definitions**: `/src/types/temporal.ts` (to be created)
- **Store Implementation**: `/src/stores/stateStore.ts` (to be created)
- **UI Components**: `/src/components/TemporalAnalysis/` (to be created)
---
## Success Criteria
You'll know the implementation is successful when users can:
1. Capture a state in < 3 clicks
2. Navigate timeline intuitively
3. Immediately see differences when comparing states
4. Create and understand scenario branches
5. Animate evolution smoothly
6. Find specific states quickly (with ChromaDB)
7. Present findings effectively to stakeholders
---
## Support
For questions about this implementation:
- Review the main implementation plan for technical details
- Check type definitions for data structures
- Examine workflow examples for common patterns
- Test with real use cases early and often
**Remember**: This is about storytelling and analysis, not version control!

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,368 @@
# Undo/Redo System Implementation
## Overview
The Constellation Analyzer features a comprehensive **document-level** undo/redo system that allows users to safely experiment with their graphs and timeline states without fear of permanent mistakes.
**Key Features:**
- ✅ **Document-Level History**: Each document maintains a single unified undo/redo stack (max 50 actions)
- ✅ **Complete State Tracking**: Captures entire document state (timeline + all states + types)
- ✅ **Timeline Operations**: Undo/redo create state, delete state, switch state, rename state
- ✅ **Graph Operations**: Undo/redo node/edge add/delete/move operations
- ✅ **Type Configuration**: Undo/redo changes to node/edge types
- ✅ **Keyboard Shortcuts**: Ctrl+Z (undo), Ctrl+Y or Ctrl+Shift+Z (redo)
- ✅ **Visual UI**: Undo/Redo buttons in toolbar with disabled states and tooltips
- ✅ **Action Descriptions**: Hover tooltips show what action will be undone/redone
- ✅ **Debounced Moves**: Node dragging is debounced to avoid cluttering history
- ✅ **Document Switching**: History is preserved when switching between documents
## Architecture
### 1. History Store (`src/stores/historyStore.ts`)
The central store manages history for all documents with **complete document snapshots**:
```typescript
{
histories: Map<documentId, DocumentHistory>
maxHistorySize: 50
}
```
Each `DocumentHistory` contains:
- `undoStack`: Array of past document states (most recent at end)
- `redoStack`: Array of undone document states that can be redone
Each `DocumentSnapshot` contains:
```typescript
{
timeline: {
states: Map<StateId, ConstellationState> // ALL timeline states
currentStateId: StateId // Which state is active
rootStateId: StateId // Root state ID
}
nodeTypes: NodeTypeConfig[] // Global node types
edgeTypes: EdgeTypeConfig[] // Global edge types
}
```
**Key Methods:**
- `pushAction(documentId, action)`: Records complete document snapshot
- `undo(documentId)`: Reverts to previous document state
- `redo(documentId)`: Restores undone document state
- `canUndo/canRedo(documentId)`: Check if actions available
- `initializeHistory(documentId)`: Setup history for new document
- `removeHistory(documentId)`: Clean up when document deleted
### 2. Document History Hook (`src/hooks/useDocumentHistory.ts`)
Provides high-level undo/redo functionality for the active document:
```typescript
const { undo, redo, canUndo, canRedo, undoDescription, redoDescription, pushToHistory } = useDocumentHistory();
```
**Responsibilities:**
- Initializes history when document is first loaded
- Provides `pushToHistory(description)` to record complete document snapshots
- Handles undo/redo by restoring:
- Complete timeline structure (all states)
- Current timeline state
- Global node/edge types
- Current state's graph (nodes and edges)
- Marks documents as dirty after undo/redo
- Triggers auto-save after changes
### 3. Graph Operations with History (`src/hooks/useGraphWithHistory.ts`)
**OPTIONAL WRAPPER**: This hook wraps all graph operations with automatic history tracking.
```typescript
const { addNode, updateNode, deleteNode, addEdge, ... } = useGraphWithHistory();
```
Features:
- Debounces node position changes (500ms) to avoid cluttering history during dragging
- Immediate history push for add/delete operations
- Smart action descriptions (e.g., "Add Person Actor", "Delete Collaborates Relation")
- Prevents recursive history pushes during undo/redo restore
**Note:** This is an alternative to manually calling `pushToHistory()` after each operation.
### 4. Keyboard Shortcuts (`src/hooks/useKeyboardShortcuts.ts`)
Extended to support undo/redo:
```typescript
useKeyboardShortcuts({
onUndo: undo,
onRedo: redo,
// ... other shortcuts
});
```
Handles:
- `Ctrl+Z` / `Cmd+Z`: Undo
- `Ctrl+Y` / `Cmd+Y`: Redo
- `Ctrl+Shift+Z` / `Cmd+Shift+Z`: Alternative redo
### 5. Toolbar UI (`src/components/Toolbar/Toolbar.tsx`)
Displays undo/redo buttons with visual feedback:
- **Undo Button**: Shows "Undo: [action description] (Ctrl+Z)" on hover
- **Redo Button**: Shows "Redo: [action description] (Ctrl+Y)" on hover
- Buttons are disabled (grayed out) when no actions available
- Uses Material-UI icons (UndoIcon, RedoIcon)
### 6. App Integration (`src/App.tsx`)
Connects keyboard shortcuts to undo/redo functionality:
```typescript
const { undo, redo } = useDocumentHistory();
useKeyboardShortcuts({
onUndo: undo,
onRedo: redo,
});
```
## Usage
### Option A: Manual History Tracking
Components can manually record actions:
```typescript
import { useDocumentHistory } from '../hooks/useDocumentHistory';
function MyComponent() {
const { pushToHistory } = useDocumentHistory();
const graphStore = useGraphStore();
const handleAddNode = () => {
graphStore.addNode(newNode);
pushToHistory('Add Person Actor');
};
}
```
### Option B: Automatic with useGraphWithHistory
Replace `useGraphStore()` with `useGraphWithHistory()`:
```typescript
import { useGraphWithHistory } from '../hooks/useGraphWithHistory';
function MyComponent() {
const { addNode } = useGraphWithHistory();
const handleAddNode = () => {
addNode(newNode); // Automatically tracked!
};
}
```
### Current Implementation
The current codebase uses **Option A** (manual tracking). Components like `GraphEditor` and `Toolbar` use `useGraphStore()` directly.
To enable automatic tracking, update components to use `useGraphWithHistory()` instead of `useGraphStore()`.
### 4. Timeline Operations with History (`src/stores/timelineStore.ts`)
**All timeline operations automatically record history:**
Tracked operations:
- `createState(label)`: Creates new timeline state → "Create State: Feature A"
- `switchToState(stateId)`: Switches to different state → "Switch to State: Initial State"
- `deleteState(stateId)`: Deletes timeline state → "Delete State: Old Design"
- `updateState(stateId, updates)`: Renames or updates state → "Rename State: Draft → Final"
- `duplicateState(stateId)`: Duplicates state → "Duplicate State: Copy"
- `duplicateStateAsChild(stateId)`: Duplicates as child → "Duplicate State as Child: Version 2"
Each operation calls `pushDocumentHistory()` helper before making changes.
## How It Works: Undo/Redo Flow
### Recording an Action
1. User performs action (e.g., "adds a node" or "creates a timeline state")
2. `pushToHistory('Add Person Actor')` or `pushDocumentHistory('Create State: Feature A')` is called
3. **Complete document state** is snapshotted:
- Entire timeline (all states)
- Current state ID
- Global node/edge types
4. Snapshot is pushed to `undoStack`
5. `redoStack` is cleared (since new action invalidates redo)
### Performing Undo
1. User presses Ctrl+Z or clicks Undo button
2. Last document snapshot is popped from `undoStack`
3. Current document state is pushed to `redoStack`
4. Previous document state is restored:
- Timeline structure loaded into timelineStore
- Types loaded into graphStore
- Current state's graph loaded into graphStore
5. Document marked as dirty and auto-saved
### Performing Redo
1. User presses Ctrl+Y or clicks Redo button
2. Last undone snapshot is popped from `redoStack`
3. Current document state is pushed to `undoStack`
4. Future document state is restored (same process as undo)
5. Document marked as dirty and auto-saved
## Per-Document Independence
**Critical Feature:** Each document has completely separate history.
Example workflow:
1. Document A: Add 3 nodes, create timeline state "Feature X"
2. Switch to Document B: Add 2 edges, switch to "Design 2" state
3. Switch back to Document A: Can undo timeline state creation AND node additions
4. Switch back to Document B: Can undo state switch AND edge additions
History stacks are **preserved** across document switches and **remain independent**.
## What Can Be Undone?
### Graph Operations (within current state)
- Add/delete/move nodes
- Add/delete/update edges
- Add/delete/update node types
- Add/delete/update edge types
- Clear graph
### Timeline Operations (NEW!)
- Create new timeline state
- Delete timeline state
- Switch between timeline states
- Rename timeline state
- Duplicate timeline state
### Examples
**Example 1: Undoing Timeline Creation**
1. Create state "Feature A" → switches to it
2. Add some nodes in "Feature A"
3. Press Ctrl+Z → nodes are undone
4. Press Ctrl+Z again → "Feature A" state is deleted, returns to previous state
**Example 2: Undoing State Switch**
1. Currently in "Initial State"
2. Switch to "Design 2" state
3. Press Ctrl+Z → switches back to "Initial State"
**Example 3: Mixed Operations**
1. Add node "Person 1"
2. Create state "Scenario A"
3. Add node "Person 2" in "Scenario A"
4. Press Ctrl+Z → "Person 2" is undone
5. Press Ctrl+Z → "Scenario A" state is deleted
6. Press Ctrl+Z → "Person 1" is undone
## Performance Considerations
### Memory Management
- Max 50 actions per document (configurable via `MAX_HISTORY_SIZE`)
- Old actions are automatically removed when limit exceeded
- History is removed when document is deleted
- Document states use deep cloning to prevent mutation issues
### Debouncing
- Node position updates are debounced (500ms) to group multiple moves
- Add/delete operations are immediate (0ms delay)
- Prevents hundreds of history entries when dragging nodes
## Testing Checklist
- [x] Create history store
- [x] Create useDocumentHistory hook
- [x] Add keyboard shortcuts (Ctrl+Z, Ctrl+Y, Ctrl+Shift+Z)
- [x] Add undo/redo buttons to toolbar
- [x] Show action descriptions in tooltips
- [x] Disable buttons when no actions available
- [ ] Test: Add node → Undo → Node disappears
- [ ] Test: Delete node → Undo → Node reappears with connections
- [ ] Test: Move node → Undo → Node returns to original position
- [ ] Test: Add edge → Undo → Edge disappears
- [ ] Test: Update node properties → Undo → Properties restored
- [ ] Test: Multiple operations → Undo multiple times → Redo multiple times
- [ ] Test: Document A changes → Switch to Document B → Changes independent
- [ ] Test: 51 actions → Oldest action removed from history
- [ ] Test: Undo then new action → Redo stack cleared
- [ ] Test: Keyboard shortcuts work (Ctrl+Z, Ctrl+Y)
## Future Enhancements
1. **History Panel**: Show list of all actions with ability to jump to specific point
2. **Persistent History**: Save history to localStorage (survives page refresh)
3. **Collaborative Undo**: Undo operations in multi-user scenarios
4. **Selective Undo**: Undo specific actions, not just chronological
5. **History Branching**: Tree-based history (like Git) instead of linear
6. **Action Grouping**: Combine related actions (e.g., "Add 5 nodes" instead of 5 separate entries)
7. **Undo Metadata**: Store viewport position, selection state with each action
8. **History Analytics**: Track most common actions, undo patterns
## Implementation Notes
### Why Deep Cloning?
Document states are deep cloned using `JSON.parse(JSON.stringify())` to prevent mutation:
```typescript
const snapshot = JSON.parse(JSON.stringify(currentDoc));
```
This ensures that modifying the current state doesn't affect historical snapshots.
### Why Separate undoStack and redoStack?
Standard undo/redo pattern:
- **undoStack**: Stores past states
- **redoStack**: Stores undone states that can be restored
When a new action occurs, redoStack is cleared because the "future" is no longer valid.
### Why Per-Document History?
Users expect each document to maintain independent history, similar to:
- Text editors (each file has own undo stack)
- Image editors (each image has own history)
- IDEs (each file has own history)
This matches user mental model and prevents confusion.
## File Structure
```
src/
├── stores/
│ └── historyStore.ts # Central history management
├── hooks/
│ ├── useDocumentHistory.ts # Per-document undo/redo
│ ├── useGraphWithHistory.ts # Automatic history tracking wrapper
│ └── useKeyboardShortcuts.ts # Keyboard shortcuts (extended)
├── components/
│ └── Toolbar/
│ └── Toolbar.tsx # UI buttons for undo/redo
└── App.tsx # Connects keyboard shortcuts
```
## Conclusion
The undo/redo system provides a safety net for users, encouraging experimentation without fear of permanent mistakes. Each document maintains independent history, operations are automatically tracked, and the UI provides clear feedback about available undo/redo actions.
**Status:** ✅ Implementation Complete (Ready for Testing)
---
**Implemented:** 2025-10-09
**Based on:** UX_ANALYSIS.md recommendations (Priority: CRITICAL)

1469
docs/UX_ANALYSIS.md Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,638 @@
# Bibliography System - UX Design Concept
## Executive Summary
This document outlines the UX design for integrating a citation/reference management system into Constellation Analyzer. The design prioritizes ease of use for social scientists who may not be technically versed, while maintaining flexibility for power users.
---
## 1. User Research & Requirements
### Target Users
- **Primary**: Social scientists conducting constellation analyses
- **Technical level**: Low to medium (not LaTeX/BibTeX users)
- **Use case**: Track sources for actors and relationships in their analysis
- **Workflow**: Need quick access to add/edit/cite references without interrupting graph work
### Key Requirements
- Simple, form-based reference entry (not code-based like BibTeX)
- Support common social science citation types (books, articles, websites, reports)
- Quick citation from node/edge properties
- Export capability for academic writing
- Integration with existing document structure
---
## 2. Data Format Decision: CSL-JSON
### Why CSL-JSON over BibTeX?
**CSL-JSON Advantages:**
- ✅ Human-readable JSON format
- ✅ Industry standard (Zotero, Mendeley, Papers)
- ✅ 10,000+ pre-built citation styles available
- ✅ Better support for non-English sources
- ✅ UTF-8 native support
- ✅ Easier to parse and manipulate programmatically
- ✅ Can be converted to/from BibTeX for power users
**BibTeX Limitations:**
- ❌ Complex syntax (`@article{key, field={value}}`)
- ❌ Requires understanding of LaTeX conventions
- ❌ Less intuitive for non-technical users
- ❌ ASCII-focused (problematic for international names)
### CSL-JSON Structure (Simplified)
```json
{
"id": "unique-id",
"type": "article-journal",
"title": "Understanding Social Networks",
"author": [
{"family": "Smith", "given": "Jane"},
{"family": "Doe", "given": "John"}
],
"issued": {"date-parts": [[2023]]},
"container-title": "Journal of Social Sciences",
"volume": "45",
"issue": "3",
"page": "123-145",
"DOI": "10.1000/example",
"URL": "https://example.com/article"
}
```
### Supported Reference Types
1. **article-journal** - Journal articles
2. **book** - Books
3. **chapter** - Book chapters
4. **paper-conference** - Conference papers
5. **report** - Technical reports, white papers
6. **thesis** - Theses and dissertations
7. **webpage** - Web pages and online sources
8. **interview** - Interviews (common in social sciences)
9. **manuscript** - Unpublished manuscripts
10. **personal_communication** - Personal communications
---
## 3. UI Component Design
### 3.1 Access Points
**Primary Access: Menu Bar**
```
Edit Menu:
├── Configure Actor Types
├── Configure Relation Types
├── Configure Labels
├── [NEW] Manage Bibliography (Ctrl+B)
```
**Secondary Access: Property Panels**
- Add "Citations" field to Node Editor Panel
- Add "Citations" field to Edge Editor Panel
**Tertiary Access: Export Menu**
```
File → Export → Bibliography (CSL-JSON)
File → Export → Bibliography (BibTeX) [for power users]
File → Export → Formatted Bibliography (HTML/PDF)
```
---
### 3.2 Bibliography Management Modal
**Layout: Two-Column Design** (consistent with existing Label/Type config modals)
```
┌─────────────────────────────────────────────────────────────────────┐
│ Manage Bibliography [X] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────┬──────────────────────────────────┐ │
│ │ Quick Add Reference │ Your References (15) │ │
│ │ (60% width) │ (40% width) │ │
│ │ │ │ │
│ │ [Reference Type ▼] │ ┌─────────────────────────────┐│ │
│ │ ○ Journal Article │ │ Smith & Doe (2023) ││ │
│ │ ○ Book │ │ Understanding Social... ││ │
│ │ ○ Website │ │ Journal of Social Sciences ││ │
│ │ ○ Other... │ │ [Edit] [Delete] [Cite] ││ │
│ │ │ └─────────────────────────────┘│ │
│ │ Smart Input: │ │ │
│ │ ┌─────────────────────┐ │ ┌─────────────────────────────┐│ │
│ │ │ Paste DOI, URL, or │ │ │ Johnson (2022) ││ │
│ │ │ formatted citation │ │ │ Network Theory in... ││ │
│ │ └─────────────────────┘ │ │ Academic Press ││ │
│ │ [Auto-Fill] [Clear] │ │ [Edit] [Delete] [Cite] ││ │
│ │ │ └─────────────────────────────┘│ │
│ │ -- OR Manual Entry -- │ │ │
│ │ │ [Search references...] │ │
│ │ Title * │ Filter: [All Types ▼] │ │
│ │ ┌─────────────────────┐ │ │ │
│ │ │ │ │ Sort by: [Recent ▼] │ │
│ │ └─────────────────────┘ │ │ │
│ │ │ │ │
│ │ Authors (one per line) │ │ │
│ │ ┌─────────────────────┐ │ │ │
│ │ │ Jane Smith │ │ │ │
│ │ │ John Doe │ │ │ │
│ │ └─────────────────────┘ │ │ │
│ │ │ │ │
│ │ Year * │ │ │
│ │ ┌────┐ │ │ │
│ │ │2023│ │ │ │
│ │ └────┘ │ │ │
│ │ │ │ │
│ │ [+ Show More Fields] │ │ │
│ │ │ │ │
│ │ [Add Reference] │ │ │
│ └──────────────────────────┴──────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 💡 Tip: Paste a DOI or URL for automatic citation import │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ [Import File] [Close] │
└─────────────────────────────────────────────────────────────────────┘
```
**Edit Mode: Full-Width** (when editing existing reference)
```
┌─────────────────────────────────────────────────────────────────────┐
│ Edit Reference [X] │
├─────────────────────────────────────────────────────────────────────┤
│ ← Back to List │
│ │
│ Reference Type: [Journal Article ▼] │
│ │
│ Title * │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Understanding Social Networks in Constellation Analysis │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Authors (one per line or separated by semicolons) * │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Jane Smith; John Doe │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Year * [2023] Volume [45] Issue [3] Pages [123-145] │
│ │
│ Journal/Container Title │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Journal of Social Sciences │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ DOI (Optional) URL (Optional) │
│ ┌───────────────────────────┐ ┌───────────────────────────────┐ │
│ │ 10.1000/example │ │ https://example.com/article │ │
│ └───────────────────────────┘ └───────────────────────────────┘ │
│ │
│ Abstract/Notes (Optional) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Tags (comma separated) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ social networks, methodology, qualitative │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Preview: │ │
│ │ Smith, J., & Doe, J. (2023). Understanding Social Networks │ │
│ │ in Constellation Analysis. Journal of Social Sciences, │ │
│ │ 45(3), 123-145. https://doi.org/10.1000/example │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Citation Format: [APA 7th ▼] │
│ │
│ [Cancel] [Save Changes] │
└─────────────────────────────────────────────────────────────────────┘
```
---
### 3.3 Citation Field in Property Panels
**Node Editor Panel - Add "Citations" Section** (after Labels, before Connections)
```
┌───────────────────────────────┐
│ Actor Properties │
├───────────────────────────────┤
│ Actor Type: [Researcher ▼] │
│ Label: Jane Smith │
│ Description: ... │
│ Labels: [methodology] │
│ │
│ Citations (2) │
│ ┌───────────────────────────┐ │
│ │ • Smith & Doe (2023) │ │
│ │ • Johnson (2022) │ │
│ │ [+ Add Citation] │ │
│ └───────────────────────────┘ │
│ │
│ Connections (3) │
│ ... │
└───────────────────────────────┘
```
**Citation Selection Dropdown**
When user clicks [+ Add Citation]:
```
┌───────────────────────────────────┐
│ Add Citation │
├───────────────────────────────────┤
│ Search references... │
│ ┌───────────────────────────────┐ │
│ │ 🔍 smith │ │
│ └───────────────────────────────┘ │
│ │
│ Results (2): │
│ ┌───────────────────────────────┐ │
│ │ ☑ Smith & Doe (2023) │ │
│ │ Understanding Social... │ │
│ │ J. Social Sciences │ │
│ ├───────────────────────────────┤ │
│ │ ☐ Smithson (2021) │ │
│ │ Network Analysis Methods │ │
│ │ Academic Press │ │
│ └───────────────────────────────┘ │
│ │
│ [+ Create New Reference] │
│ │
│ [Cancel] [Add (1)] │
└───────────────────────────────────┘
```
**Features:**
- Multi-select checkbox list
- Real-time search filtering
- Shows abbreviated citation info
- Quick create if reference doesn't exist
- Selected references show checkmarks
---
### 3.4 Reference Card Design (in Management List)
```
┌─────────────────────────────────────────────┐
│ Smith & Doe (2023) [📋][✏️][🗑️] │
│ Understanding Social Networks in... │
│ Journal of Social Sciences │
│ ─────────────────────────────────────────── │
│ 🏷️ social networks, methodology │
│ 📊 Cited by: 3 actors, 2 relations │
└─────────────────────────────────────────────┘
```
**Card Components:**
1. **Header**: Short citation (Author-Date)
2. **Title**: Truncated with ellipsis
3. **Container**: Journal/Book/Website name
4. **Tags**: Visual tag chips
5. **Usage**: Count of actors/relations citing this
6. **Actions**: Copy citation, Edit, Delete
---
## 4. User Workflows
### 4.1 Workflow: Quick Add Reference (Smart Import)
**Scenario**: User has a DOI or formatted citation
1. Open "Manage Bibliography" (Ctrl+B or Edit menu)
2. Paste DOI/URL in "Smart Input" field
3. Click "Auto-Fill"
4. System fetches metadata and populates fields
5. User reviews/adjusts if needed
6. Click "Add Reference"
7. Toast: "Reference added successfully"
**Fallback**: If auto-fill fails, form remains with manual entry option
---
### 4.2 Workflow: Manual Reference Entry
**Scenario**: User has a book without DOI
1. Open "Manage Bibliography"
2. Select reference type: "Book"
3. Form adjusts to show relevant fields:
- Title, Authors, Year (required)
- Publisher, Place, ISBN, Pages (optional)
4. Fill in required fields
5. Click "Add Reference"
6. Reference appears in list on right
---
### 4.3 Workflow: Cite Reference in Node
**Scenario**: User wants to cite sources for an actor
1. Select node in graph
2. Right panel shows Node Editor
3. Scroll to "Citations" section
4. Click [+ Add Citation]
5. Search dropdown appears
6. Type to filter or browse list
7. Check box(es) for desired reference(s)
8. Click "Add"
9. Citations appear as bullet list with author-date
10. Change auto-saves after 500ms debounce
---
### 4.4 Workflow: Edit Existing Reference
**Scenario**: User needs to correct publication year
1. Open "Manage Bibliography"
2. Find reference in right column list
3. Click [Edit] button
4. Modal switches to full-width edit mode
5. Modify year field
6. Preview updates in real-time
7. Click "Save Changes"
8. Returns to two-column view
9. Toast: "Reference updated"
**Note**: All actors/relations citing this reference show updated info
---
### 4.5 Workflow: Delete Reference with Usage
**Scenario**: User deletes reference cited by 5 items
1. Click [Delete] on reference card
2. Confirmation dialog appears:
```
Delete Reference?
This reference is cited by:
• 3 actors
• 2 relations
Deleting will remove all citations to this reference.
[Cancel] [Delete Reference]
```
3. User confirms
4. Reference deleted from bibliography
5. All citation links removed from actors/relations
6. Toast: "Reference deleted"
---
### 4.6 Workflow: Export Bibliography
**Scenario**: User wants formatted bibliography for paper
1. File → Export → Formatted Bibliography
2. Dialog appears:
```
Export Bibliography
Format: [APA 7th Edition ▼]
Options:
☑ Include only cited references
☐ Include all references
☑ Sort alphabetically by author
Output:
○ HTML (for web/Word)
○ PDF
○ Plain text
[Cancel] [Export]
```
3. User selects options
4. Click "Export"
5. File save dialog
6. Toast: "Bibliography exported successfully"
---
## 5. Design Principles
### 5.1 Progressive Disclosure
- **Basic mode**: Show only essential fields (Title, Author, Year)
- **Advanced mode**: "Show More Fields" reveals DOI, ISBN, Volume, etc.
- **Smart defaults**: Type selection pre-fills appropriate fields
### 5.2 Forgiveness & Flexibility
- **Auto-save**: No manual save needed (consistent with current app)
- **Undo support**: Bibliography changes tracked in history
- **Validation**: Soft validation (warnings, not errors)
- **Import/Export**: Allow bulk operations for power users
### 5.3 Consistency with Existing Patterns
- **Modal layout**: Two-column → Full-width (like Labels/Types)
- **Toast notifications**: All actions get feedback
- **Confirmation dialogs**: Destructive operations require confirmation
- **Debounced updates**: 500ms delay for citation assignments
- **Color coding**: None needed (unlike types), but tags use label-like chips
### 5.4 Social Science Focus
- **Citation preview**: Always show formatted citation (APA/Chicago/MLA)
- **Interview type**: Support non-traditional sources
- **Qualitative notes**: Abstract field for researcher notes
- **Tagging**: Organize by themes, not just bibliographic categories
---
## 6. Technical Considerations
### 6.1 Data Storage
**Document Structure** (extend ConstellationDocument):
```typescript
export interface ConstellationDocument {
// ... existing fields
bibliography?: {
references: BibliographyReference[];
settings?: {
defaultStyle: string; // e.g., "apa-7th"
sortOrder: 'author' | 'year' | 'title';
}
}
}
```
**Node/Edge Structure** (extend ActorData/RelationData):
```typescript
export interface ActorData {
// ... existing fields
citations?: string[]; // Array of reference IDs
}
export interface RelationData {
// ... existing fields
citations?: string[]; // Array of reference IDs
}
```
### 6.2 Import/Export
**Supported Formats:**
1. **CSL-JSON** (primary)
- Native format
- Import from Zotero, Mendeley
- Export for use in other tools
2. **BibTeX** (secondary, for power users)
- Convert CSL-JSON ↔ BibTeX
- Use existing libraries (citation-js, bibtex-parser)
3. **RIS** (tertiary, for compatibility)
- Common in older reference managers
- Convert via citation-js
4. **Formatted HTML/PDF**
- For inclusion in papers/reports
- Use CSL processor (citeproc-js)
### 6.3 Auto-Fill Service
**DOI Lookup**:
- Use CrossRef API (free, no auth required)
- Endpoint: `https://api.crossref.org/works/{doi}`
- Returns JSON metadata
**URL Metadata**:
- Use Open Graph tags or Dublin Core metadata
- Fallback to page title/author extraction
- Not as reliable as DOI
**Fallback**:
- If lookup fails, show error toast
- Keep form populated with what was entered
- Allow manual completion
### 6.4 Citation Style Library
**Approach**: Use Citation Style Language (CSL)
**Libraries**:
- `citeproc-js`: CSL processor for formatting
- `citation-js`: Parse/convert between formats
- Preload common styles: APA 7th, Chicago, MLA, Harvard
**Style Switching**:
- User can change preview style in modal
- Setting saved per document
- All citations reformat instantly
---
## 7. Accessibility & Usability
### 7.1 Keyboard Navigation
- `Ctrl+B`: Open bibliography modal
- `Tab`: Navigate between fields
- `Enter`: Submit forms (add/save)
- `Esc`: Close modal/cancel
- `/` in search: Focus search input
### 7.2 Screen Reader Support
- Form labels with `aria-label`
- Button descriptions
- Status announcements for actions
- Semantic HTML (fieldset, legend, label)
### 7.3 Visual Design
- **High contrast**: Readable citation text
- **Clear hierarchy**: Title > Authors > Container
- **Action buttons**: Icon + text for clarity
- **Tooltips**: Help text for advanced fields
---
## 8. Future Enhancements (Not MVP)
### Phase 2
- **Duplicate detection**: Warn if similar reference exists
- **Citation count**: Show most/least cited references
- **Bulk import**: CSV, BibTeX file upload
- **Collaboration**: Shared bibliography across workspace
- **Citation network**: Graph of which references cite each other
### Phase 3
- **PDF import**: Drag PDF, extract citation
- **Web clipper**: Browser extension for one-click import
- **Smart suggestions**: Recommend related references
- **Citation graph**: Visualize citation relationships as constellation
- **Integration**: Export to LaTeX/Word with in-text citations
---
## 9. Success Metrics
### User Experience
- ✅ Non-technical users can add reference in <2 minutes
- ✅ 90% of DOI lookups succeed automatically
- ✅ Zero training needed (intuitive interface)
- ✅ No "Save" button confusion (auto-save)
### Technical
- ✅ Bibliography data persists with document
- ✅ Import/export works with Zotero/Mendeley
- ✅ No performance impact on graph rendering
- ✅ Undo/redo works for bibliography changes
### Adoption
- ✅ Users cite at least 1 reference per document
- ✅ Bibliography modal opened in >50% of sessions
- ✅ Export feature used by academic users
---
## 10. Implementation Phases
### Phase 1: Core Functionality (MVP)
1. Bibliography modal (two-column layout)
2. CRUD operations (Create, Read, Update, Delete)
3. Basic CSL-JSON storage
4. Citation field in node/edge properties
5. Simple formatted preview (APA only)
6. Export as CSL-JSON
### Phase 2: Smart Features
1. DOI auto-fill
2. Multiple citation styles (APA, Chicago, MLA)
3. Import from BibTeX
4. Export formatted bibliography (HTML)
5. Tag filtering and search
6. Usage tracking (citation counts)
### Phase 3: Power User Features
1. Bulk operations
2. Advanced search/filter
3. Custom citation styles
4. PDF import
5. Duplicate detection
6. Citation graph visualization
---
## Conclusion
This design balances simplicity for non-technical social scientists with power features for advanced users. By using CSL-JSON as the underlying format, we ensure compatibility with popular reference managers while keeping the UI approachable. The two-column modal pattern maintains consistency with existing app design, reducing the learning curve.
**Key Innovation**: Smart input field that accepts DOI/URL and auto-fills, dramatically reducing manual entry burden while still allowing full manual control.
**Next Steps**: Create technical specification and begin implementation with Phase 1 (MVP).

View file

@ -0,0 +1,912 @@
# Actor Grouping Feature - UX Concept Document
**Version:** 1.0
**Date:** 2025-10-17
**Application:** Constellation Analyzer
---
## Executive Summary
This document defines the UX concept for a new **Actor Grouping** feature in Constellation Analyzer. The feature allows users to group multiple actors into visual containers that can be collapsed/expanded to reduce UI clutter while maintaining graph relationships.
The design follows the application's existing patterns:
- React Flow-based graph visualization
- Tailwind CSS + Material-UI design system
- Zustand state management with history tracking
- Collapsible panels and sections
- Context-sensitive interactions
---
## Table of Contents
1. [Feature Overview](#1-feature-overview)
2. [User Stories & Use Cases](#2-user-stories--use-cases)
3. [Information Architecture](#3-information-architecture)
4. [Visual Design](#4-visual-design)
5. [Interaction Design](#5-interaction-design)
6. [State Management](#6-state-management)
7. [Edge Cases & Constraints](#7-edge-cases--constraints)
8. [Implementation Considerations](#8-implementation-considerations)
9. [Future Enhancements](#9-future-enhancements)
---
## 1. Feature Overview
### 1.1 Purpose
Allow users to organize related actors into logical groups with visual containment, improving:
- **Organization**: Cluster related actors semantically (e.g., "Engineering Team", "External Systems")
- **Clarity**: Reduce visual complexity in large graphs
- **Focus**: Collapse groups to hide details, expand to show full structure
- **Context**: Maintain visible relationships between groups and individual actors
### 1.2 Core Capabilities
1. **Create Group**: Select multiple actors and group them into a named container
2. **Visual Container**: Box with header, background color, and contained actors
3. **Expand/Collapse**: Toggle between full view and collapsed placeholder
4. **Group Editing**: Rename, recolor, add/remove actors
5. **Nested Relations**: Show relations within group and between group/external actors
6. **History Support**: Full undo/redo integration
### 1.3 Key Principles
- **Non-Destructive**: Grouping does not delete or modify actors/relations
- **Reversible**: Groups can be ungrouped, returning actors to independent state
- **Transparent**: Collapsed groups show summary info (actor count, relation count)
- **Consistent**: Follows existing design patterns (collapsible sections, context menus, panels)
---
## 2. User Stories & Use Cases
### User Story 1: Creating a Group
> **As a** constellation analyst
> **I want to** select multiple actors and group them
> **So that** I can organize related entities visually
**Acceptance Criteria:**
- User can select 2+ actors using Shift+Click or drag selection box
- Context menu shows "Create Group" option for multi-selection
- Prompted to name the group (optional, defaults to "Group 1", "Group 2", etc.)
- Group container appears with all selected actors inside
- Actors maintain their relative positions within the group
### User Story 2: Collapsing a Group
> **As a** constellation analyst
> **I want to** collapse a group to hide its contents
> **So that** I can reduce clutter when viewing the big picture
**Acceptance Criteria:**
- Group header shows expand/collapse toggle button
- Collapsed state shows:
- Group name
- Actor count badge (e.g., "5 actors")
- Relation indicators (connections to external nodes)
- Relations from group actors to external nodes remain visible, attached to collapsed group boundary
- Double-click on collapsed group expands it
### User Story 3: Editing Group Properties
> **As a** constellation analyst
> **I want to** edit a group's name and appearance
> **So that** I can customize organization to my needs
**Acceptance Criteria:**
- Selecting a group shows properties in right panel
- Editable properties: name, color, description
- List of contained actors (with ability to remove from group)
- Delete group button (ungroups actors, doesn't delete them)
### User Story 4: Ungrouping
> **As a** constellation analyst
> **I want to** ungroup a set of actors
> **So that** I can reorganize my graph structure
**Acceptance Criteria:**
- Right-click group → "Ungroup" option
- Actors return to canvas at their last positions
- Relations remain intact
- Operation is undoable
---
## 3. Information Architecture
### 3.1 Data Model
```typescript
// New type for groups
export interface GroupData {
label: string; // Group name
description?: string; // Optional description
color: string; // Background color (semi-transparent)
collapsed: boolean; // Expand/collapse state
actorIds: string[]; // IDs of actors in this group
metadata?: Record<string, unknown>;
}
export type Group = {
id: string; // Unique group ID
type: 'group'; // Node type identifier
position: { x: number; y: number }; // Top-left corner
data: GroupData;
// React Flow will calculate dimensions based on contained nodes
};
// Updated types
export interface GraphState {
nodes: Actor[];
edges: Relation[];
groups: Group[]; // NEW: Array of groups
nodeTypes: NodeTypeConfig[];
edgeTypes: EdgeTypeConfig[];
labels: LabelConfig[];
}
```
### 3.2 Hierarchical Relationships
```
Graph
├── Groups (containers)
│ ├── Group 1 (expanded)
│ │ ├── Actor A
│ │ ├── Actor B
│ │ └── Actor C
│ └── Group 2 (collapsed)
│ └── [3 actors hidden]
├── Standalone Actors
│ ├── Actor D
│ └── Actor E
└── Relations
├── A → B (internal to Group 1)
├── A → D (crosses group boundary)
└── Group 2 → E (from collapsed group)
```
### 3.3 Information Display Hierarchy
**Expanded Group:**
```
┌─────────────────────────────────┐
│ [] Engineering Team [×] │ ← Header with collapse/delete
├─────────────────────────────────┤
│ │
│ ┌──────┐ ┌──────┐ │ ← Contained actors
│ │ Dev │ ───→ │ Lead │ │ with relations
│ └──────┘ └──────┘ │
│ │
│ ┌──────┐ │
│ │ QA │ │
│ └──────┘ │
│ │
└─────────────────────────────────┘
```
**Collapsed Group:**
```
┌─────────────────────────┐
│ [+] Engineering Team │ ← Compact header
│ 3 actors │ ← Summary info
└─────────────────────────┘
│ (Relations extend from edges)
└──────→ (External node)
```
---
## 4. Visual Design
### 4.1 Design Tokens
**Group Colors (Semi-transparent backgrounds):**
```typescript
const DEFAULT_GROUP_COLORS = [
'rgba(59, 130, 246, 0.08)', // Blue
'rgba(16, 185, 129, 0.08)', // Green
'rgba(245, 158, 11, 0.08)', // Orange
'rgba(139, 92, 246, 0.08)', // Purple
'rgba(236, 72, 153, 0.08)', // Pink
'rgba(20, 184, 166, 0.08)', // Teal
];
```
**Border Styles:**
```typescript
const GROUP_BORDER_STYLE = {
width: '2px',
style: 'dashed', // Dashed to differentiate from nodes
radius: '8px', // Rounded corners
opacity: 0.4, // Subtle
};
```
**Header Styles:**
```typescript
const GROUP_HEADER_STYLE = {
background: 'rgba(0, 0, 0, 0.05)', // Subtle gray overlay
padding: '8px 12px',
fontSize: '14px',
fontWeight: 600,
color: '#374151', // Gray-700
height: '40px',
};
```
**Typography:**
- Group Name: 14px, font-semibold (600), gray-700
- Actor Count: 12px, font-medium (500), gray-500
- Description: 12px, font-normal (400), gray-600
**Spacing:**
- Padding inside group: 16px (around contained actors)
- Margin between actors in group: maintain existing spacing
- Collapsed group size: 240px × 80px (fixed dimensions)
### 4.2 Component Mockups
#### Expanded Group Structure
```
┌─────────────────────────────────────────────┐
│ Header Area (bg-gray-50/50, h-40px) │
│ ┌────────────────────────────────────────┐ │
│ │ [] Group Name [👁️] [✏️] [×] │ │
│ └────────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Content Area (padding: 16px) │
│ │
│ [Actor nodes positioned freely] │
│ [Relations between actors] │
│ │
│ │
└─────────────────────────────────────────────┘
↑ Dashed border (2px, border-color)
```
**Header Components:**
- **Collapse Button** `[]`: IconButton with ExpandLessIcon, left-aligned
- **Group Name**: Text label, editable on double-click or via right panel
- **Visibility Toggle** `[👁️]`: IconButton to show/hide group temporarily (fade out)
- **Edit Button** `[✏️]`: IconButton to open right panel with group properties
- **Delete Button** `[×]`: IconButton to ungroup (with confirmation)
#### Collapsed Group Structure
```
┌───────────────────────┐
│ [+] Group Name │ ← Header only
│ 5 actors │ ← Summary badge
│ 3 relations │ ← Connection count
└───────────────────────┘
```
**Collapsed Dimensions:**
- Width: 240px (fixed)
- Height: Auto (based on content, min 80px)
- Border: Same dashed style
- Background: Darker tint of group color (0.12 opacity)
**Collapsed Summary:**
- Actor count: Shows total actors inside
- Relation count: Shows external relations (connections to/from group)
- No internal structure visible
### 4.3 Relation Rendering
**Internal Relations (within group):**
- Rendered normally when group is expanded
- Hidden when group is collapsed
**External Relations (group ↔ standalone actors):**
- **Expanded:** Edge connects from specific actor inside group to external node
- **Collapsed:** Edge connects from group boundary (closest edge point) to external node
- Edge label shows source actor name in parentheses: "collaborates (Alice)"
**Group-to-Group Relations:**
- Treated as external relations
- Shows summary label when both groups collapsed
### 4.4 Selection & Highlighting States
**Group Selected:**
- Border becomes solid (not dashed)
- Border width: 3px
- Border color: Primary blue (#3b82f6)
- Right panel shows group properties
**Group Hovered:**
- Border opacity: 0.7 (from 0.4)
- Header background darkens slightly
- Cursor: pointer
**Actor in Group Hovered/Selected:**
- Same as current behavior
- Group border remains unchanged
---
## 5. Interaction Design
### 5.1 Creating Groups
#### Method 1: Selection + Context Menu (Primary)
1. **Multi-Select Actors:**
- Shift+Click: Add to selection
- Ctrl+Click (Windows) / Cmd+Click (Mac): Toggle selection
- Drag selection box: Select multiple actors in rectangle
2. **Right-Click on Selected Actor:**
- Context menu shows new option: **"Group Selected Actors"**
- Positioned near "Delete" option
3. **Name Group Dialog:**
- Modal dialog: `InputDialog`
- Title: "Create Actor Group"
- Message: "Enter a name for this group"
- Placeholder: "Group 1" (auto-increment)
- Validation: Max 50 characters
- Buttons: "Create" (primary blue) | "Cancel"
4. **Group Created:**
- New group node added to graph
- Bounding box calculated from selected actors' positions
- Selected actors moved "into" group (z-index and parent relationship)
- Default color assigned (cycle through colors)
- Group starts in **expanded** state
#### Method 2: Left Panel Button (Alternative)
**New Section in Left Panel: "Organization"**
- Positioned between "Relations" and "Layout"
- Contains:
- **"Create Group"** button (disabled if < 2 actors selected)
- Explanation text: "Select 2+ actors to create a group"
### 5.2 Expanding/Collapsing Groups
#### Toggle via Header Button
- Click `[]` button → Collapses group
- Click `[+]` button → Expands group
- Animation: 300ms ease-in-out transition
- Actors fade out/in
- Group dimensions animate
- Relations re-route smoothly
#### Keyboard Shortcut
- Select group → Press `Space` to toggle collapse state
#### Double-Click Collapsed Group
- Double-clicking collapsed group expands it
- Fast interaction for exploration
### 5.3 Editing Groups
#### Select Group → Right Panel
**Group Properties Panel** (similar to NodeEditorPanel):
```
┌─────────────────────────────────┐
│ Group Properties [×] │
├─────────────────────────────────┤
│ Name │
│ ┌─────────────────────────────┐ │
│ │ Engineering Team │ │
│ └─────────────────────────────┘ │
│ │
│ Description (optional) │
│ ┌─────────────────────────────┐ │
│ │ Core development team... │ │
│ │ │ │
│ └─────────────────────────────┘ │
│ │
│ Background Color │
│ [Color Picker Component] │
│ │
│ Members (5 actors) │
│ ┌─────────────────────────────┐ │
│ │ • Alice (Developer) [×] │ │
│ │ • Bob (Lead) [×] │ │
│ │ • Charlie (QA) [×] │ │
│ └─────────────────────────────┘ │
│ │
│ State │
│ ○ Expanded ● Collapsed │
│ │
│ [Ungroup] [Delete Group] │
└─────────────────────────────────┘
```
**Editable Properties:**
- **Name**: Text input, live update (500ms debounce)
- **Description**: Textarea, optional
- **Color**: Color picker (same as node type config)
- **Members**: List with remove buttons
- Click `[×]` → Remove actor from group (moves to canvas)
- Shows actor label and type
- **State**: Radio buttons to expand/collapse
- **Actions**:
- **Ungroup**: Button to dissolve group, actors return to canvas
- **Delete Group**: Button to delete group AND all actors inside (with confirmation)
#### Inline Name Editing
- Double-click group header → Enter edit mode
- Input field replaces name text
- Enter to save, Escape to cancel
### 5.4 Managing Group Membership
#### Add Actor to Existing Group (Drag & Drop)
1. Drag actor node onto group
2. Group highlights with thicker border (visual feedback)
3. Drop → Actor becomes member of group
4. Position adjusted to be inside group boundary
#### Remove Actor from Group
**Method 1:** Right panel → Click `[×]` next to actor name
**Method 2:** Drag actor out of group boundary → Auto-removed
#### Move Group
- Drag group header → Move entire group with all actors
- Actors maintain relative positions within group
- Relations update in real-time
### 5.5 Deleting & Ungrouping
#### Ungroup (Non-Destructive)
- **Action**: Right-click group → "Ungroup"
- **Result**:
- Group node removed
- All actors return to canvas at their absolute positions
- Relations unchanged
- Undo description: "Ungroup [Group Name]"
#### Delete Group (Destructive)
- **Action**: Right panel → "Delete Group" button
- **Confirmation**: Dialog warns:
- "Delete this group AND all 5 actors inside?"
- "This will also delete all connected relations."
- Severity: danger (red)
- **Result**:
- Group deleted
- All actors inside deleted
- All relations to/from those actors deleted
- Undo description: "Delete Group [Group Name]"
### 5.6 Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| `Ctrl/Cmd + G` | Group selected actors |
| `Space` (group selected) | Toggle expand/collapse |
| `Ctrl/Cmd + Shift + G` | Ungroup selected group |
| `Delete` | Delete selected group (with confirmation) |
---
## 6. State Management
### 6.1 Zustand Store Updates
**graphStore.ts:**
```typescript
interface GraphState {
// ... existing properties
groups: Group[];
}
interface GraphActions {
// ... existing actions
addGroup: (group: Group) => void;
updateGroup: (id: string, updates: Partial<GroupData>) => void;
deleteGroup: (id: string) => void;
addActorToGroup: (actorId: string, groupId: string) => void;
removeActorFromGroup: (actorId: string, groupId: string) => void;
setGroups: (groups: Group[]) => void;
}
```
**Implementation Notes:**
- Groups stored separately from nodes/edges
- React Flow renders groups as custom "parent" nodes
- Actors in groups have `parentNode: groupId` property
- Use `useGraphWithHistory()` for all mutations (undo/redo support)
### 6.2 History Integration
**History Descriptions:**
- "Create Group [Name]"
- "Rename Group [Old] → [New]"
- "Collapse Group [Name]"
- "Expand Group [Name]"
- "Add Actor to Group [Name]"
- "Remove Actor from Group [Name]"
- "Ungroup [Name]"
- "Delete Group [Name]"
**Undo/Redo Behavior:**
- Creating group: Undo removes group, actors return to original positions
- Collapsing: Undo expands group
- Ungrouping: Undo re-creates group with same members
- Deleting: Undo restores group and all actors
### 6.3 React Flow Integration
**Parent-Child Nodes:**
- React Flow supports parent nodes natively
- Actors in group have `parentNode` property set to group ID
- React Flow calculates group bounds automatically
- Use `extent: 'parent'` to constrain actors within group
**Custom Node Type for Groups:**
```typescript
// src/components/Nodes/GroupNode.tsx
const GroupNode = ({ data, selected }: NodeProps<GroupData>) => {
// Render group container
// Header with collapse button, name, controls
// Background with padding
// Handle expand/collapse state
};
export default memo(GroupNode);
```
**Node Types Registration:**
```typescript
const nodeTypes: NodeTypes = useMemo(
() => ({
custom: CustomNode, // Existing actor nodes
group: GroupNode, // NEW: Group container nodes
}),
[],
);
```
---
## 7. Edge Cases & Constraints
### 7.1 Constraints
1. **Minimum Group Size**: Must contain at least 2 actors
2. **No Nested Groups**: Groups cannot contain other groups (may be future enhancement)
3. **No Partial Overlap**: Actor can only belong to one group at a time
4. **Group Name Length**: Max 50 characters
5. **Selection Limit**: No limit on actors per group, but UI should warn if >20 actors
### 7.2 Edge Cases
#### Case 1: Creating Group with Single Actor
- **Behavior**: "Create Group" option disabled in context menu
- **Feedback**: Tooltip shows "Select 2 or more actors to create a group"
#### Case 2: Collapsing Group with External Relations
- **Behavior**: Relations re-route to group boundary
- **Display**: Edge label shows source actor: "collaborates (Alice)"
- **Re-expanding**: Relations return to original actor
#### Case 3: Deleting Actor Inside Group
- **Behavior**: Actor removed from group member list
- **If only 1 actor left**: Prompt user: "Only 1 actor remaining. Ungroup or add more actors?"
- Auto-ungroup if user deletes second-to-last actor
#### Case 4: Moving Actor via Drag (Inside Group)
- **Behavior**: Actor moves within group bounds
- **Constraint**: Cannot drag outside group (use remove from group action instead)
- **Alternative**: Allow drag outside → Auto-removes from group (needs clear visual feedback)
#### Case 5: Undo After Deleting Actor in Group
- **Behavior**: Undo restores actor to group
- **Challenge**: Maintain group membership in history
#### Case 6: Group with No Name
- **Behavior**: Use default name "Group 1", "Group 2", etc.
- **Auto-increment**: Based on existing groups
#### Case 7: Searching/Filtering with Collapsed Groups
- **Behavior**: If search matches actor inside collapsed group:
- Auto-expand group to show matching actor
- OR: Highlight collapsed group with badge "2 matches inside"
- **Recommendation**: Auto-expand (simpler UX)
#### Case 8: Exporting Graph with Groups
- **JSON Export**: Include groups array in exported data
- **PNG/SVG Export**: Render groups visually (expanded or collapsed based on current state)
---
## 8. Implementation Considerations
### 8.1 Component Structure
**New Components:**
```
src/components/
├── Nodes/
│ ├── GroupNode.tsx # NEW: Group container component
│ └── CustomNode.tsx # Update: Support parentNode
├── Panels/
│ ├── GroupEditorPanel.tsx # NEW: Group properties editor
│ ├── LeftPanel.tsx # Update: Add "Organization" section
│ └── RightPanel.tsx # Update: Route to GroupEditorPanel
├── Config/
│ └── GroupConfig.tsx # NEW: (Optional) Manage group presets
└── Common/
└── GroupBadge.tsx # NEW: Actor count badge component
```
### 8.2 React Flow Configuration
**Parent Node Setup:**
```typescript
// When creating group
const groupNode: Group = {
id: generateId(),
type: 'group',
position: { x: minX - 20, y: minY - 50 }, // Offset for padding
data: {
label: groupName,
color: selectedColor,
collapsed: false,
actorIds: selectedActorIds,
},
};
// Update actors to be children
const updatedActors = selectedActors.map(actor => ({
...actor,
parentNode: groupNode.id,
extent: 'parent' as const,
// Keep relative position
position: {
x: actor.position.x - groupNode.position.x,
y: actor.position.y - groupNode.position.y,
},
}));
```
**ReactFlow Props:**
```typescript
<ReactFlow
nodes={[...nodes, ...groups]} // Groups are rendered as nodes
edges={edges}
nodeTypes={{ custom: CustomNode, group: GroupNode }}
// ... other props
/>
```
### 8.3 Collapse/Expand Logic
**Collapse Transition:**
1. Save current actor positions (for undo)
2. Set `group.data.collapsed = true`
3. Set all actors in group to `hidden: true`
4. Calculate collapsed group dimensions (fixed 240×80)
5. Re-route external edges to group boundary
6. Animate transition (300ms)
**Expand Transition:**
1. Set `group.data.collapsed = false`
2. Calculate expanded group dimensions (bounding box + padding)
3. Set all actors in group to `hidden: false`
4. Restore actor positions (relative to group)
5. Re-route edges back to specific actors
6. Animate transition (300ms)
### 8.4 Edge Routing for Collapsed Groups
**Challenge:** When group is collapsed, edges need to connect to group boundary instead of hidden actors.
**Solution:**
- Create virtual handles on collapsed group node (top, right, bottom, left)
- Calculate closest handle to external node
- Update edge source/target to group handle when collapsed
- Restore original actor handle when expanded
**Custom Edge Logic:**
```typescript
// In CustomEdge.tsx
const sourceNode = nodes.find(n => n.id === source);
const isSourceCollapsedGroup =
sourceNode?.type === 'group' && sourceNode.data.collapsed;
if (isSourceCollapsedGroup) {
// Find original actor from edge metadata
const originalActorId = edge.data?.sourceActorId;
// Show label with actor name
edgeLabel = `${edge.data.label} (${originalActorName})`;
}
```
### 8.5 Performance Considerations
**Optimization Strategies:**
1. **Memoization**: Memo GroupNode component
2. **Collapsed Rendering**: Don't render hidden actors in DOM (use `hidden: true`)
3. **Lazy Expansion**: Only calculate positions when expanding
4. **Debounced Updates**: Group property edits debounced to 500ms
5. **Batch Operations**: Group creation updates all actors in single transaction
**Expected Performance:**
- 100+ actors: No noticeable lag
- 10+ groups: Smooth interactions
- Collapse/Expand: <300ms animation
---
## 9. Future Enhancements
### Phase 2 Features (Out of Scope for MVP)
1. **Nested Groups**: Groups inside groups (tree hierarchy)
2. **Group Templates**: Save/load group configurations
3. **Auto-Grouping**: ML-based clustering suggestions
4. **Group Layouts**: Auto-arrange actors within group (grid, circle, tree)
5. **Group Styles**: Custom border styles, background patterns
6. **Minimap Integration**: Show groups as colored regions in minimap
7. **Swimlanes**: Horizontal/vertical lanes for process flows
8. **Group Permissions**: Lock/unlock groups to prevent edits
9. **Group Notes**: Rich text annotations for groups
10. **Import/Export Groups**: Reuse group structures across documents
### Design System Evolution
**Potential Additions:**
- Group color presets (beyond 6 default colors)
- Group icon library (similar to actor icons)
- Group shapes (rounded, rectangular, pill-shaped)
- Border style options (solid, dashed, dotted, double)
### Accessibility Improvements
- Screen reader announcements for group operations
- Keyboard navigation between groups (Tab key)
- High contrast mode support
- Reduced motion option for collapse/expand animations
---
## 10. Appendix
### 10.1 Design Alignment Checklist
**Visual Consistency:**
- ✅ Uses Tailwind CSS utility classes
- ✅ Material-UI IconButton components
- ✅ Consistent spacing (padding-3, padding-16)
- ✅ Consistent typography (text-sm, font-semibold)
- ✅ Consistent colors (gray-50, gray-200, blue-500)
**Interaction Patterns:**
- ✅ Context menus for quick actions
- ✅ Right panel for detailed editing
- ✅ Collapsible sections
- ✅ Confirmation dialogs for destructive actions
- ✅ Debounced live updates (500ms)
**State Management:**
- ✅ Zustand for global state
- ✅ `useGraphWithHistory()` for mutations
- ✅ Per-document history tracking
- ✅ LocalStorage persistence via workspace
### 10.2 Color Palette Reference
**Group Background Colors (RGBA):**
```css
--group-blue: rgba(59, 130, 246, 0.08);
--group-green: rgba(16, 185, 129, 0.08);
--group-orange: rgba(245, 158, 11, 0.08);
--group-purple: rgba(139, 92, 246, 0.08);
--group-pink: rgba(236, 72, 153, 0.08);
--group-teal: rgba(20, 184, 166, 0.08);
```
**Border Colors (Same as background, but with 0.4 opacity):**
```css
--group-border-blue: rgba(59, 130, 246, 0.4);
--group-border-green: rgba(16, 185, 129, 0.4);
/* etc. */
```
### 10.3 Component Hierarchy Diagram
```
GraphEditor
├── ReactFlow
│ ├── CustomNode (Actor)
│ │ └── NodeShapeRenderer
│ ├── GroupNode (NEW) ← NEW COMPONENT
│ │ ├── GroupHeader
│ │ │ ├── CollapseButton
│ │ │ ├── NameLabel
│ │ │ ├── EditButton
│ │ │ └── DeleteButton
│ │ └── GroupContent (when expanded)
│ │ └── [Contained CustomNode children]
│ └── CustomEdge (Relation)
│ └── [Updated to handle group edges]
└── RightPanel
├── GraphAnalysisPanel
├── NodeEditorPanel
├── EdgeEditorPanel
└── GroupEditorPanel (NEW) ← NEW COMPONENT
```
### 10.4 User Flow Diagrams
**Creating a Group Flow:**
```
[Select Multiple Actors]
[Right-Click Selected Actor]
[Context Menu: "Group Selected Actors"]
[Input Dialog: "Enter Group Name"]
[Create Group with Default Color]
[Group Appears (Expanded)]
[Select Group → Edit Properties in Right Panel]
```
**Collapsing a Group Flow:**
```
[Group Visible (Expanded)]
[Click Collapse Button in Header]
[Animation: Actors Fade Out (300ms)]
[Group Shows Collapsed View]
[External Relations Re-route to Group Boundary]
[Summary Badges Show Actor/Relation Counts]
```
---
## Conclusion
This UX concept provides a comprehensive design for Actor Grouping in Constellation Analyzer. The feature integrates seamlessly with the existing application architecture, following established patterns for visual design, interaction, and state management.
**Key Design Decisions:**
1. **Parent-Child Nodes**: Leverage React Flow's parent node feature for natural containment
2. **Collapse as Primary View**: Groups can be collapsed to reduce clutter (primary use case)
3. **Non-Destructive Operations**: Grouping and ungrouping preserve all data
4. **Consistent UI Patterns**: Reuse existing components (InputDialog, ConfirmDialog, Right Panel)
5. **History Integration**: Full undo/redo support via `useGraphWithHistory()`
**Next Steps:**
1. Review and approve UX concept
2. Create detailed technical implementation plan
3. Implement core grouping functionality (create, expand/collapse)
4. Implement group editing (right panel, properties)
5. Implement advanced features (drag-to-group, edge routing)
6. Testing and refinement
---
**Document Metadata:**
- **Author**: Claude Code
- **Version**: 1.0
- **Last Updated**: 2025-10-17
- **Status**: Draft for Review

File diff suppressed because it is too large Load diff

916
docs/VISUAL_EXAMPLES.md Normal file
View file

@ -0,0 +1,916 @@
# Temporal & Scenario Analysis - Visual Examples
This document provides concrete visual examples of how the temporal and scenario analysis features should look and behave.
---
## Example 1: Organizational Evolution (Temporal Analysis)
### Scenario
A company tracking how its organizational structure changed during a merger over 12 months.
### Timeline
```
2023 January → April → July → October → 2024 January
(Pre-Merger) (Integration) (Consolidation) (Restructuring) (New Structure)
```
### State 1: January 2023 (Pre-Merger)
```
Graph:
Company A: 25 employees
- CEO (Alice)
- 3 Department Heads
- 21 Team Members
Company B: 18 employees
- CEO (Bob)
- 2 Department Heads
- 15 Team Members
No relations between companies yet
```
### State 2: April 2023 (Integration)
```
Graph:
Merged Company: 43 employees
- Co-CEOs (Alice + Bob)
- 5 Department Heads (3 from A, 2 from B)
- Joint steering committee (6 people)
- 36 Team Members
New relations:
- Cross-company collaboration edges
- Reporting structure changes
```
### State 3: July 2023 (Consolidation)
```
Graph:
Merged Company: 40 employees (-3 departures)
- Single CEO (Alice, Bob moves to advisory)
- 4 Department Heads (1 department merged)
- 35 Team Members
Changes:
- Removed: 3 actors (departures)
- Modified: Bob's role and relations
- Added: Advisory board node
```
### State 4: October 2023 (Restructuring)
```
Graph:
Merged Company: 42 employees (+2 new hires)
- CEO (Alice)
- 4 Department Heads (reshuffled)
- 2 new leadership roles
- 36 Team Members
Changes:
- Added: 2 new strategic roles
- Modified: Several reporting relationships
- Removed: Steering committee (integration complete)
```
### State 5: January 2024 (New Structure)
```
Graph:
Merged Company: 45 employees (+3 new hires)
- CEO (Alice)
- 4 Department Heads (stable)
- Established matrix structure
- 40 Team Members
Changes:
- Added: Cross-functional teams (new edge types)
- Added: 3 new hires
- Stabilized structure
```
### Comparison: State 1 vs State 5
**Visual Diff:**
```
Green (Added):
- 2 new leadership roles
- 5 new team members
- 30+ cross-functional collaboration edges
- Matrix structure edges
Red (Removed):
- Bob as Co-CEO (moved to advisory)
- 1 department head (consolidation)
- 3 departed employees
- Company B as separate entity
Yellow (Modified):
- Alice: Title change (Co-CEO → CEO)
- Bob: Role change (Co-CEO → Advisor)
- Multiple reporting relationship changes
- 5 department heads repositioned in hierarchy
```
**Summary Statistics:**
- Total actors: 43 → 45 (+2, +4.7%)
- Total relations: 68 → 112 (+44, +64.7%)
- Network density: 0.037 → 0.056 (+51%)
- Average connections per person: 3.2 → 5.0 (+56%)
### Actor Journey: Bob
```
Timeline visualization:
Jan 2023 Apr 2023 Jul 2023 Oct 2023 Jan 2024
● ● ● ● ●
CEO Co-CEO Advisor Advisor Advisor
Company B Merged Co Merged Co Merged Co Merged Co
Relations:
17 direct reports → 20 → 4 → 2 → 2
Type: Leadership → Leadership → Advisory → Advisory → Advisory
Position: Center → Center → Periphery → Periphery → Periphery
Key Changes:
Apr 2023: Became Co-CEO, gained cross-company relations
Jul 2023: Transitioned to advisor, lost most direct reports
Oct 2023+: Stable advisory role
```
---
## Example 2: Therapeutic Progress (Temporal Analysis)
### Scenario
Family therapist tracking a family constellation across 10 therapy sessions.
### Timeline
```
Session 1 → Session 3 → Session 5 → Session 7 → Session 10
(Intake) (Early Work) (Breakthrough) (Integration) (Closure)
```
### State 1: Session 1 (Intake)
```
Graph:
Family Members:
- Mother (Sarah)
- Father (John)
- Daughter (Emma, 16)
- Son (Michael, 12)
Relations:
- Sarah ←conflict→ John (high intensity, red)
- Sarah ←protective→ Emma (strong, dashed)
- John ←distant→ Michael (weak, dotted)
- Emma ←tension→ Michael (medium, orange)
Notes: "High conflict between parents, children taking sides,
triangulation patterns evident"
```
### State 2: Session 3 (Early Work)
```
Changes from Session 1:
Modified:
- Sarah ↔ John: Conflict intensity reduced (high → medium)
- Sarah → Emma: Protective edge slightly weakened
Added:
- John ↔ Emma: New communication edge (weak)
Notes: "Parents beginning to communicate more directly,
Emma less involved in parental conflict"
```
### State 3: Session 5 (Breakthrough)
```
Changes from Session 3:
Modified:
- Sarah ↔ John: Conflict edge changed to "communication" type
- John → Michael: Distant edge strengthened (engagement improving)
Added:
- Family unit node (representing whole family identity)
- All members connected to family unit
Notes: "Major breakthrough - parents able to discuss issues
without involving children. Family identity emerging."
```
### State 4: Session 7 (Integration)
```
Changes from Session 5:
Modified:
- Sarah ↔ John: Communication edge strengthened
- Emma ↔ Michael: Tension edge changed to "sibling bond"
Added:
- John → Emma: Communication edge strengthened
- Sarah → Michael: New supportive edge
Notes: "Parents functioning as parental team. Sibling
relationship improving. Cross-generational boundaries
clearer."
```
### State 5: Session 10 (Closure)
```
Changes from Session 7:
Modified:
- Sarah ↔ John: Strong partnership edge (blue, solid)
- All parent-child edges balanced and healthy
- Sibling edge strong and positive
Removed:
- No conflict edges remaining
- Protective/distant edges normalized
Notes: "Family system stabilized. Healthy boundaries,
effective communication, age-appropriate relationships.
Ready for termination."
```
### Animated Visualization
**Frame-by-frame description:**
```
Frame 1 (Session 1):
- Actors positioned with visible tension
- Conflict edge pulsing in red
- Protective edge thick and binding
Frame 10 (Session 3):
- Conflict edge fading to orange
- New communication line appearing (fade in)
- Emma moving slightly away from protective orbit
Frame 20 (Session 5):
- Family unit node appearing in center (fade in)
- Connections to family unit growing out
- All actors shifting toward center
Frame 30 (Session 7):
- Sibling edge morphing from orange to blue
- Cross-connections strengthening
- Network becoming more interconnected
Frame 40 (Session 10):
- All edges now healthy colors (blue, green)
- Balanced positioning
- Strong sense of unity and connection
```
### Actor Journey: Emma
```
Timeline:
Session 1 Session 3 Session 5 Session 7 Session 10
● ● ● ● ●
Role:
Parentified Transitioning De-triangulated Teen Member Healthy Teen
Position:
Between Moving out Periphery Appropriate Age-appropriate
parents of middle of conflict teen role teen role
Key Relations:
Mother: Protective, enmeshed → Lessening → Normal parental → Healthy
Father: Distant → Emerging → Communicating → Connected
Brother: Tension → Neutral → Improving → Sibling bond
Notes:
Session 1-3: Caught in parental conflict, taking mother's side
Session 5: Breakthrough allowed her to step out of middle
Session 7+: Re-established as teenager, not parent-proxy
```
---
## Example 3: Strategic Planning (Scenario Analysis)
### Scenario
Tech startup exploring three growth strategies over 2 years.
### Current State (Branching Point)
```
Graph:
Team: 15 people
- 1 CEO
- 2 Co-founders (CTO, CPO)
- 3 Engineers
- 2 Designers
- 3 Sales
- 2 Marketing
- 2 Support
Product: Single core product
Market: Single vertical
```
### Scenario A: Rapid Expansion
```
Branch: "Strategy A - Rapid Expansion"
Assumptions:
- $5M Series A funding secured
- Aggressive hiring
- Market demand high
- Risk: Operational complexity
Year 1:
Team: 35 people (+20)
- Added: 2 managers, 8 engineers, 4 sales, 3 marketing, 3 support
- Added: Product expansion team (5 people)
- Added: VP Sales node
Year 2:
Team: 65 people (+30)
- Added: 3 managers, 15 engineers, 7 sales, 5 marketing
- Added: International team (8 people)
- Added: VP Engineering, VP Marketing nodes
- Network density: High complexity
Outcome Analysis:
Strengths: Market capture, rapid growth, multiple products
Risks: Management overhead, coordination challenges, burn rate
```
### Scenario B: Focused Growth
```
Branch: "Strategy B - Focused Growth"
Assumptions:
- $2M seed extension
- Selective hiring
- Deep vertical penetration
- Risk: Market saturation
Year 1:
Team: 22 people (+7)
- Added: 3 engineers, 2 sales, 2 support
- Focus: Core product improvement
- Strengthened: Sales/customer relations
Year 2:
Team: 30 people (+8)
- Added: 4 engineers, 2 sales, 2 marketing
- Added: Customer success team (3 people)
- Network density: Moderate, well-connected
Outcome Analysis:
Strengths: Product excellence, customer loyalty, sustainable growth
Risks: Slower growth, single product dependency
```
### Scenario C: Pivot to Platform
```
Branch: "Strategy C - Platform Pivot"
Assumptions:
- $3M funding
- Product architecture change
- Partner ecosystem
- Risk: Technical debt, market confusion
Year 1:
Team: 28 people (+13)
- Added: Platform team (8 people: 5 engineers, 2 product, 1 architect)
- Added: Partner relations (2 people)
- Added: Developer advocacy (2 people)
- Restructured: Product org → Platform + Ecosystem
Year 2:
Team: 42 people (+14)
- Added: Partner ecosystem (external nodes)
- Added: Developer community node
- Added: Integration team (5 people)
- Network: Extended beyond company (partners)
Outcome Analysis:
Strengths: Ecosystem leverage, network effects, scalability
Risks: Complex coordination, dependency on partners
```
### Comparison: Scenario A vs B vs C (Year 2)
**Side-by-side visualization:**
```
┌──────────────────┬──────────────────┬──────────────────┐
│ Scenario A │ Scenario B │ Scenario C │
│ Rapid Expansion │ Focused Growth │ Platform Pivot │
├──────────────────┼──────────────────┼──────────────────┤
│ Team: 65 people │ Team: 30 people │ Team: 42 people │
│ 5 VPs │ 3 Managers │ 4 Managers │
│ High complexity │ Moderate density │ Extended network │
│ │ │ │
│ [Dense graph] │ [Tight graph] │ [Extended graph] │
│ Many nodes │ Fewer nodes │ External nodes │
│ Hierarchical │ Flat structure │ Hub-and-spoke │
│ │ │ │
│ Burn: High │ Burn: Low │ Burn: Medium │
│ Revenue: High │ Revenue: Medium │ Revenue: Variable│
│ Risk: Medium │ Risk: Low │ Risk: High │
└──────────────────┴──────────────────┴──────────────────┘
```
**Comparison metrics:**
```
Metric Scenario A Scenario B Scenario C
─────────────────────────────────────────────────────────────
Team Size 65 30 42
Management Layers 4 2 3
Network Density 0.089 0.156 0.112*
Avg Connections/Person 5.8 4.7 6.3*
External Connections 5 8 24
Products 3 1 Platform
Revenue Potential $15M $5M $8M
Risk Score 7/10 3/10 8/10
* Including external partner nodes
```
### Actor Journey: CTO (Across All Scenarios)
**Scenario A (Rapid Expansion):**
```
Current → Year 1 → Year 2
Role:
CTO (Hands-on) → VP Engineering → CTO (Strategic)
Direct Reports:
3 → 8 → 23
Focus:
Architecture → Team building → Organization leadership
Network Position:
Central-technical → Central-management → Central-strategic
Note: Increasingly removed from code, focus on scaling organization
```
**Scenario B (Focused Growth):**
```
Current → Year 1 → Year 2
Role:
CTO (Hands-on) → CTO (Hands-on) → CTO (Technical Lead)
Direct Reports:
3 → 6 → 10
Focus:
Architecture → Product excellence → Technical depth
Network Position:
Central-technical → Central-technical → Central-technical
Note: Remains hands-on, deep technical involvement, leads by example
```
**Scenario C (Platform Pivot):**
```
Current → Year 1 → Year 2
Role:
CTO (Hands-on) → CTO + Chief Architect → CTO (Ecosystem)
Direct Reports:
3 → 8 → 12
Focus:
Product → Platform architecture → External integrations
Network Position:
Central-technical → Central-hub → Hub-to-external
Note: Shifts to platform thinking, manages internal + external relations
```
**Comparison visualization:**
```
Scenario A Scenario B Scenario C
Year 2: (Strategic) (Technical) (Ecosystem)
Hands-on ●──────────●──────────●──────────● ●──────────●
Code: None Moderate Some
Team Size: ●──────────●──────────●──────────● ●──────────●
Huge (23) Small (10) Medium (12)
External ●──────────●──────────●──────────● ●──────────●
Focus: Low Low High
Stress: ●──────────●──────────●──────────● ●──────────●
High Low Medium
Job ●──────────●──────────●──────────● ●──────────●
Satisfaction: Medium High Medium
```
---
## Example 4: Timeline Scrubber Interaction
### Visual Design
```
┌─────────────────────────────────────────────────────────────────┐
│ Timeline: Company Evolution │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ↓ (You are here) │
│ ●═══●═══●═══●═══●═══●═══●═══●═══●═══●═══●═══● │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ J F M A M J J A S O N D │
│ a e a p a u u u e c o e │
│ n b r r y n l g p t v c │
│ │
│ ◀───────────────────────────────────────────────────────▶ │
│ [Drag to scrub through timeline] │
│ │
│ Speed: [◀] [1x] [▶] Loop: [ ] Auto-play: [ ] │
└─────────────────────────────────────────────────────────────────┘
```
### Interaction States
**Hover over state marker:**
```
● ← Marker highlights
╱╲
╲ Tooltip appears:
┌────────────────┐
│ April 2023 │
│ Q2 Review │
│ 12 actors │
│ 18 relations │
│ Click to view │
└────────────────┘
```
**Click state marker:**
```
Before: After:
●───●───●───● ●───●───●───●
↑ ↑
(You are here) (You are here)
Graph updates with transition animation:
- Actors fade out/in
- Actors move to new positions
- Relations appear/disappear
- Duration: 500ms
```
**Drag scrubber:**
```
Dragging:
●═══●═══●═══●═══●
↑ ↑ ↑ ↑
(scrubbing through intermediate frames)
Graph continuously updates
Shows interpolated states
Smooth animation at 30fps
```
**Multi-select for comparison:**
```
Click first state (Shift+Click):
●═══●═══●═══●═══●
✓ (selected)
Click second state:
●═══●═══●═══●═══●
✓ ✓
└───────┘
(Range highlighted)
Compare button appears:
[⚖ Compare Selected]
```
---
## Example 5: Diff Visualization Modes
### Mode 1: Overlay Mode
```
Original graph (State A) shown in gray/muted colors
Changes overlaid with highlighting:
┌─────────────────────────────────────┐
│ │
│ Alice │
│ (gray) │
│ │ │
│ │ │
│ ┌─┴─┐ │
│ │ │ │
│ Bob Carol │
│ (gray)(gray) │
│ │
│ NEW! │
│ ┌─────┐ │
│ │ Dave │ ← Green border │
│ └─────┘ │
│ │ │
│ │ ← Green edge │
│ │ │
│ Carol │
│ │
└─────────────────────────────────────┘
Legend:
■ Green = Added
■ Red = Removed (shown faded)
■ Yellow = Modified
■ Gray = Unchanged
```
### Mode 2: Side-by-Side Mode
```
┌──────────────────────┬──────────────────────┐
│ State A (Before) │ State B (After) │
├──────────────────────┼──────────────────────┤
│ │ │
│ Alice │ Alice │
│ │ │ │ │
│ │ │ │ │
│ ┌─┴─┐ │ ┌─┴─┐ │
│ │ │ │ │ │ │
│ Bob Carol │ Bob Carol │
│ │ │ │
│ │ │ │
│ │ Dave │
│ │ (green) │
│ │ │
│ Actors: 3 │ Actors: 4 │
│ Relations: 2 │ Relations: 3 │
└──────────────────────┴──────────────────────┘
Synchronized: Zoom and pan linked between both views
```
### Mode 3: Diff List View
```
┌─────────────────────────────────────────────────────────┐
│ Changes: State A → State B │
├─────────────────────────────────────────────────────────┤
│ │
│ ADDED (1 actor, 1 relation) │
│ ✓ Dave (Person) │
│ ✓ Carol → Dave (Collaboration) │
│ │
│ REMOVED (0) │
│ (none) │
│ │
│ MODIFIED (1 actor) │
│ ○ Carol │
│ • Position: (120, 80) → (180, 100) │
│ • Connections: 1 → 2 │
│ │
│ UNCHANGED (2 actors, 2 relations) │
│ [Collapse to hide] │
│ │
│ Summary: │
│ Total changes: 3 │
│ Actors affected: 2 (50%) │
│ Relations affected: 1 (33%) │
│ Network density change: +15% │
└─────────────────────────────────────────────────────────┘
```
### Mode 4: Animated Diff
```
Animation sequence (10 frames, 2 seconds total):
Frame 0 (State A):
Alice, Bob, Carol visible
Frame 3:
Dave fades in (opacity 0.3)
Frame 5:
Dave fully visible
New edge starts growing from Carol
Frame 7:
Edge fully connected
Carol moves to new position (interpolated)
Frame 10 (State B):
Final state
Highlighting fades out over 1 second
Visual cues during animation:
- New elements pulse briefly
- Removed elements fade with red glow
- Modified elements highlighted during change
```
---
## Example 6: Actor Journey Visualization
### Journey Timeline View
```
Actor: Sarah Chen
Timeframe: January 2023 - December 2023
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Jan Feb Mar Apr May Jun Jul Aug Sep │
│ ●──────●──────●──────●──────●──────●──────●──────●──────● │
│ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │
│ Eng Eng Sr.Eng Sr.Eng Lead Lead Manager Manager Manager│
│ │
│ Connections: 3→3→4→5→6→7→8→10→12 │
│ │
│ Key Events: │
│ Mar: Promotion to Senior Engineer │
│ May: Promoted to Team Lead │
│ Jul: Became Engineering Manager │
│ Sep: Team expanded significantly │
│ │
│ Property Changes: │
│ • Title changed: 3 times │
│ • Direct reports: 0→0→2→2→4→4→8→8→8 │
│ • Position: Center-left → Center (more central) │
│ │
│ Relationship Evolution: │
│ • Peer relationships: 3→3→4→4→3→3→2→2→1 (declining) │
│ • Managerial relations: 0→0→0→2→4→4→8→10→12 (growing) │
│ • Cross-team relations: 0→0→1→2→3→5→6→8→10 (growing) │
└─────────────────────────────────────────────────────────────────┘
```
### Journey Graph View
```
Visual representation of Sarah's network evolution:
January (Starting point):
[Sarah]
┌────┼────┐
│ │ │
[Tom][Ann][Lee]
(peers)
May (Became Team Lead):
[Sarah] ← Now has direct reports
┌────┼────┬────┐
│ │ │ │
[Tom][Ann][Lee][New]
↓ ↓
[Jr1][Jr2]
September (Engineering Manager):
[Sarah]
┌────────┼────────┐
│ │ │
[Lead1][Lead2][Lead3]
│ │ │
┌─┼─┐ ┌─┼─┐ ┌─┼─┐
[T][T] [T][T] [T][T]
Network metrics:
Betweenness centrality: 0.05 → 0.15 → 0.42 (×8.4 increase)
Degree centrality: 0.12 → 0.18 → 0.35 (×2.9 increase)
Closeness centrality: 0.25 → 0.32 → 0.48 (×1.9 increase)
```
---
## Example 7: Scenario Branching Visualization
### Tree View
```
┌─────────────────────────────────────────────────────────────────┐
│ Scenario Tree: Strategic Planning │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Current State │
│ (Jan 2024) │
│ ● │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ │ │ │ │
│ Scenario A Scenario B Scenario C │
│ (Rapid Expand) (Focused) (Platform) │
│ ● ● ● │
│ │ │ │ │
│ ┌────┼────┐ ┌────┴────┐ ┌────┴────┐ │
│ │ │ │ │ │ │ │ │
│ Q2 Q3 Q4 Q2 Q3 Q2 Q3 │
│ ● ● ● ● ● ● ● │
│ │ │ │
│ Q4-A1 │ │
│ ● ┌────┴────┐ │
│ │ │ │ │
│ Q4-A2 Q4-C1 Q4-C2 │
│ ● ● ● │
│ │
│ Colors: │
│ ● Blue = Scenario A branch │
│ ● Green = Scenario B branch │
│ ● Purple = Scenario C branch │
│ ● Gray = Current reality │
│ │
│ [Expand All] [Collapse All] [Compare Scenarios] │
└─────────────────────────────────────────────────────────────────┘
```
### Timeline View with Branches
```
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ●─────●─────● Scenario A │
│ / Q2 Q3 Q4 (Rapid) │
│ / │
│ ●────────Current────────● │
│ Jan 2024 │ │
│ \ │
│ ●────● Scenario B │
│ Q2 Q3 (Focused) │
│ │
│ ●─────●─────●─────● Scenario C │
│ / Q2 Q3 Q4-C1 Q4-C2 (Platform) │
│ / │
│ / │
│ ● │
│ │
│ Hover on branch to see: │
│ • Scenario assumptions │
│ • Key metrics comparison │
│ • Probability/confidence │
│ • Notes and rationale │
└─────────────────────────────────────────────────────────────────┘
```
---
## Example 8: Presentation Mode
### Full-Screen Slideshow
```
┌───────────────────────────────────────────────────────────────────┐
│ │
│ [F to toggle fullscreen] │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Organizational Evolution │ │
│ │ 2023-2024 │ │
│ │ │ │
│ │ │ │
│ │ [Graph Visual] │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ Key Insights: │ │
│ │ • Team grew by 80% over 12 months │ │
│ │ • Network density increased significantly │ │
│ │ • Leadership structure matured │ │
│ │ │ │
│ │ State 3 of 5 │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ [◀ Previous] [⏸ Pause] [▶ Next] [Esc Exit] │
│ │
└───────────────────────────────────────────────────────────────────┘
Navigation:
- Arrow keys to navigate
- Space to play/pause
- Esc to exit presentation mode
- Number keys to jump to slide
- 'R' to restart from beginning
```
---
## Summary
These examples demonstrate:
1. **Temporal Evolution**: How organizations, families, and systems change over time
2. **Scenario Exploration**: Comparing alternative futures with different assumptions
3. **Visual Comparison**: Multiple ways to see and understand differences
4. **Actor Tracking**: Following individuals through changes
5. **Interactive Timeline**: Scrubbing, clicking, and animating through states
6. **Presentation**: Telling compelling stories with data
All visualizations should be:
- **Interactive**: Click, drag, hover for more information
- **Animated**: Smooth transitions between states
- **Informative**: Rich metadata and context
- **Exportable**: Save as images, videos, or reports
- **Responsive**: Work on different screen sizes
The goal is to make temporal and scenario analysis intuitive, visual, and powerful for storytelling and analysis.

View file

@ -0,0 +1,152 @@
# Workspace Persistence Architecture
## Overview
The workspace manager now functions as a **persistent document library**. Documents are stored permanently in localStorage and remain available even after their tabs are closed.
## Key Concepts
### Document States
1. **Created Documents**: All documents created, imported, or opened are stored persistently in localStorage
2. **Open Documents**: Documents with active tabs (tracked in `documentOrder`)
3. **Closed Documents**: Documents stored in localStorage but without active tabs
### Data Structure
```typescript
// Workspace State (saved to localStorage)
{
workspaceId: string;
workspaceName: string;
documentOrder: string[]; // IDs of documents with open tabs
activeDocumentId: string | null; // Currently visible document
settings: WorkspaceSettings;
}
// Document Metadata (lightweight, one per document)
{
id: string;
title: string;
isDirty: boolean;
lastModified: string;
viewport?: { x, y, zoom }; // Persisted viewport state
}
// In-Memory State
{
documents: Map<string, ConstellationDocument>; // Loaded documents (performance optimization)
documentMetadata: Map<string, DocumentMetadata>; // All document metadata
}
```
## User Flows
### Creating a Document
1. User clicks "New Document"
2. Document is created and saved to localStorage
3. Document ID is added to `documentOrder` (opens as tab)
4. Document metadata is added to `documentMetadata`
5. Document is loaded into memory (`documents` Map)
### Closing a Tab
1. User closes a document tab (X button)
2. `closeDocument()` is called
3. Document ID is **removed from `documentOrder`** (tab disappears)
4. Document **remains in localStorage** (persistent storage)
5. Document metadata **remains in `documentMetadata`**
6. Document is unloaded from memory (performance optimization)
### Opening a Closed Document
1. User opens Document Manager
2. All documents from `documentMetadata` are displayed (including closed ones)
3. Closed documents are visually indicated (no "Open" badge)
4. User clicks on a closed document
5. `switchToDocument()` is called
6. Document is loaded from localStorage into memory
7. Document ID is **added back to `documentOrder`** (tab appears)
8. Document becomes active
### Deleting a Document
1. User clicks Delete in Document Manager
2. Confirmation dialog appears
3. If confirmed, `deleteDocument()` is called
4. Document is **removed from localStorage** (permanent deletion)
5. Document is removed from `documentOrder` (if open)
6. Document metadata is removed from `documentMetadata`
7. Document is unloaded from memory
## Implementation Details
### Key Functions
#### `closeDocument(documentId)`
- Removes from `documentOrder` (closes tab)
- Keeps in localStorage (persistent)
- Checks for unsaved changes before closing
#### `switchToDocument(documentId)`
- Loads document from localStorage if not in memory
- Adds to `documentOrder` if not already there (reopens tab)
- Sets as `activeDocumentId`
#### `deleteDocument(documentId)`
- Permanently removes from localStorage
- Removes from `documentOrder`
- Removes from `documentMetadata`
- Requires confirmation
### Document Manager Display
- Shows **all documents** from `documentMetadata` (not just `documentOrder`)
- Visual indicators:
- **Blue border + "Open" badge**: Document has an active tab
- **Orange dot**: Document has unsaved changes
- **Search**: Filters across all documents
- Footer shows: "X documents in workspace • Y open"
### Performance Optimizations
- **Lazy Loading**: Documents are only loaded into memory when needed
- **Unload**: Closed documents are removed from memory (but stay in storage)
- **Viewport Persistence**: Each document's viewport state is saved and restored
### History Management
- History stacks are per-document but **not persisted** to localStorage
- History is reset when a document is closed and reopened
- This is intentional to avoid localStorage bloat
## Storage Keys
```typescript
// Workspace state
'constellation:workspace:v1'
// Individual document
'constellation:document:v1:{documentId}'
// Document metadata
'constellation:meta:v1:{documentId}'
```
## Migration Notes
- Old single-document format is automatically migrated on first load
- Migration creates a workspace with the legacy document as the first document
- Migration is one-way (cannot downgrade)
## Future Enhancements
Potential improvements for future versions:
1. **Recent Documents List**: Show recently accessed documents separately
2. **Favorites**: Star/pin frequently used documents
3. **Document Tags**: Categorize documents with user-defined tags
4. **Trash/Archive**: Soft delete with recovery option
5. **Cloud Sync**: Synchronize workspace across devices
6. **History Persistence**: Optionally save undo/redo stacks (with size limits)

View file

@ -111,10 +111,6 @@ export const useTimelineStore = create<TimelineStore & TimelineActions>(
console.log(`Timeline initialized for document ${documentId}`);
},
setActiveDocument: (documentId: string) => {
set({ activeDocumentId: documentId });
},
loadTimeline: (documentId: string, timeline: Timeline) => {
set((state) => {
const newTimelines = new Map(state.timelines);

View file

@ -25,7 +25,6 @@ vi.mock("./timelineStore", () => ({
getState: () => ({
timelines: new Map(),
loadTimeline: vi.fn(),
setActiveDocument: vi.fn(),
clearTimeline: vi.fn(),
}),
},

View file

@ -600,11 +600,6 @@ export const useWorkspaceStore = create<Workspace & WorkspaceActions>((set, get)
activeDocumentId: documentId,
};
});
// Always sync timelineStore.activeDocumentId — loadDocument returns early
// when the document is already in memory, so loadTimeline is never called
// and timelineStore.activeDocumentId would remain stale.
useTimelineStore.getState().setActiveDocument(documentId);
});
},

View file

@ -66,9 +66,6 @@ export interface TimelineActions {
// Load timeline from document
loadTimeline: (documentId: string, timeline: Timeline) => void;
// Set active document without reloading timeline data (for switching between already-loaded documents)
setActiveDocument: (documentId: string) => void;
// Create new state
createState: (label: string, description?: string, cloneFromCurrent?: boolean) => StateId;