tpmjs/CLAUDE.md
Ajax Davis ae0d5e37cf docs: rewrite CLAUDE.md — concise, focused on production debugging
Remove verbose case studies, sync system docs, and redundant examples.
Add Vercel/Railway/GitHub CLI debugging instructions and direct DB access guide.
2026-02-10 02:47:13 +10:00

5.7 KiB

Project Overview

Turborepo monorepo. pnpm workspaces. Next.js 16 App Router (apps/web). PostgreSQL via Prisma (packages/db). Deployed on Vercel. Database on Neon (via Railway for some services).

Architecture Rules

  1. Use @tpmjs/ui components — never raw HTML <button>, <input>, <table>, etc.
  2. No barrel exports — import directly: @tpmjs/ui/Button/Button, not @tpmjs/ui
  3. Module boundaries — apps import packages, never the reverse. UI has no deps on utils.
  4. Avoid count() in API routes — use take: limit + 1 technique for pagination (Prisma cold start is slow in serverless)
  5. All API routes need export const runtime = 'nodejs' and export const maxDuration = 60

Essential Commands

pnpm install                          # Install deps
pnpm dev --filter=@tpmjs/web          # Dev server
pnpm build                            # Build all
pnpm type-check                       # Type-check all
pnpm lint                             # Lint all
pnpm format                           # Biome format
pnpm --filter=@tpmjs/db db:generate   # Regenerate Prisma client (after schema changes)
pnpm --filter=@tpmjs/db db:push       # Push schema to DB (dev)
pnpm --filter=@tpmjs/db db:migrate    # Create migration (prod)
pnpm --filter=@tpmjs/db db:studio     # Prisma Studio GUI

Git Hooks (Lefthook)

Pre-commit runs: format, lint, type-check. Pre-push runs: test. If hooks pass locally, CI will pass too.

Vercel Build

Build command: cd ../.. && pnpm install && pnpm --filter=@tpmjs/web... build (the ... suffix builds all workspace dependencies first).

Debugging Production Issues

You have access to gh, vercel, and railway CLIs. Always use these first when debugging production problems rather than guessing at fixes.

Verify Deployment Status

# Check what commit is live in production
curl -s https://tpmjs.com/api/health | jq .

# Compare with local commit
git log --oneline -1

The health endpoint returns commitSha, commitMessage, and deploymentUrl.

GitHub Actions (CI)

gh run list --limit 10                        # Recent runs
gh run view <run-id> --log-failed             # See failure logs
gh run view <run-id> --job <job-id> --log     # Specific job logs
gh run rerun <run-id> --failed                # Rerun failed jobs
gh run watch                                  # Watch current run
gh pr checks <pr-number>                      # Check status on a PR

Vercel (Deployments)

vercel ls                                     # List deployments
vercel inspect <deployment-url>               # Build info + lambda list
vercel logs <deployment-url>                  # Runtime logs
vercel logs <deployment-url> --since 1h       # Last hour of logs
vercel env ls                                 # List env vars

Key things to check:

  • vercel inspect shows lambda functions (λ) — if you only see static pages (○), API routes didn't deploy
  • vercel logs shows runtime errors, timeouts, and cold start issues

Railway (Database / Services)

railway status                                # Current project/environment
railway logs                                  # Service logs
railway logs --deployment <id>                # Specific deployment logs
railway variables                             # List env vars
railway connect postgres                      # Connect to DB directly
railway up                                    # Deploy current directory

Debugging Workflow

  1. Identify the problem: Is it a build failure, runtime error, or timeout?
  2. Check CI first: gh run list then gh run view <id> --log-failed
  3. Check Vercel: vercel inspect <url> to verify lambdas deployed, vercel logs <url> for runtime errors
  4. Check database: railway logs or connect directly with railway connect postgres
  5. Verify the fix: Push, watch CI with gh run watch, then curl https://tpmjs.com/api/health

Direct Database Access

The production database is Neon PostgreSQL. Connection strings are in .env.local (DATABASE_URL for pooled, DATABASE_URL_UNPOOLED for direct).

Prisma Studio (GUI for browsing/editing data):

# Reads connection from packages/db/.env or DATABASE_URL env var
pnpm --filter=@tpmjs/db db:studio

psql (raw SQL queries):

# Connect using the unpooled URL for direct access
psql "$DATABASE_URL_UNPOOLED"

# Common queries
SELECT count(*) FROM tools;
SELECT id, name, slug, quality_score, view_count FROM tools ORDER BY view_count DESC LIMIT 20;
SELECT * FROM stats_snapshots ORDER BY date DESC LIMIT 5;
SELECT * FROM sync_logs ORDER BY created_at DESC LIMIT 10;
SELECT * FROM page_views ORDER BY date DESC LIMIT 20;

One-off Prisma scripts (when you need Prisma's type safety):

# Run a .ts script against prod DB using tsx
cd packages/db && npx tsx scripts/my-script.ts

Note: Prisma reads .env from packages/db/, not the root. If db:studio can't connect, ensure DATABASE_URL is set there or exported in your shell.

Manual Cron Triggers

curl -X POST https://tpmjs.com/api/sync/changes -H "Authorization: Bearer $CRON_SECRET"
curl -X POST https://tpmjs.com/api/sync/keyword -H "Authorization: Bearer $CRON_SECRET"
curl -X POST https://tpmjs.com/api/sync/metrics -H "Authorization: Bearer $CRON_SECRET"
curl -X POST https://tpmjs.com/api/sync/view-rollup -H "Authorization: Bearer $CRON_SECRET"
curl -X POST https://tpmjs.com/api/sync/stats-snapshot -H "Authorization: Bearer $CRON_SECRET"

Publishing Packages

pnpm changeset              # Create changeset
pnpm changeset:version      # Version packages
pnpm changeset:publish      # Publish to npm
git push --follow-tags       # Push with tags