Skip to content

sotomaque/eng-hub

Repository files navigation

Eng Hub

An internal tool for engineering managers. Replaces the Figma boards, spreadsheets, personal docs, and manual GitHub spelunking with a single dashboard for project health, team composition, goal tracking, 1:1s, and delivery stats.


Why

Engineering management tooling is fragmented. Project health lives in static Figma boards with no history. 1:1 notes are scattered across personal tools with no continuity when reports change managers. Goals are tracked inconsistently. Team composition is invisible beyond org charts. Delivery data requires manually checking GitHub.

Eng Hub puts it all in one place.


Features

Area What it does
Project Home Pages Per-project hub with description, team roster, health status, milestones, goals, and links to Figma, repos, docs
Health Tracking 8-dimension assessments (Growth, Margin, Longevity, Client Sat, Eng/Product/Design Vibe) with notes, full history, and at-a-glance status
1:1 Meeting Notes Rich text notes by direct report, reusable templates, management chain visibility, and handoff when reports change managers
Goal Management Hierarchical milestones and quarterly goals with key results, assignees, status, and target dates
Budget & Billets Per-project budget tracking and contracted headcount (billets) with department, title, seniority level, and count
Team Arrangements Drag-and-drop team editor, seniority composition bars, draft arrangements before committing, org chart per project
Delivery Insights GitHub stats (commits, PRs, reviews, trends) with visual dashboards and resilient sync with exponential backoff
Contributor Comparison Side-by-side comparison of selected contributors — commits, PRs merged, monthly trends, and AI-generated narrative summaries (via Anthropic Claude)
Performance Reviews Per-person review packets with 4 scored dimensions (Core Competency, Teamwork, Innovation, Time Management), optional comments, PDF upload, trend chart, and computed averages
Skill Matrices Per-person skill tags (e.g. React, Python, Machine Learning) with a shared global skill library and autocomplete — add skills in the edit sheet, displayed on each person's profile
People Directory Searchable directory with profiles, manager hierarchies, department/title taxonomy, and manager change audit trail

Tech stack

Layer Technology
Runtime Bun
Framework Next.js 16 (App Router), React 19
API tRPC 11 with Zod validation
Database PostgreSQL via Supabase + Prisma
Auth Clerk with management chain-based visibility
UI Tailwind CSS 4 + shadcn/ui
AI Vercel AI SDK + Anthropic Claude (optional — contributor comparison summaries)
Quality Biome · Knip · Lefthook · Playwright E2E · Changesets

Project structure

apps/web        → Next.js frontend
packages/api    → tRPC routers and GitHub integration
packages/db     → Prisma schema & client
packages/ui     → Shared UI components (shadcn/ui)

Getting started

bun install
cp apps/web/.env.example apps/web/.env.local   # fill in your keys
bun dev                                        # start dev server

See Environment file layout for detailed configuration.


Development workflows

Running local dev

  1. Copy the example env and fill in your keys:
    cp apps/web/.env.example apps/web/.env.local
  2. Add your database URLs to apps/web/.env.local (pooled + direct) and packages/db/.env (same two URLs).
  3. Generate the Prisma client and start the dev server:
    cd packages/db && bun run db:generate
    bun dev

The app runs at http://localhost:3000 with Turbopack HMR.

Running against local Supabase

For fully offline development with seeded test data:

  1. Start the local Supabase stack (PostgreSQL, Auth, Storage, etc.):
    bunx supabase start
  2. Switch your environment to local:
    cd apps/web && bun run env:local
  3. Push the Prisma schema to the local database:
    cd packages/db && bun run db:push
  4. (Optional) Reset the local database to re-apply migrations and seed data:
    cd packages/db && bun run db:reset
  5. Start the dev server:
    bun dev

The local Supabase database runs on localhost:54322 with seed data from supabase/seed.sql. Auth still goes through Clerk cloud, so you need valid Clerk dev keys in apps/web/.env.local.local.

Note: SKIP_ENV_VALIDATION=1 is set in the local env file so the app starts even without optional services (UploadThing, QStash, GitHub).

Pointing at a deployed preview branch

When you open a PR, Supabase automatically creates an isolated preview database from supabase/migrations/ and applies supabase/seed.sql. Vercel deploys a preview of the app with the Supabase-provided env vars injected automatically.

To point your local dev server at a preview branch database:

  1. Go to Supabase dashboard → your project → the preview branch → Settings → Database → Connection string
  2. Copy the pooled (port 6543) and direct (port 5432) connection strings
  3. Paste them into apps/web/.env.local.preview and packages/db/.env.preview
  4. Switch your local environment:
    cd apps/web && bun run env:preview
  5. Start the dev server:
    bun dev

