Personal dashboard for visualizing GitHub commit activity across multiple repositories.
- Repository overview with
7d/30d/90d/180d/360d/allselectors - Detailed repository pages (daily chart + calendar heatmap)
- Cross-repository comparison (regularity, streaks, gaps)
- Impact analytics (additions, deletions, files changed, largest commits)
- Story view with narrative highlights
- Settings UI for repository sync/activation and display names
- Automated section screenshot generation for all pages and date ranges
- TypeScript
- SvelteKit + Vite
- SQLite + Drizzle ORM
- Apache ECharts
- GitHub CLI (
gh) for GitHub API access
- Node.js 22 LTS
- GitHub CLI authenticated (
gh auth status)
# Clone repository
git clone git@github.com:hipotures/gitiary.git
cd gitiary
# Install dependencies
npm install
# Optional: create local env file
cp .env.example .env
# Initialize/update SQLite schema
npx drizzle-kit push
# Start app
npm run devOpen http://localhost:5173/settings and then:
- Click Sync with GitHub (imports repositories into local DB as inactive).
- Activate repositories you want to track.
- Run per-repo sync from Settings (30d or full), or use CLI sync.
Repository configuration is stored in SQLite table repo.
- Indexer reads active repositories from DB (
repo.is_active = 1). /api/repos/syncand/settingspopulate/update repository records.repos.jsonis not used by the runtime indexer path.
npm run dev# Sync all active repositories (default: backfill 30 days)
npm run index
# Sync specific active repo
npm run index -- --repo owner/name
# Verbose mode
npm run index -- --verbose
# Custom backfill window
npm run index -- --backfill-days 365
# Full history sync
npm run index -- --full-history
# Full-history metrics rebuild
npm run reindex:metrics| Flag | Type | Default | Description |
|---|---|---|---|
--repo, -r |
owner/name |
all active repos | Sync one repository (must already exist and be active in DB) |
--verbose, -v |
boolean | false |
Verbose logs |
--backfill-days |
integer | 30 |
Backfill window for incremental mode |
--full-history |
boolean | false |
Full history mode (replaces stored daily and commit stats for repo) |
The global date selector supports: 7, 30, 90, 180, 360, all.
Important behavior:
Impacttruly supports all listed ranges from fullimpactData.CompareandStoryserver loaders fetch360days and then filter client-side, soallis effectively bounded by the loaded dataset in those views.
Full API documentation (routes, request/response, error codes, examples):
docs/api.md
# Optional JSON snapshot export (not required by runtime pages)
npm run snapshot
# Build static output
npm run build
# Preview output
npm run previewNotes:
- Build output is generated in
build/. snapshotwritesstatic/snapshot.jsonfor offline/export workflows.- Settings page and mutating API routes are server-only (
prerender = false) and are not available on pure static hosting.
Generate screenshots for every marked section across all ranges:
node --import tsx scripts/capture-sections.tsGuide and CLI options:
docs/screenshots.md
.env (optional):
DATABASE_PATH=./data/gitiary.dbrepo: repository metadata and active/sync statedaily: daily aggregated commit counts and impact metricscommit_stats: commit-level metrics (sha, message, additions/deletions/files changed)metadata: internal key-value metadata (for examplelastGithubSync)
npm run check
npm run test
npm run test:coverage
npm run buildCurrent automated tests cover:
- Domain logic (
src/lib/domain/*.test.ts) - Selected DB behavior (
src/lib/server/db/queries.test.ts)
By default, API endpoints are unauthenticated.
- Do not expose this app directly to untrusted networks without access controls.
- Protect mutating routes (
/api/repos/sync,/api/repos/:id,/api/repos/:id/sync) behind reverse proxy auth, VPN, or private network.
Cause: no active repositories in DB.
Fix:
- Open
/settings. - Sync from GitHub.
- Mark repositories as active.
- Run
npm run indexagain.
Check GitHub CLI auth:
gh auth statusIf you see errors about url.searchParams during prerender:
- check components/routes that access query params in prerendered pages,
- or limit those routes from prerendering.
npm install -D playwright
npx playwright install chromiumThe repository also includes local helper scripts:
scripts/commit-stats.pyscripts/commit-stats-detailed.py
Notes:
- They are optional and not part of the main app runtime.
- They use
gh apiand target a hardcoded repository path in the script. - They require Python dependencies (for example
rich) in your local environment.
Run indexer every 6 hours:
sudo cp systemd/gitiary-indexer.service /etc/systemd/system/
sudo cp systemd/gitiary-indexer.timer /etc/systemd/system/
sudo systemctl enable --now gitiary-indexer.timer
systemctl status gitiary-indexer.timer
sudo journalctl -u gitiary-indexer -fIf needed, adjust WorkingDirectory in systemd/gitiary-indexer.service before enabling.
gitiary/
├── src/
│ ├── lib/
│ │ ├── server/
│ │ │ ├── db/ # Schema, connection, queries
│ │ │ ├── github/ # GitHub API client
│ │ │ └── indexer/ # CLI sync logic
│ │ ├── domain/ # Pure domain functions
│ │ └── components/ # Svelte components
│ └── routes/ # UI pages + API routes
├── scripts/ # Seed/snapshot/screenshots/helpers
├── drizzle/ # SQL migrations
├── docs/ # Project documentation
└── systemd/ # Service + timer units
CC0 1.0 Universal (Public Domain)