Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ RUN npm ci --omit=dev
# Copy server code
COPY server/ ./server/

# Copy shared constants for server use
# Copy shared modules the server imports from src/
COPY src/utils/constants.js ./src/utils/constants.js
COPY src/utils/knowledgeGraph.js ./src/utils/knowledgeGraph.js

# Copy built frontend
COPY --from=builder /app/dist ./dist
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,28 @@ Toolbox is a self-hosted web app that brings together everything you need to pre
| 📖 **Knowledge Guide** | 7-pillar structured library with AI-assisted Commit flow to save learnings from chat sessions |
| 🎨 **Architecture Builder** | Drag-and-drop whiteboard with 20+ components, bezier connections, templates, and AI design verification |
| 📚 **Flashcards + SRS** | SM-2 spaced repetition system with per-deck settings, card browser, deck stats, and a study activity heatmap |
| 🕸️ **Knowledge Graph** | Interactive prerequisite map of ~60 system design concepts with a live SM-2 retention heatmap, readiness filters, curated learning tracks, and deep links into Guide, Builder, and Flashcards |
| 🧱 **Adaptive Remediation** | Fail an advanced card and the SRS engine detects shaky foundations, then queues the prerequisite cards into your next review session |
| 🧮 **BotE Calculator** | Back-of-the-envelope sizing sandbox: live QPS/storage/cache/bandwidth/hardware math, scenario presets, an interactive latency cheat-sheet with a budget composer, AI "Audit My Math", and 1-click Markdown export |
| 🧠 **Feynman Simulator** | Voice-enabled Feynman technique: explain a concept, get structured AI feedback on gaps |
| 🔀 **Interleaved Review** | Study all due cards across every deck in a single shuffled session |
| 🍅 **Pomodoro Timer** | Persistent focus timer with plant gamification (🌱→🌸→🥀) and Strict Mode |
| ⚙️ **Shadow Memory** | The AI learns your timeline, strengths, and goals across sessions for personalized coaching |
| 🔌 **Multi-Provider AI** | Gemini, Claude, and OpenAI out of the box, plus bring-your-own-model via any OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, OpenRouter, …) with live model discovery |

---

## 📸 Screenshots

<table>
<tr>
<td align="center"><em>Knowledge Graph — prerequisite map with live SRS heatmap</em></td>
<td align="center"><em>BotE Calculator — capacity estimation sandbox</em></td>
</tr>
<tr>
<td><img src="docs/screenshots/screenshot-graph.png" alt="Knowledge Graph" /></td>
<td><img src="docs/screenshots/screenshot-calculator.png" alt="BotE Calculator" /></td>
</tr>
<tr>
<td align="center"><em>Architecture Whiteboard Builder</em></td>
<td align="center"><em>Structured Knowledge Guide</em></td>
Expand Down Expand Up @@ -111,7 +123,7 @@ All user data lives in a single SQLite file — back it up by copying that file.

## 🛠️ Tech Stack

React 19 · Vite · React Router · Zustand · Vanilla CSS · Node.js · Express · SQLite (`better-sqlite3`) · Vercel AI SDK (Gemini / Claude / OpenAI / BYOM) · Docker
React 19 · Vite · React Router · Zustand · Vanilla CSS · d3-force · Node.js · Express · SQLite (`better-sqlite3`) · Vercel AI SDK (Gemini / Claude / OpenAI / BYOM) · Docker

---

Expand Down
12 changes: 10 additions & 2 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ import { FaArrowRight } from 'react-icons/fa'
### 3. Global State: Use Existing Zustand Stores

For features requiring cross-page persistence, use the existing stores:
- `src/stores/appStore.js` — Theme, sidebar, chat panels, API key, whiteboard nodes/edges, toasts
- `src/stores/appStore.js` — Theme, sidebar, chat panels, API key, whiteboard nodes/edges, toasts, calculator modal, `srsVersion` sync counter
- `src/stores/useTimerStore.js` — Pomodoro timer state
- `src/stores/useCalcStore.js` — BotE Calculator inputs, scenario, and latency budget (persisted to localStorage)

