Skip to content

kevinlin/contrib-stack

Repository files navigation

ContribStack

ContribStack is a hosted developer-activity profile service. Each user gets a public page at contribstack.app/<handle> with an overlaid multi-source contribution heatmap — GitHub, GitLab, and custom ingest connections each render as their own colored layer. An embeddable widget.js web component lets you drop the same heatmap into any external site.

Architecture

pnpm monorepo with three packages:

Package Role
apps/web Next.js App Router — SSR profile pages, settings UI, API routes, Auth.js GitHub OAuth
packages/widget Framework-free <contrib-stack> web component (Vite lib build → widget.js)
packages/connectors Source-pull logic for GitHub and GitLab backfill/refresh

Production runs as a single Railway node with SQLite on a persistent volume (DATABASE_PATH). Litestream continuously replicates the database to Cloudflare R2 for backup and disaster recovery.

Local development

Prerequisites: Node 22+, pnpm 10+

git clone <repo-url> contrib-stack && cd contrib-stack
pnpm install
cp .env.example apps/web/.env.local   # fill in secrets
pnpm dev                              # http://localhost:3000

pnpm dev starts the Next.js dev server. The widget is built automatically when needed.

Environment variables

See .env.example for the full list. At minimum for local dev:

  • ENCRYPTION_KEY — 32-byte key, base64-encoded (openssl rand -base64 32)
  • AUTH_SECRET — random string (openssl rand -base64 32)
  • AUTH_GITHUB_ID / AUTH_GITHUB_SECRET — GitHub OAuth app credentials
  • DATABASE_PATH — optional; defaults to in-memory SQLite if unset

Testing

pnpm test                    # Vitest unit tests (all packages)
pnpm --filter web e2e        # Playwright E2E (starts dev server automatically)

Deploy to Railway

Production deployment is owned by GitHub Actions. The CI workflow runs lint, unit and integration tests, the migration test, the production build, and Playwright E2E tests. A successful main workflow then triggers Deploy production, which deploys that exact commit to Railway. Disable Railway's repository-triggered auto-deploy so changes cannot bypass these checks.

  1. Create a Railway project and service for this repo. Railway builds via the root Dockerfile and reads deployment settings from railway.json.
  2. Attach a volume mounted at /data.
  3. Set environment variables from .env.example in the Railway dashboard:
    • DATABASE_PATH=/data/contribstack.db
    • AUTH_URL to your production domain
    • ENCRYPTION_KEY, AUTH_SECRET, GitHub OAuth credentials
    • R2 credentials for Litestream backup (R2_ENDPOINT, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY)
  4. Create a GitHub environment named production with:
    • Secret RAILWAY_TOKEN: a token scoped to the Railway project.
    • Variable RAILWAY_SERVICE_ID: the target Railway service ID.
  5. Push to main. After CI passes, GitHub Actions deploys the revision. On startup, docker-entrypoint.sh restores the DB from R2 if missing, applies committed Drizzle migrations, and starts Next.js under Litestream replication.

Ingest API

Create an ingest connection in Settings to get an API key (shown once). Push daily counts with:

curl -X POST https://contribstack.app/api/ingest \
  -H "Authorization: Bearer csk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '[{"date":"2026-07-11","count":5}]'

The endpoint upserts counts per date for that connection. Payloads are capped at 5 000 rows and rate-limited per key.

About

Hosted developer-activity profiles with layered GitHub, GitLab, and custom contribution heatmaps, plus an embeddable web component.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors