Skip to content

Local development

Use this guide to start a development environment and run checks before changing Calends source code.

  1. Install Node.js 22, clone the repository and run the setup commands below.
  2. Open the local app; follow the instructions for .dev.vars if you need to bypass sign-in.
  3. Run checks relevant to your changes, then review the full checklist before submitting.

You’ll need Node.js 22.

终端窗口
git clone https://github.com/imetn/calends && cd calends
npm ci
npm run db:migrate:local
npm run dev

To bypass sign-in during development, add DEV_BYPASS_AUTH=1 to .dev.vars, preserving existing contents.

npm run dev starts two processes: Vite (front end with hot reload, :5173) and wrangler (the Worker and a local D1, :8787). Open http://127.0.0.1:5173/admin.

The local database is kept in .wrangler/state at the repository root.

Command What it does
npm test Unit tests (billing, phases, metrics, shared plans, categories and more)
npm run typecheck TypeScript type check
npm run lint oxlint
npm run format / npm run format:check Prettier format / check
npm run i18n:check Checks every language has every string
npm run build Production build
npm run email:preview Renders every reminder email with sample data into .preview/email/ as HTML; sends nothing
npm run demo Generates the demo ledger of the made-up user Alex and writes it to the local database
src/ app and public page
shared/ billing, phases, metrics, FX, masking, i18n — shared by browser and Worker
worker/ API, auth (password + passkeys), MCP, reminders and channels, backup, ICS
migrations/ D1 / SQLite schema
docker/ self-hosting image entrypoint

Stack: React 19 with the React Compiler and Vite for the app, with react-aria-components for dialogs, menus and controls; shadcn/ui for the public page; Cloudflare Workers + D1 on the server.

终端窗口
npm run typecheck && npm run lint && npm run format:check && npm run i18n:check && npm test && npm run build

A few ground rules (see CONTRIBUTING.md in the repository):

  • Domain logic lives in shared/ and must run in both the browser and the Worker — no DOM or Node APIs. Add unit tests in shared/*.test.ts for billing, phase or metric changes.
  • Every user-visible string goes through t(), and never at module top level. Add new strings to en and zh-CN at least.
  • Keep stored data compatible. Old records must keep working; schema changes go in a new file under migrations/; new data must round-trip through backups.
  • Privacy: anything that could identify a person or account stays off the public page; shared/mask.ts allow-lists what’s shared.
  • Keep the UI consistent with existing components and check phone width (390px), desktop, light and dark.