Do not create new top-level stores unless the feature genuinely requires it and doesn't fit in either existing store.
Do not create new top-level stores unless the feature genuinely requires it and doesn't fit in an existing store.

### 4. Backend Changes: Update Both db.js and Routes

Expand Down Expand Up @@ -145,9 +146,16 @@ server/
| Flashcards + SRS | `/study` | `StudyPage.jsx`, `FlashcardView.jsx`, `DeckEditor.jsx`, `CardBrowser.jsx`, `StatsDashboard.jsx` |
| Feynman Simulator | `/feynman` | `FeynmanPage.jsx` |
| Interleaved Review | `/interleaved` | `InterleavedPage.jsx` |
| Knowledge Graph | `/graph` | `GraphPage.jsx`, `components/graph/*`, `src/utils/knowledgeGraph.js`, `server/routes/graph.js`, `server/graph/*` |
| BotE Calculator | `/calculator` + global `⌘E` modal | `CalculatorPage.jsx`, `components/calculator/*`, `src/utils/bote.js`, `useCalcStore.js`, `server/routes/calculator.js` |
| Pomodoro Timer | Global modal | `PomodoroModal.jsx`, `PomodoroWidget.jsx`, `useTimerStore.js` |
| Settings | `/settings` | `SettingsPage.jsx` |

Cross-cutting modules:
- `src/utils/knowledgeGraph.js` — pure graph data + algorithms, imported by BOTH client and server. Keep it dependency-free. Edges must stay acyclic — `validateGraph()` runs at server boot and in tests.
- `server/srs/scheduler.js` — the SM-2 scheduler (`calculateNextSrsState`), shared by decks and graph routes.
- `server/graph/health.js` / `server/graph/remediation.js` — pure functions; the route layer owns all DB access.

---

