Files
zpan/CONTRIBUTING.md
Jasper Van b92df828ab ci: parallelize and isolate test suites (#556)
* ci: parallelize and isolate test suites

* ci: avoid unavailable Playwright video runtime

* ci: shard coverage and cache docker smoke

* ci: balance Playwright shards by test

* ci: smoke test the CLI container

* ci: enforce merged coverage thresholds

* ci: ratchet canonical coverage baseline

* ci: make coverage ratchet lossless

* ci: organize parallel gates by responsibility

* perf(ci): reduce total runner time

* perf(ci): balance runner cost and latency

* perf(ci): suppress passing test logs

* fix(test): make coverage sorting proof deterministic

* perf(docker): exclude test-only build inputs

* perf(ci): scope Docker smokes to packaging changes

* refactor(test): enforce fast test boundaries

* test: isolate coverage ownership

* perf(test): run backend projects concurrently

* perf(ci): separate test layers by runtime

* perf(test): separate integration boundaries

* perf(ci): prioritize test runners

* docs(ci): clarify package scheduling

* test: restore shared Cloudflare mocks

* fix(preview): isolate Cloudflare E2E build config

* fix(auth): bind preview sessions to request origin

* revert: remove ineffective preview auth workaround

* fix(auth): stop signing JWTs on session reads
2026-08-05 15:01:12 -04:00

201 lines
8.0 KiB
Markdown

# Contributing
By participating in this project, you agree to abide by our [Code of Conduct](CODEOFCONDUCT.md).
## Setup
Prerequisites: Node.js 24+ (managed by [Volta](https://volta.sh/))
```sh
git clone git@github.com:saltbo/zpan.git
cd zpan
pnpm install
```
## Development
```sh
pnpm dev # CF Workers mode with HMR (default, uses staging D1)
pnpm dev:node # Node.js mode with HMR (SQLite, reads .dev.vars)
```
## Quality Gates
Every commit and PR must pass these checks. Husky enforces them on pre-commit.
```sh
pnpm lint # Biome — lint + format check
pnpm typecheck # TypeScript strict mode
pnpm test # Unit + integration tests (Node runtime, 90% coverage gate)
pnpm test:cf # Integration tests (Cloudflare Workers runtime)
pnpm e2e # Playwright E2E tests
```
### Test boundaries
- Backend unit tests use `*.test.ts`, run in Node, and must not create a database-backed application.
- Frontend unit and component tests use `*.test.ts(x)` and run in jsdom.
- Backend repository, HTTP, and application integration tests use `*.integration.test.ts`; CI runs HTTP/application and datastore/adapter boundaries independently.
- `*.cf-test.ts` is reserved for behavior that specifically needs D1, Workers bindings, or the Workers runtime.
- Pull requests run only `@critical` browser journeys against the local Cloudflare runtime. The complete multi-viewport browser suite runs nightly.
- Tests must replace S3 and ZPan Cloud with local fakes; CI must not depend on staging services or credentials.
## Adding a Feature
1. **Write code** in the relevant directory (`server/`, `src/`, `shared/`)
2. **Write tests** — co-locate with source as `*.test.ts` (Node) or `*.cf-test.ts` (CF Workers)
3. **Run checks**`pnpm lint && pnpm typecheck && pnpm test && pnpm test:cf`
4. **Coverage** — new code must maintain 90%+ line coverage on `server/`
5. **Commit** — use [Conventional Commits](https://www.conventionalcommits.org) (`feat:`, `fix:`, `docs:`, etc.)
6. **PR** — target the `main` branch
7. **Preview verification** — every PR must be verified in the preview environment (see below)
## Preview Verification
Every PR that touches UI or API behavior **must** be verified in the Cloudflare Workers preview environment before merging. The verification report **must** be posted as a PR comment — a PR without a verification comment cannot be merged.
Cloudflare Workers automatically deploys each PR to a preview URL (posted as a PR comment).
Before merging, the reviewer **must** verify in the preview environment and post a PR comment with:
- **Screenshots** proving the feature works (golden path + edge cases)
- **What was tested** (e.g. "Switched theme to dark, changed language to Chinese, verified password mismatch error")
- **Verdict** — approve or request changes
A code-review-only approval (reading the diff without visiting the preview) is **not sufficient** to merge.
### Preview environment details
- All PRs share one staging D1 database (`zpan-db-staging`) — data persists across deployments
- A dev storage backend is pre-configured, so file upload works out of the box
- If you need a clean state, coordinate with maintainers
### Staging test accounts
A shared test account is available on the staging database for preview verification:
| Field | Value |
|-------|-------|
| Email | `reviewer@zpan.dev` |
| Password | `zpan-staging-reviewer-2026` |
Use this account for UI regression testing in preview deployments. **Do not change the password** — other contributors depend on it.
For admin feature testing, use the dedicated non-production preview admin account:
| Field | Value |
|-------|-------|
| Email | `admin@zpan.space` |
| Password | Private maintainer `DEV_ADMIN_PASSWORD` value |
Use this account only in the staging/preview environment. **Do not commit, post, or use the password for production.**
If the staging admin account is missing, demoted, or the password stops working, a maintainer can repair it without touching production:
```sh
pnpm seed:preview-admin
```
The command reads `DEV_ADMIN_PASSWORD` from the shell environment or the gitignored local `.dev.vars` file, then targets
`zpan-db-staging` with `--env staging --remote` and upserts only `admin@zpan.space`.
To rotate the shared preview password intentionally, run the same command with the new non-production
`DEV_ADMIN_PASSWORD` value and update the private maintainer credential source in the same change.
## Database Migrations
Schema is defined in `server/db/schema.ts` and `server/db/auth-schema.ts`.
```sh
pnpm db:generate # Generate migration SQL after schema changes
pnpm db:migrate # Apply migrations (Node/SQLite)
pnpm db:migrate:d1 # Apply migrations (D1 local)
wrangler d1 migrations apply zpan-db --remote # Apply migrations (D1 production)
```
To reset local databases with seed data (admin user + dev storage):
```sh
pnpm db:reset # Reset Node database (zpan.db)
pnpm db:reset:d1 # Reset D1 local database (.wrangler)
```
Migration files live in `migrations/` at project root. Always commit them.
### Storage usage backfill
After applying the migration that creates `storage_usage_breakdowns`, run the storage usage backfill once. The command is a dry run unless `--apply` is present.
```sh
pnpm storage:backfill -- --d1 zpan-db --remote
pnpm storage:backfill -- --d1 zpan-db --remote --apply
pnpm storage:backfill -- --sqlite zpan.db
pnpm storage:backfill -- --sqlite zpan.db --apply
```
The backfill recalculates all eight storage categories from `matters` and `image_hostings`. It is an operator command, not part of the application runtime or deployment lifecycle.
### Storage enabled/status backfill
After applying migrations 0066 through 0069, convert legacy storage status values into
the `enabled` flag and the `unknown`/`healthy`/`unhealthy` health model:
```sh
pnpm storage-status:backfill -- --d1 zpan-db --remote
pnpm storage-status:backfill -- --d1 zpan-db --remote --apply
pnpm storage-status:backfill -- --sqlite zpan.db
pnpm storage-status:backfill -- --sqlite zpan.db --apply
```
Run this once before deploying the application version that reads health status.
### Turso (libSQL) migrate path
When deploying the Node/Docker image against a Turso (libSQL) database, set `TURSO_DATABASE_URL` (and `TURSO_AUTH_TOKEN` for remote URLs) before running `db:migrate`. `drizzle.config.ts` detects the env var and switches to the `turso` dialect automatically:
```sh
TURSO_DATABASE_URL=libsql://your-db.turso.io \
TURSO_AUTH_TOKEN=your-token \
pnpm db:migrate
```
For local libSQL files the token can be omitted:
```sh
TURSO_DATABASE_URL=file:./zpan.db pnpm db:migrate
```
Migrations run automatically at Docker container startup when `TURSO_DATABASE_URL` is set. See [docs/deploy/docker.md](docs/deploy/docker.md) for the full Docker + Turso setup.
## Deployment
Primary target is Cloudflare Workers. Node.js (Docker) is the backup runtime.
```sh
pnpm build # Build frontend to dist/
pnpm deploy # Build + deploy to Cloudflare Workers
```
## Project Structure
```
zpan/
├── server/ # Hono API (routes, middleware, auth, platform abstraction)
├── src/ # React frontend (TanStack Router, shadcn/ui)
├── shared/ # Shared types, Zod schemas, constants
├── workers/ # Cloudflare Workers entry
├── migrations/ # D1/SQLite migrations (drizzle-kit generated, wrangler managed)
├── wrangler.toml # Cloudflare Workers config
└── biome.json # Lint + format config
```
## Financial Contributions
We welcome financial contributions on our [Open Collective](https://opencollective.com/zpan).
## Contributors
Thank you to all the people who have already contributed to ZPan!
<a href="https://github.com/saltbo/zpan/graphs/contributors"><img src="https://opencollective.com/zpan/contributors.svg?width=890" /></a>