▍ humdrum codex / soft
5.3 KB raw

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

A local-only, single-user personal dashboard (weather, news, history, sports, calendar, todos, Mastodon/Bluesky, GitHub/Vercel, Obsidian) plus a printable daily newspaper PDF. Runs only at http://localhost:4317. See README.md for usage, BRIEF.md/PLAN.md for intent.

It descends from the 37 Apps kit (../_shared-app-kit/) but deliberately drops the cloud stack: no Clerk, Stripe, Vercel, or Neon. Don't "restore kit parity" by adding them back — local-only is the point.

Commands

pnpm dev          # dev server on :4317 (Turbopack)
pnpm build        # MUST be --webpack (set in script) — see gotchas
pnpm start        # run the production build on :4317
pnpm typecheck    # tsc --noEmit — run this to verify changes
pnpm db:push      # apply db/schema.ts to data/dashboard.db
pnpm db:seed      # idempotently add missing default sources
pnpm icons        # regenerate PWA icons from public/icons/source.svg

No test suite. Verify with pnpm typecheck + a manual run (or puppeteer screenshot against the dev server, which is how the UI was validated during the build).

Architecture (the parts that span files)

API-first, single data path. Every surface reads /api/*. Only lib/store.ts touches the DB (Drizzle over local SQLite, better-sqlite3). Route handlers wrap logic in withErrors() from lib/api.ts and call requireUser() from lib/auth.ts — a no-op single-user shim (returns "local"). If real auth is ever needed, that one file is the seam.

The source module pattern is the core abstraction. A "source" (weather, news, github…) is defined once in lib/sources/modules/<kind>.ts as a SourceModule: fetch(), a Zod configSchema + payloadSchema, and isConfigured(). Modules register in lib/sources/modules/index.ts. The flow:

To add a source: schema in lib/schemas/sources/<kind>.ts → module in lib/sources/modules/<kind>.ts → register in the barrel → add a branch in CardBodies.tsx → add to scripts/seed.ts and run pnpm db:seed.

macOS-native sources (Calendar.app, Things 3) run AppleScript through lib/mac.ts (runOsa + FS/RS-delimited output parsed by parseRows). The host process needs Automation permission (macOS prompts once). Calendar lists names via /api/integrations/calendars; Things completes a task via /api/integrations/things/complete. The "todos" kind is the Things Today source, rendered by components/cards/ThingsCard.tsx (special-cased in the Dashboard for its complete-checkbox). A vestigial local /api/todos + todos table remain for export compatibility but aren't shown.

Bento layout: each source stores explicit cols/rows grid spans (lib/layout.ts spanStyle); the dashboard is a dense grid-auto-flow with fixed gridAutoRows, and cards fill their tile and scroll internally. The dashboard's "Edit layout" mode (components/Dashboard.tsx) makes cards dnd-kit drag sources for reordering (renumbers position) and adds a bottom-right corner handle that resizes by whole grid cells (writes cols/rows); both persist via PATCH /api/sources/[id]. The old size enum column + TILE_SPANS are vestigial (kept for export/back-compat, no longer drive layout).

The newspaper. /print is a server component rendering current snapshots (lib/edition-data.ts) with print CSS in app/globals.css (.paper, @media print hides the nav). POST /api/edition (lib/pdf.ts) refreshes sources, then drives puppeteer to render /print to a PDF saved under editions/, recorded in the editions table and served by /api/editions/[id]/file.

Gotchas