## Data Structure: Pillars & Blueprint Sections
Expand Down
123 changes: 122 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ All request bodies are JSON (`Content-Type: application/json`) unless noted. All
- [Chat & AI](#chat--ai)
- [Flashcard Decks](#flashcard-decks)
- [Flashcards](#flashcards)
- [Knowledge Graph](#knowledge-graph)
- [BotE Calculator](#bote-calculator)
- [Whiteboard Boards](#whiteboard-boards)
- [Guide Content](#guide-content)
- [User Profile (Shadow Memory)](#user-profile-shadow-memory)
Expand Down Expand Up @@ -465,7 +467,7 @@ All fields are optional. SRS state fields (`ease_factor`, `interval`, etc.) are

### `PUT /api/decks/:deckId/cards/:cardId/review`

Submit a review rating for a card. Runs the SM-2 SRS algorithm and persists the next state. Also increments the study session heatmap counter for today.
Submit a review rating for a card. Runs the SM-2 SRS algorithm and persists the next state. Also increments the study session heatmap counter for today. (`POST` is accepted as an alias for older clients and queued offline mutations.)

**Request Body**
```json
Expand All @@ -482,6 +484,27 @@ Submit a review rating for a card. Runs the SM-2 SRS algorithm and persists the

**Response `200`** — Updated card object with recalculated SRS fields and fresh `srs_previews`.

Side effects tied to the Knowledge Graph remediation engine:

- Reviewing a card resolves its open `remediation_queue` rows.
- On failure (`quality < 3`), the engine finds the card's graph nodes, checks their direct prerequisite nodes for shaky cards (new, learning, lapsed, overdue, or low ease), and queues up to 3 of them for the next session. The response includes the plan:

```json
{
"...": "updated card fields",
"remediation": [
{
"cardId": "uuid",
"front": "What is replication lag?",
"nodeName": "Replication (Leader / Follower)",
"reason": "Foundation for CAP & PACELC"
}
]
}
```

Queued cards lead the next due-card session (single-deck and interleaved) tagged with `is_remediation: 1`, `remediation_node`, and `remediation_reason`.

---

### `DELETE /api/decks/:deckId/cards/:cardId`
Expand All @@ -492,6 +515,104 @@ Delete a single card.

---

## Knowledge Graph

The graph itself (nodes, prerequisite edges, learning tracks) is defined in `src/utils/knowledgeGraph.js` and validated (unique ids, no dangling edges, acyclic) at server boot. These endpoints combine it with live flashcard SRS state.

### `GET /api/graph`

The full graph with live memory health per node.

**Response `200`**
```json
{
"nodes": [
{
"id": "consistent-hashing",
"name": "Consistent Hashing",
"pillarId": "distributed-mechanics",
"pillarName": "Distributed Data Mechanics",
"pillarColor": "#a78bfa",
"topicId": "partitioning-sharding",
"summary": "The hash ring: adding a node only remaps the arc it owns.",
"health": "decayed",
"strength": 0.35,
"counts": { "total": 2, "new": 1, "learning": 0, "lapsed": 1, "due": 0, "maturing": 0, "mastered": 0 },
"ready": false,
"locked": false
}
],
"edges": [{ "from": "partitioning", "to": "consistent-hashing" }],
"tracks": [
{ "id": "senior-distributed", "name": "Senior Distributed Systems", "emoji": "🧠", "description": "...", "nodeIds": ["..."], "nodeCount": 23, "masteredCount": 2 }
],
"stats": { "mastered": 4, "due": 20, "decayed": 2, "unseen": 33 },
"remediationCount": 1
}
```

Health buckets: `mastered` (every graded card at ease ≥ 2.5 and interval > 21 d), `due` (learning, new, or scheduled within 48 h), `decayed` (a lapse, a queued remediation, or crushed ease), `unseen` (no linked cards). Cards link to nodes by keyword phrases, with the card's source guide topic as the fallback.

---

### `GET /api/graph/nodes/:id`

Detail payload for the slide-over panel: linked cards with SRS state, prerequisite/dependent nodes with health, the linked Guide topic (with filled-section count), and whiteboards containing the node's builder components.

**Response `200`** — `{ node, cards, prereqs, dependents, guide, boards }`.

---

### `POST /api/graph/nodes/:id/session`

Build a study session from one node's studyable cards (due, learning, or new), capped at 20.

**Response `200`** — `{ cards, nodeName }`. Cards carry `deckName`, `nodeName`, and `srs_previews`.

---

### `POST /api/graph/tracks/:id/session`

Build a study session for a curated learning track. Cards are ordered by the track's topological (prerequisite-first) node order, due cards before new within each node, capped at 30.

**Response `200`** — `{ cards, trackName, nodeOrder }`.

---

## BotE Calculator

All sizing math runs client-side in `src/utils/bote.js`. The server's only calculator endpoint is the AI sanity check.

### `POST /api/calculator/audit`

"Audit My Math" — sends the current assumptions and computed results to the AI and returns a structured critique.

**Request Body**
```json
{
"scenario": { "id": "url-shortener", "name": "URL Shortener", "description": "..." },
"inputs": { "dau": 10000000, "readRatio": 100, "...": "..." },
"results": { "peakTotalQps": "463", "retainedWithReplication": "1.08 TB", "...": "..." },
"model": "gemini-3.5-flash"
}
```

**Response `200`**
```json
{
"verdict": "revisit",
"summary": "Two or three sentences on the estimate's quality.",
"findings": [
{ "severity": "warning", "area": "Storage", "finding": "...", "suggestion": "..." }
],
"omittedFactors": ["Database index overhead", "CDN offload of media egress"]
}
```

`verdict` is `"sound"` or `"revisit"`. `severity` is `"critical"`, `"warning"`, or `"info"`.

---

## Whiteboard Boards

### `GET /api/boards`
Expand Down
11 changes: 10 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,16 @@ stream: async (payload, onChunk, onDone, signal) => {
server/
├── index.js # Express app setup, middleware, route mounting
├── db.js # SQLite connection, schema creation, migrations
├── srs/
│ └── scheduler.js # SM-2 scheduling (shared by decks + graph routes)
├── graph/
│ ├── health.js # Knowledge-graph node health from SRS state (pure)
│ └── remediation.js # Prerequisite remediation planning (pure)
└── routes/
├── chat.js # AI chat endpoints (streaming + starters)
├── decks.js # Flashcard deck + card CRUD + SRS logic
├── decks.js # Flashcard deck + card CRUD + SRS review + remediation queue
├── graph.js # Knowledge graph: health, node detail, study sessions
├── calculator.js # BotE Calculator AI audit
├── boards.js # Whiteboard board CRUD
├── guide_content.js # Guide section content CRUD
├── config.js # API key management
Expand Down Expand Up @@ -288,6 +295,8 @@ The full API reference is in **[`docs/api.md`](api.md)**. Quick summary of route
| `search.js` | `/api/search` | Cross-domain full-text search |
| `study_sessions.js` | `/api/study_sessions` | Study heatmap data |
| `system.js` | `/api/system` | Stats, cache flush, DB download |
| `graph.js` | `/api/graph` | Knowledge graph with live SRS health, node detail, track/node study sessions |
| `calculator.js` | `/api/calculator` | "Audit My Math" structured AI critique |

---

Expand Down
Binary file modified docs/screenshots/screenshot-builder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/screenshot-calculator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/screenshot-chat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/screenshot-feynman.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/screenshot-flashcards.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/screenshot-graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/screenshot-guide.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/screenshot-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 16 additions & 1 deletion docs/srs-algorithm.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,21 @@ This allows building concept dependency graphs inside a deck.

---

## Knowledge-Graph Remediation

Beyond per-card `prerequisite_id` links, the Knowledge Graph (`src/utils/knowledgeGraph.js`) defines a concept-level prerequisite DAG. Failing a card (`quality < 3`) triggers the remediation engine (`server/graph/remediation.js`):

1. Map the failed card to its graph nodes (keyword phrases first, source guide topic as fallback).
2. Collect the **direct** prerequisite nodes (one hop up, never transitive).
3. Among those nodes' cards, keep the **shaky** ones: never studied, in Learning/Relearning, `ease_factor < 2.3`, `interval < 4` days, or overdue. Solid foundations produce no remediation — then the failure is treated as intrinsic to the card.
4. Queue at most **3** cards (weakest ease first) into `remediation_queue`.

Queued cards lead the next due-card session (before learning/review/new cards), flagged `is_remediation: 1` so the UI shows a Foundation Checkup banner. Reviewing a queued card — at any rating — resolves its queue row. Duplicate open rows for the same card are never created, so the queue cannot flood.

Node health for the graph heatmap lives in `server/graph/health.js`: a node is **mastered** when every graded card has `ease ≥ 2.5` and `interval > 21` days with nothing due within 48 hours, **decayed** on any lapse/remediation/crushed ease, **due** otherwise, and **unseen** with no linked cards.

---

## SRS Preview Labels

The UI shows interval previews for all 4 buttons before the user picks. Formatting rules:
Expand All @@ -179,7 +194,7 @@ The UI shows interval previews for all 4 buttons before the user picks. Formatti

## Implementation Reference

The full algorithm is a single pure function `calculateNextSrsState(card, quality, settings, confidence)` in [`server/routes/decks.js`](../server/routes/decks.js#L25). It returns a plain object with:
The full algorithm is a single pure function `calculateNextSrsState(card, quality, settings, confidence)` in [`server/srs/scheduler.js`](../server/srs/scheduler.js) (shared by the decks and knowledge-graph routes). It returns a plain object with:

```js
{
Expand Down
Loading
Loading