Skip to content

Commit 7cfad62

Browse files
committed
docs: consolidate documentation into ./docs folder
- Create docs/architecture.md - data model, storage, identity system - Create docs/api.md - API endpoint reference - Create docs/cli.md - CLI command reference - Create docs/development.md - development setup guide - Create docs/providers.md - genealogy provider configuration - Create docs/roadmap.md - detailed phase documentation with Phase 17 (Socket.IO) - Simplify PLAN.md to high-level summary with links to docs - Streamline CLAUDE.md with quick reference and links - Simplify README.md with user-focused content and links
1 parent 6a3cd0a commit 7cfad62

9 files changed

Lines changed: 1250 additions & 1887 deletions

File tree

CLAUDE.md

Lines changed: 76 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -1,248 +1,107 @@
11
# CLAUDE.md
22

3-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
3+
Guidance for Claude Code when working with this repository.
44

55
## Project Overview
66

7-
SparseTree is a genealogy toolkit for creating local databases of your family tree, validating data, curating favorites, and generating sparse family tree visualizations that can be printed on posters. It connects to genealogy providers (FamilySearch, Ancestry, WikiTree, 23andMe) to download ancestry data, stores it locally as JSON, and provides a web UI for browsing, searching, and visualizing your tree. The "sparse tree" feature lets you mark interesting ancestors as favorites and generate a simplified visualization showing only those people connected through their lineage.
7+
SparseTree is a genealogy toolkit for creating local databases of your family tree from multiple providers (FamilySearch, Ancestry, WikiTree, 23andMe), with a web UI for browsing, searching, and visualizing your tree. The "sparse tree" feature lets you mark interesting ancestors as favorites and generate simplified visualizations.
88

9-
## Commands
9+
## Quick Reference
1010

11-
### Download ancestry data
12-
```bash
13-
FS_ACCESS_TOKEN=YOUR_TOKEN node index PERSON_ID
14-
# Options:
15-
# --max=N Limit to N generations
16-
# --ignore=ID1,ID2 Skip specific person IDs
17-
# --cache=all|complete|none Cache behavior (default: all)
18-
# --oldest=YEAR Only include people born after YEAR (supports BC notation)
19-
# --tsv=true Also log to TSV file during indexing
20-
```
11+
| Resource | Description |
12+
|----------|-------------|
13+
| [docs/architecture.md](./docs/architecture.md) | Data model, storage layout, identity system |
14+
| [docs/api.md](./docs/api.md) | API endpoint reference |
15+
| [docs/cli.md](./docs/cli.md) | CLI command reference |
16+
| [docs/development.md](./docs/development.md) | Development setup, PM2, browser automation |
17+
| [docs/providers.md](./docs/providers.md) | Genealogy provider configuration |
18+
| [docs/roadmap.md](./docs/roadmap.md) | Detailed phase documentation |
19+
| [PLAN.md](./PLAN.md) | High-level roadmap |
2120

22-
### Find lineage path between two people
23-
```bash
24-
node find ROOT_ID ANCESTOR_ID
25-
# Options:
26-
# --method=s|l|r shortest/longest/random path (default: s)
27-
```
28-
29-
### Export database to TSV
30-
```bash
31-
node tsv DB_ID
32-
```
21+
## Essential Commands
3322

34-
### Print sorted by date
3523
```bash
36-
node print DB_ID [--bio]
37-
```
24+
# Development
25+
pm2 restart ecosystem.config.cjs # Restart app (ports 6373/6374)
26+
npm run build # Build all packages
3827

39-
### Purge records from cache
40-
```bash
41-
node purge ID1,ID2
42-
```
28+
# Migrations
29+
npx tsx scripts/migrate.ts # Run migrations
30+
npx tsx scripts/migrate.ts --status # Check status
4331

44-
### Prune unused person files
45-
```bash
46-
node prune DB_ID
47-
```
32+
# Update
33+
./update.sh # Pull, build, migrate, restart
4834