The preview database has seed data (projects, people, teams) so you can develop and run E2E tests locally against real data.

Running locally against production

To switch back to the production database:

cd apps/web && bun run env:prod

This copies apps/web/.env.local.prod.env.local and packages/db/.env.prodpackages/db/.env.

Tip: The toggle scripts update both the web app env and the Prisma CLI env, so prisma db push and prisma studio will also point at the correct database.

Environment file layout

apps/web/
  .env                ← shared keys (Clerk, GitHub, etc.) — gitignored
  .env.local          ← DB URLs for current session — gitignored, swapped by toggle scripts
  .env.local.local    ← local Supabase DB URLs — committed
  .env.local.prod     ← production DB URLs — gitignored
  .env.local.preview  ← preview branch DB URLs — gitignored
  .env.example        ← template with all required keys — committed

packages/db/
  .env                ← DB URLs for Prisma CLI — gitignored, swapped by toggle scripts
  .env.local-template ← local Supabase DB URLs — committed
  .env.prod           ← production DB URLs — gitignored
  .env.preview        ← preview branch DB URLs — gitignored

Database (Supabase)

The project uses Supabase for PostgreSQL with Prisma as the ORM. Schema changes go through Supabase migrations (not prisma migrate), and Prisma is used only for client generation.

First-time setup

bunx supabase login                              # authenticate with Supabase
bunx supabase link --project-ref <PROJECT_REF>   # link to your Supabase project
bunx supabase db pull                            # pull baseline migration from production

Making schema changes

  1. Edit packages/db/prisma/schema.prisma
  2. Apply to local/dev DB: cd packages/db && bunx prisma db push
  3. Generate migration: cd packages/db && bun run db:migrate:new <descriptive_name>
  4. Verify: bunx supabase db reset (replays all migrations + seed)
  5. Generate Prisma client: cd packages/db && bun run db:generate
  6. Commit both schema.prisma and the new supabase/migrations/<timestamp>_<name>.sql

Key commands

Command Description
cd packages/db && bun run db:generate Regenerate Prisma client
cd packages/db && bun run db:migrate:new <name> Generate a new migration from schema diff
cd packages/db && bun run db:reset Drop & recreate DB from migrations + seed
cd packages/db && bun run db:studio Open Prisma Studio
bunx supabase db pull Pull remote schema as a migration
bunx supabase db push Push local migrations to remote

Preview environments & deployment pipeline

The project uses Supabase Branching + Vercel Previews for a fully automated PR-to-production pipeline. No manual database steps are needed.

When a PR is opened:

  1. Supabase creates an isolated preview database, runs all migrations from supabase/migrations/, then applies supabase/seed.sql
  2. Vercel deploys a preview of the app with the Supabase-provided preview DB env vars injected automatically
  3. CI runs lint, typecheck, and unit tests; then E2E tests run against the Vercel preview URL

When a PR is merged to main:

  1. Supabase deletes the preview branch database
  2. Supabase applies any new migration files to the production database automatically
  3. Vercel deploys to production (with production DB env vars)

⚠️ Important: Production migrations come from the .sql files in supabase/migrations/, not from Prisma's db push. The db push command does a direct schema diff and is only safe for local development — never use it against production. Always generate a migration file (bun run db:migrate:new) and commit it with your PR.

PRs with no migration files (e.g. test-only or frontend-only changes) skip the database step entirely — the production DB is unchanged.


Testing

Unit tests

Unit tests use bun:test and live in __tests__/ directories alongside the code they test.

cd apps/web && bun run test              # run all unit tests
cd apps/web && bun run test:watch        # watch mode
cd packages/api && bun test             # run API package tests directly

E2E tests

E2E tests use Playwright with Clerk Testing Tokens for authentication bypass. Tests run against seed data in supabase/seed.sql.

Note: Goals CRUD and manager-edit tests require E2E_CLERK_USER_ID to be set (the Clerk user ID of the E2E test account). This links person-alice in the seed to the test user, enabling /me/goals and manager permission tests. Without it, those tests are skipped. Set it in .env, as a GitHub Actions secret, and as a Vercel Preview environment variable.

Running locally against a preview branch (recommended):

  1. Switch to the preview database: cd apps/web && bun run env:preview
  2. Start the dev server: bun dev
  3. In a separate terminal, run the tests:
    cd apps/web && bun run test:e2e

