Surplus logo
Surplus Docsby Sharing Excess

Contributing

This guide covers the mechanics of making a change to Surplus — getting set up, meeting the quality bar, and getting your work validated. If you're brand new, start with the Quickstart.

Before you start

Make sure you can run the stack and that a clean checkout passes:

bun install
bun run typecheck   # types across every package
bunx biome check .  # read-only lint + format (CI uses this)
bun run knip:ci     # unused files and dependencies

These should pass on production / staging before you begin, so you know any failures afterward are yours.

Make your change

Surplus rewards working with its structure rather than around it:

  • Follow the conventions. camelCase, no any, semantic UI tokens, stable element IDs, transactions for multi-step writes. These aren't style preferences — they're what keeps the codebase navigable and the tests reliable.
  • Adding or changing an endpoint? Touch the four layers in order — contract, service function, service class, route handler — as described in Request lifecycle. The contract change is what keeps the client and server in sync.
  • Changing the database? Edit the Drizzle schema in packages/postgres/src/schema/ (the source of truth) and apply it with the Drizzle push workflow. Don't hand-write ad-hoc SQL for routine schema changes.
  • Reuse types. Derive from @surplus/types with .pick(), .omit(), .partial(), and .extend() instead of redefining fields.

Validate locally

Before opening a pull request, run the full set of checks:

bun run typecheck
bun run lint        # Biome check + autofix (CI runs bunx biome check . read-only)
bun run knip:ci
bun run test        # Playwright end-to-end suite (ephemeral infra)

The end-to-end suite spins up a throwaway Neon branch and Upstash instance, so it's safe to run repeatedly. See Testing for how to add coverage for your change — new behavior should come with a test.

Opening a pull request

New pull requests are pre-filled from .github/pull_request_template.md. Fill in each section:

  • Problem — what you're fixing or building. Link related issues with Closes #123 or Part of #123 when applicable.
  • Solution — a plain-English summary of what you implemented. Reviewers can scan the diff for file-level detail.
  • Screenshots / Recordings — optional; include for UI changes or delete the section if not applicable.
  • Notes — follow-up work, known gaps, rollout or migration context, and how you validated locally (for example, bun run lint, bun run typecheck, bun run test).

A few habits that help reviewers:

  • Keep PRs small and focused — one logical change per pull request when you can.
  • Call out schema changes, cache invalidation, or deploy-sensitive behavior in Notes so nothing surprises production.
  • Use Screenshots / Recordings for client UI work — overlays and semantic tokens are easier to review with visuals.
  • Don't discuss security vulnerabilities in a public PR; use Vulnerability disclosure instead.

Continuous integration

Pull requests targeting production or staging automatically run quality (Biome, typecheck, Knip) and E2E (Playwright) in GitHub Actions. E2E injects configuration through the Railway CLI against the same kind of ephemeral infrastructure you use locally. Get CI green before requesting a merge. See Testing for details.

Commit messages

Keep commits focused and write messages in the imperative, describing the change and the why — for example, "Add multi-distribution batch allocate for hub inventory" or "Fix logger not visible in Apitally." Group related work into a single logical commit rather than many noisy ones.

A quick checklist

  • bun run typecheck passes
  • bunx biome check . is clean (or bun run lint after autofix)
  • bun run knip:ci passes
  • bun run test passes, and new behavior is covered
  • The change follows the conventions
  • New endpoints go through the contract and the four layers
  • Schema changes are made in Drizzle, not ad-hoc SQL

Security issues

Found a vulnerability? Please don't open a public issue. See Vulnerability disclosure for how to report it responsibly.