49-
## Architecture
50-
51-
### Data Flow
52-
1. `index.js` fetches person data from FamilySearch API via `lib/fscget.js`
53-
2. Raw API responses stored in `data/person/{ID}.json`
54-
3. `lib/json2person.js` transforms API data to simplified person objects
55-
4. Compiled graph database saved to `data/db-{ID}.json`
56-
57-
### Key Files
58-
- `config.js` - API credentials (via `FS_ACCESS_TOKEN` env var), rate limiting delays, and "known unknowns" filter list
59-
- `lib/fs.client.js` - FamilySearch API client wrapper using `fs-js-lite`
60-
- `lib/json2person.js` - Transforms raw API JSON to person objects with: name, lifespan, location, parents[], children[], occupation, bio
61-
- `lib/pathShortest.js`, `lib/pathLongest.js`, `lib/pathRandom.js` - Graph traversal algorithms for finding lineage paths
62-
63-
### Data Structure
64-
Person object in database:
65-
```javascript
66-
{
67-
name: string,
68-
lifespan: "BIRTH-DEATH", // supports BC notation
69-
location: string,
70-
parents: [ID, ID],
71-
children: [ID, ...], // populated during db save
72-
occupation: string,
73-
bio: string
74-
}
35+
# Download ancestry
36+
FS_ACCESS_TOKEN=TOKEN node index PERSON_ID --max=10
7537
```
7638

77-
### Authentication
78-
Get your access token from browser dev tools when logged into FamilySearch - copy the Authorization header value (without "Bearer" prefix). Tokens last 24+ hours.
79-
80-
## Web UI
81-
82-
### Development
83-
The app runs via PM2 with live reload enabled. No need to run `npm run dev` - just edit files and changes will auto-reload.
39+
## Project Structure
8440

85-
```bash
86-
# App is already running on:
87-
# - Frontend: http://localhost:6373
88-
# - Backend: http://localhost:6374
89-
90-
# If needed to restart:
91-
pm2 restart ecosystem.config.cjs
9241
```
93-
94-
### Structure
95-
- `client/` - React + Vite + Tailwind frontend
96-
- `server/` - Express API backend
97-
- `shared/` - TypeScript types shared between client/server
98-
99-
### API Endpoints
100-
- `GET /api/databases` - List all graph databases
101-
- `GET /api/persons/:dbId` - List persons in database
102-
- `GET /api/persons/:dbId/:id/tree` - Get tree data for D3
103-
- `GET /api/search/:dbId?q=&location=&occupation=` - Search with filters
104-
- `POST /api/path/:dbId` - Find path (body: source, target, method)
105-
- `GET /api/indexer/events` - SSE stream for indexer progress
106-
- `GET /api/export/:dbId/tsv` - Export as TSV
107-
108-
### AI Toolkit Integration
109-
The server integrates `@portos/ai-toolkit` for AI provider management:
110-
- `GET/POST /api/providers` - Manage AI providers
111-
- `GET/POST /api/runs` - Execute and track AI runs
112-
- `GET/POST /api/prompts` - Manage prompt templates
113-
114-
Provider configuration stored in `data/ai/providers.json`.
115-
116-
## Browser Automation
117-
118-
Persistent Chrome with CDP on port 9920:
119-
```bash
120-
./.browser/start.sh
42+
client/ # React + Vite + Tailwind frontend
43+
server/ # Express API backend
44+
shared/ # TypeScript types
45+
lib/ # CLI tools (index, find, purge, etc.)
46+
scripts/ # Migration scripts
47+
data/ # Local storage (git-ignored)
48+
docs/ # Documentation
12149
```
122-
Profile data stored in `.browser/data/`. Connect via `ws://localhost:9920`.
123-
124-
## Git Workflow
125-
126-
- **dev**: Active development (auto-bumps patch on CI pass)
127-
- **main**: Production releases only
128-
- PR `dev → main` creates tagged release and preps next version
129-
- **Use `/gitup` to push** - The dev branch receives auto version bump commits from CI. Always use `git pull --rebase --autostash && git push` (or `/gitup`) instead of plain `git push`.
130-
- Update `.changelog/v{major}.{minor}.x.md` when making changes (see Release Changelog Process below)
131-
- **Commit after each feature or bug fix** - lint, commit, and push automatically to keep work safe
13250