Other modes:

cd apps/web && bun run test:e2e          # headless (starts dev server if needed)
cd apps/web && bun run test:e2e:ui       # Playwright UI mode
cd apps/web && bun run test:e2e:headed   # headed browser
cd apps/web && bun run test:e2e:debug    # step-through debugger

Running against a deployed preview URL:

PLAYWRIGHT_TEST_BASE_URL=https://your-preview.vercel.app \
  cd apps/web && bun run test:e2e

Tests live in apps/web/e2e/ and import { test, expect } from ./helpers (which injects Clerk testing tokens).

In CI, the E2E job waits for the Vercel preview deployment, then runs tests against it.


Code quality

Linting & formatting

Biome handles both linting and formatting across the entire monorepo.

bun run biome:check          # check for lint + format issues
bun run biome:fix            # auto-fix all issues
bun run format               # format only
bun run --filter web lint    # lint web app via turbo
bun run --filter web lint:fix

Dead code detection

Knip detects unused exports, files, and dependencies.

bun run knip

Git hooks (Lefthook)

Lefthook manages git hooks. Hooks are installed automatically on bun install via the prepare script.

Hook What runs
pre-commit Biome check + auto-fix on staged files only
pre-push TypeScript typecheck, unit tests, and Knip (in parallel)

To reinstall hooks manually:

bunx lefthook install

Scripts reference

bun run dev                        # start all workspaces
bun run --filter web dev           # start web app only
Command Description
bun run --filter web lint Lint with Biome
bun run --filter web lint:fix Lint + auto-fix
bun run --filter web typecheck TypeScript type-check
bun run --filter web test Run unit tests
bun run --filter web test:e2e Run E2E tests
bun run --filter web ci Lint + typecheck + test
bun run knip Check for dead code and unused dependencies
bun run format Format all files with Biome
cd apps/web && bun run env:local Switch local env to local Supabase
cd apps/web && bun run env:prod Switch local env to production DB
cd apps/web && bun run env:preview Switch local env to preview branch DB
cd packages/api && bun run sync-git-stats <projectId> <repoPath> Sync contributor stats from a local git clone
bun changeset Create a changeset for the current PR
bun changeset:version Apply changesets and bump versions

Syncing stats from local git repos

For projects hosted on GitLab or other providers where the API isn't accessible, you can sync contributor stats from a local clone of the repository.

Usage

cd packages/api
bun run sync-git-stats <projectId> <repoPath>

Example (jeric2o):

cd packages/api
bun run sync-git-stats cmlsmp63g0000itbru5wvt294 ~/Desktop/hypergiant/jeric2o development

How it works

  1. Runs git log --numstat on the local repo to extract per-commit author email, date, additions, and deletions
  2. Queries the database for team members on the project and builds an email-to-username mapping
  3. Matches commit authors by email to team members (unmatched commits are logged and skipped)
  4. Aggregates into all-time and year-to-date stats with weekly trend data
  5. Writes results to contributor_stats (full replace) and updates the sync timestamp

Prerequisites

  • The repo must be cloned locally and the path passed as the second argument
  • Team members must exist on the project in the app
  • Each team member's Person email must match their git commit email, or they need a gitlabUsername set
  • Run while pointing at the correct database (local, preview, or prod via bun run env:prod)

Debugging author matching

The script prints a detailed mapping table and lists unmatched commit emails with their commit counts. If contributors are missing from the output, update the Person's email in the app to match their git config email.


Contributor comparison

The Stats page lets you select 2+ contributors and open a side-by-side comparison sheet showing commits, lines changed, PRs merged, monthly trends, and recent MRs.

How data is sourced

Project type Data source Works in production?
GitHub URL configured GitHub REST + GraphQL APIs (same data as stats dashboards) Yes
GitLab / local repo only git log against a local clone (via repoPath) No — dev/local only

GitHub-backed projects use the same GITHUB_TOKEN already configured for stats sync. No additional setup is needed.

AI-generated summaries

When ANTHROPIC_API_KEY is set, the comparison sheet shows a "Generate Summary" button that streams a narrative analysis of the comparison data using Claude. The summary covers individual profiles, monthly trajectory, work style comparison, and key takeaways.

A "Custom Prompt" option lets you add instructions (e.g., "Focus on who improved the most over the last 3 months").

Env var Required? Description
ANTHROPIC_API_KEY Optional Enables AI summary generation. Get one at console.anthropic.com.

If the key is not set, the AI summary section is hidden — all other comparison features work without it.

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages