Contributing
How we develop Alchemify — conventions for anyone contributing code (human or AI).
Versioning
Section titled “Versioning”Milestones use plain numbers: 0.1, 0.2, 0.3. No “v” prefix, no patch number. Semver formality comes later when there’s something to ship.
GitHub milestones track which issues belong to which release. Current state:
- 0.1 — Core backend (auth, SQL proxy, schema introspection) + frontend app shell
- 0.2 — Docker, architecture hardening, runtime security
- 0.3 — Reserved for future work
Testing
Section titled “Testing”- Framework: Vitest + Supertest
- Database: Tests run against the real
alchemifydatabase, not mocks - Isolation: Tables are truncated between test runs (
beforeEach) - Pattern: Test helpers in
test/setup.tshandle seeding (orgs, users, magic links) - Run:
pnpm testfrom repo root
Write tests for new endpoints and SQL functions. Follow the existing pattern in test/auth.test.ts.
E2E tests
Section titled “E2E tests”End-to-end tests use Playwright and live in the root e2e/ directory. They exercise the full stack (frontend + server + database).
pnpm test:e2e # run all E2E tests (headless)pnpm test:e2e:ui # open Playwright's visual test runnerThe webServer config in e2e/playwright.config.ts starts both the backend and frontend dev servers automatically. If servers are already running, they’ll be reused.
Tests use unique emails (*@test.local) to avoid collisions with manual data. A global teardown deletes all @test.local users after each run.
Journey tests
Section titled “Journey tests”Journey tests exercise the full builder flow end-to-end: login → create table via AI → add CRUD data → generate custom page → verify it renders. They’re separate from the regular E2E suite because they hit the real OpenAI API and are slower.
pnpm test:journey # requires all 3 servers already runningUnlike test:e2e, the journey config does not start servers automatically — you must have pnpm dev, pnpm dev:web, and pnpm dev:chat running first. The test includes a preflight check that gives a clear error if any service is unreachable.
Journey tests live in e2e/journeys/ and have their own Playwright config (playwright.journey.config.ts), teardown, and screenshot directory. They are not included in pnpm test:e2e.
Page diagnostics
Section titled “Page diagnostics”The diagnose tool launches a headless browser, logs in as a test user, navigates to a page, and reports console errors — useful for debugging AI-generated custom pages without opening DevTools manually.
pnpm diagnose /our-employees # admin role (default)pnpm diagnose /dashboard --role staff # specific rolepnpm diagnose / --role member # root page as memberRequires the backend (pnpm dev) and frontend (pnpm dev:web) servers running, plus the test seed applied (psql alchemify dba -f apps/server/test-seed.sql). Screenshots are saved to tools/diagnose/screenshots/ (gitignored). Exit code 0 = no errors, 1 = errors found.
Console messages are categorized (compilation, render, execution) and sandbox infrastructure noise (CSP, Vite HMR, WebSocket) is filtered automatically.
AI exploratory testing
Section titled “AI exploratory testing”The explorer uses Claude Code + Playwright MCP for open-ended exploratory testing of the builder pipeline. Unlike scripted tests, it evaluates non-deterministic AI output, explores freely, and finds issues that deterministic tests can’t.
e2e/explorer/run.sh prompt.md # interactive (env=local)e2e/explorer/run.sh poc.md --env staging -p # staging, print modee2e/explorer/cron.sh # batch run all testse2e/explorer/cron.sh --env staging # batch run against stagingThe --env flag selects the target environment (local or staging). Config is in e2e/explorer/config.ts. Staging requires EXPLORER_EMAIL and EXPLORER_TOKEN env vars.
Requires all 3 dev servers running (for local) plus the test seed applied. The prompt instructs the AI tester to log in, create tables and data, request custom pages, verify rendering, and check console errors. Batch results go to e2e/explorer/results/ (gitignored).
See e2e/explorer/README.md for full setup and cleanup instructions.
Chat API harness
Section titled “Chat API harness”The chat harness uses Claude Code + curl to test the AI builder’s chat API directly — no browser involved. It sends messages, parses SSE streams, observes tool calls, and analyzes the AI’s behavior. Useful for iterating on prompt/tool behavior without the overhead of a headless browser.
apps/chat/test/harness/run.sh smoke.md # interactiveapps/chat/test/harness/run.sh smoke.md -p # print mode (JSON)apps/chat/test/harness/run.sh build-app.md --timeout 30m -p # full build with timeoutapps/chat/test/harness/run.sh smoke.md --schema myapp # with app schemaapps/chat/test/harness/run.sh smoke.md --tenant acme # multi-tenant modeRequires the backend (pnpm dev) and chat (pnpm dev:chat) servers running. Config is in apps/chat/cli/config.ts. Prompt files describe test scenarios; the system prompt teaches Claude how to authenticate, call each endpoint, parse SSE events, and report findings. Reports are saved to apps/chat/test/harness/output/ (gitignored).
Documentation
Section titled “Documentation”The docs site lives at apps/docs/ (Starlight/Astro). Two sections:
- User Guide — Non-technical. How to use the app. Written for people who don’t code.
- Developer Guide — Technical. Architecture, setup, API, extension points.
Convention: When making user-visible changes, update the relevant docs. User-facing features go in the User Guide. Technical changes go in the Developer Guide.
pnpm dev:docs --host # dev server (port 4321)pnpm build:docs # static buildSchema management
Section titled “Schema management”The base schema lives in apps/server/schema.sql (includes numbered files from schema/). Migrations live in apps/server/migrations/ using dbmate format.
Fresh installs use the base schema (schema.sql) — it’s idempotent and produces a complete database.
Existing databases are upgraded via migrations. This repo defines the migration files; the admin repo runs them against HQ and tenant databases.
Dual maintenance: every migration must also update the corresponding base schema file, so reset-dev.sh and migrations produce the same result.
# Dev: full reset from base schema (no migrations needed)./scripts/reset-dev.sh
# Base schema conventions# - IF NOT EXISTS for roles and tables# - CREATE OR REPLACE for functions# - Re-apply: psql -U dba -d alchemify -f apps/server/schema.sqlSee apps/server/migrations/CONVENTIONS.md for migration format, naming, and rules around breaking changes.
Workflow
Section titled “Workflow”- Discuss the change
- Create a GitHub issue (requirements, not implementation details)
- Implement on the
backendbranch - Write or update tests
- Run
pnpm lintandpnpm formatbefore committing - Update docs if user-visible
- Commit with a clear message
Issues created from the backend branch should include the backend label.
Linting & formatting
Section titled “Linting & formatting”The project uses ESLint (with type-checked rules) and Prettier for consistent code quality. Both are configured at the repo root and apply to all workspaces.
pnpm lint # ESLint — check for errorspnpm format # Prettier — auto-format all filespnpm format:check # Prettier — check without writingKey rules enforced:
- No floating promises —
awaitorvoidevery promise - No unused variables — prefix with
_if intentionally unused - Consistent type imports —
import { type Foo }style - Double quotes, semicolons, trailing commas — handled by Prettier (100-char line width)
The ops/check.sh script runs lint and format checks alongside typecheck and tests.
Code style
Section titled “Code style”- Simple over clever — direct solutions, no over-engineering
- No extras — don’t add error handling, comments, types, or refactoring beyond what’s needed
- Delete, don’t deprecate — remove unused code completely, no backwards-compat shims
- Security first — watch for injection, XSS, and OWASP top 10; flag immediately