133-
## Release Changelog Process
51+
## Architecture Summary
13452

135-
All release notes are maintained in `.changelog/v{major}.{minor}.x.md` files. Each minor version series has a single changelog file that accumulates changes throughout development. **No root CHANGELOG.md** - all changelog content lives in `.changelog/`.
136-
137-
### During Development
138-
139-
**Always update `.changelog/v0.2.x.md`** when you make changes:
140-
- Add entries under appropriate emoji sections (🎉 Features, 🐛 Fixes, 🔧 Improvements, 🗑️ Removed)
141-
- Keep the version as `v0.2.x` throughout development (don't change it to 0.2.2, 0.2.3, etc.)
142-
- Group related changes together for clarity
143-
- Explain the "why" not just the "what"
144-
145-
### Before Releasing to Main
146-
147-
Final review before merging `dev → main`:
148-
- Ensure all changes are documented in `.changelog/v0.2.x.md`
149-
- Add the release date (update "YYYY-MM-DD" to actual date)
150-
- Polish descriptions for clarity
151-
- Commit the changelog
152-
153-
### On Release (Automated)
154-
155-
When merging to `main`, the GitHub Actions workflow automatically:
156-
1. Reads `.changelog/v0.2.x.md`
157-
2. Replaces all instances of `0.2.x` with actual version (e.g., `0.2.5`)
158-
3. Creates the GitHub release with substituted changelog
159-
4. Renames `v0.2.x.md``v0.2.5.md` (preserves git history)
160-
5. Bumps dev to next minor version (e.g., 0.3.0)
161-
162-
See `.changelog/README.md` for detailed format and best practices.
163-
164-
## Data Storage Architecture
165-
166-
SparseTree uses a hybrid storage model:
167-
- **JSON files** (`data/`) - Source of truth for raw API data
168-
- **SQLite database** (`data/sparsetree.db`) - Fast query index with FTS5 search, recursive CTEs for path finding
169-
- **Content-addressed blobs** (`data/blobs/`) - Deduplicated media storage
170-
171-
### SQLite Schema
172-
Key tables in `server/src/db/schema.sql`:
173-
- `person` - Canonical person records with ULID primary keys
174-
- `external_identity` - Maps provider IDs (FamilySearch, Ancestry, etc.) to canonical IDs
175-
- `parent_edge` / `spouse_edge` - Relationship graphs with provenance
176-
- `vital_event` - Birth, death, burial events with dates/places
177-
- `claim` - Extensible facts (occupation, religion, bio, etc.)
178-
- `person_fts` - FTS5 virtual table for full-text search
179-
180-
### ID Mapping
181-
- Canonical IDs: ULIDs (26-char, sortable, no special chars)
182-
- External IDs: Provider-specific (e.g., FamilySearch `GW21-BZR`)
183-
- `idMappingService` handles bidirectional lookup with in-memory cache
184-
185-
## Data Migrations
186-
187-
SparseTree uses a migration system for schema and data changes. Migrations are tracked in `data/.data-version` (data migrations) and the SQLite `migration` table (schema migrations).
188-
189-
### Running Migrations
190-
```bash
191-
# Run all pending migrations
192-
npx tsx scripts/migrate.ts
193-
194-
# Preview what would run (no changes made)
195-
npx tsx scripts/migrate.ts --dry-run
196-
197-
# Check migration status
198-
npx tsx scripts/migrate.ts --status
199-
200-
# Rollback last N migrations
201-
npx tsx scripts/migrate.ts --rollback=1
53+
```
54+
Layer 3: Local Overrides → User edits (SQLite local_override)
55+
Layer 2: Normalized Data → SQLite (person, life_event, parent_edge, etc.)
56+
Layer 1: Raw Provider Cache → JSON files (data/person/*.json)
20257
```
20358

204-
### Creating New Migrations
205-
1. **Schema migrations** (`server/src/db/migrations/`): Add new files like `002_add_column.ts`
206-
2. **Data migrations** (`scripts/migrate.ts`): Add entries to `dataMigrations` array
207-
208-
Migration naming convention: `NNN_description` (e.g., `001_initial`, `002_add_indexes`)
59+
- **Canonical IDs**: ULIDs (26-char, owned by SparseTree)
60+
- **External IDs**: Provider-specific (FamilySearch, Ancestry, etc.)
61+
- **SQLite**: Fast queries with FTS5 search, JSON as source of truth
20962

210-
### Migration in Release Process
211-
- Data migrations run automatically via `update.sh`
212-
- When creating migrations that affect existing data:
213-
1. Test with `--dry-run` first
214-
2. Provide a `down()` function when possible for rollback
215-
3. Document the migration in the changelog
216-
4. Consider backwards compatibility with older app versions
63+
## Git Workflow
21764

218-
## Updating SparseTree
65+
- **dev**: Active development (auto-bumps patch on CI)
66+
- **main**: Production releases only
67+
- **Push pattern**: `git pull --rebase --autostash && git push`
68+
- **Changelog**: Update `.changelog/v{major}.{minor}.x.md` with changes
69+
- **Commit often**: After each feature or bug fix
70+
71+
## Code Guidelines
72+
73+
- ES modules (`"type": "module"`)
74+
- Functional programming over classes
75+
- No `try/catch` if avoidable
76+
- No `window.alert`/`window.confirm` - use toast and modals
77+
- Full URL paths for routes (no modals without deep links)
78+
- DRY and YAGNI patterns
79+
- Never use `pm2 kill` or `pm2 delete all`
80+
81+
## Key Files
82+
83+
| File | Purpose |
84+
|------|---------|
85+
| `config.js` | API credentials, rate limits |
86+
| `lib/json2person.js` | Transform API → person objects |
87+
| `lib/sqlite-writer.js` | Write to SQLite during indexing |
88+
| `server/src/db/schema.sql` | Full SQLite schema |
89+
| `server/src/services/id-mapping.service.ts` | Canonical ↔ external ID lookup |
90+
| `ecosystem.config.cjs` | PM2 configuration |
21991

220-
Use `update.sh` to pull the latest code and apply all updates:
92+
## Browser Automation
22193

22294
```bash
223-
# Full update: pull, install, build, migrate, restart
224-
./update.sh
225-
226-
# Preview what would happen
227-
./update.sh --dry-run
228-
229-
# Update without restarting PM2
230-
./update.sh --no-restart
231-
232-
# Update from a specific branch
233-
./update.sh --branch=dev
95+
./.browser/start.sh # Start Chrome with CDP
96+
# Default CDP port: 9920
97+
# Profile: .browser/data/
23498
```
23599

236-
The update script:
237-
1. Checks for uncommitted changes (fails if dirty)
238-
2. Pulls latest from main (or specified branch)
239-
3. Installs npm dependencies
240-
4. Builds the application
241-
5. Runs pending data migrations
242-
6. Restarts PM2 services
100+
Web UI: `/settings/browser` for connection, `/providers/genealogy` for logins.
243101

244102
## Notes
245-
- The database has cyclic loop issues (people linked as their own ancestors) - use longest path method to detect these
246-
- ES modules (`"type": "module"` in package.json)
247-
- Rate limiting built-in with random delays between API calls
248-
- SQLite auto-enables when `data/sparsetree.db` exists with data
103+
104+
- Database has cyclic loops - use `--method=l` (longest path) to detect
105+
- SQLite auto-enables when `data/sparsetree.db` exists
106+
- Rate limiting built into API calls
107+
- Credentials encrypted with AES-256-GCM in `data/credentials.json`

0 commit comments

Comments
 (0)