bigwolfe
init
1966985
|
raw
history blame
3.19 kB
# Phase 0: Research & Technical Decisions
## 1. Graph Visualization Library
**Decision**: Use `react-force-graph-2d`.
**Rationale**:
- **Performance**: Uses HTML5 Canvas/WebGL for rendering, capable of handling thousands of nodes (meeting the "personal knowledge base" scale requirement).
- **React Integration**: Native React component wrapper around `force-graph`, managing the lifecycle and updates declarative.
- **Feature Set**: Built-in zoom/pan, auto-centering, node/link interactions (hover/click), and flexible styling.
- **Maintainability**: Widely used, active community.
**Alternatives Considered**:
- `vis-network`: Good but heavier and imperative API is harder to integrate cleanly with modern React hooks.
- `d3-force` (raw): Too low-level. Would require rebuilding canvas rendering, zoom/pan logic, and interaction handlers from scratch.
- `cytoscape.js`: Powerful but focused more on graph theory analysis; visual customization is CSS-like but sometimes more complex for "floating particle" aesthetics.
## 2. Data Structure & API
**Decision**: Flat structure with `nodes` and `links` arrays.
**Schema**:
```json
{
"nodes": [
{ "id": "path/to/note.md", "label": "Note Title", "val": 1, "group": "folder-name" }
],
"links": [
{ "source": "path/to/source.md", "target": "path/to/target.md" }
]
}
```
**Rationale**:
- Matches the expected input format of `react-force-graph`.
- `val` property allows automatic node sizing based on degree (calculated on backend or frontend). Backend calculation is preferred for caching/performance.
- `id` uses the file path to ensure uniqueness and easy mapping back to navigation events.
## 3. Theme Integration
**Decision**: Pass dynamic colors via React props, reading from CSS variables or a ThemeContext.
**Strategy**:
- The `GraphView` component will hook into the current theme (light/dark).
- Colors for background, nodes, and text will be passed to `<ForceGraph2D />`.
- **Light Mode**: White background, dark grey nodes/links.
- **Dark Mode**: `hsl(var(--background))` (usually dark), light grey nodes.
- **Groups**: Use a categorical color scale for folders (e.g., D3 scale or a fixed palette).
## 4. Unlinked Notes
**Decision**: Include all notes in the `nodes` array, even if they have no entries in `links`.
**Physics**:
- The force simulation will naturally push unconnected nodes away from the center cluster but keep them within the viewport if a bounding box or gravity is applied.
- We will apply a weak `d3.forceManyBody` (repulsion) and a central `d3.forceCenter` to keep the "cloud" visible.
## 5. Backend Implementation
**Decision**: Add `get_graph_data` to `IndexerService`.
**Logic**:
1. Fetch all notes from `note_metadata` (id, title).
2. Fetch all links from `note_links` where `is_resolved=1`.
3. Compute link counts for node sizing (optional optimization: do this in SQL or Python).
4. Return JSON.
5. **Caching**: Use a simple in-memory cache with a short TTL (e.g., 5 minutes) or invalidation on note create/update events to ensure sub-2s response times for large vaults. *For V1, direct SQL query is likely fast enough for <1000 notes.*