# Development Requirements: Rust 1.97 (Cot itself requires 1.94), PostgreSQL 17+, and a browser. Node is only needed for browser automation or upgrading vendored browser assets; serving the application has no Node build step. Use `.env.example` as the list of supported settings. Environment files are not loaded automatically. Start a dedicated PostgreSQL database, set `DATABASE_URL`, then run `cargo run`. Database migrations run before the server accepts requests. For an isolated Windows development database, use `scripts/dev.ps1`. It uses installed PostgreSQL binaries, creates data under ignored `target/`, binds the database and app to loopback, enables registration, and explicitly seeds demonstration accounts. `scripts/stop-dev.ps1` stops only the processes started for this workspace. Required checks: ```text cargo fmt --check cargo clippy --all-targets -- -D warnings cargo test ``` PostgreSQL integration tests require `MEGURI_TEST_DATABASE_URL` pointing at a disposable database, with CREATEDB for the isolated demo-lifecycle tests. Run `cargo test --test integration -- --ignored --test-threads=1`. Most tests create isolated workspaces/users; lifecycle tests create and remove uniquely named databases to test protection, reset, retention, and reseeding. Never use a production database. CI uses an explicit Debian Node job container and the PostgreSQL service hostname `postgres`, for both Gitea Actions and GitHub Actions. Loopback inside the job does not reach the database service. No host database port is published. A bounded authenticated `psql SELECT 1` check runs before compilation; database networking/authentication failures stop the job rather than producing a pool timeout in every integration test. The application and browser tests still share job-container loopback. Browser checks: sign in; inspect the calendar; create a request as one user and approve it as another; verify the publication status separately; verify that a user outside the workspace cannot read it. Use both desktop and narrow viewports. A test failure is not a reason to relax an authorization or scheduling invariant. ## Operational limitations For automated browser checks, run `npm ci`, `npx playwright install chromium`, then `npm run test:browser` against a seeded local app with signup enabled. By default the tests use installed Chrome; set `MEGURI_BROWSER_CHANNEL=chromium` for downloaded Chromium. The original suite creates its own workspace. `tests/browser-calendars.cjs` creates an isolated test account and checks email participants/absences, country defaults, reactive CSV import, workspace working hours, policy flows, and display-timezone isolation. `tests/browser-configuration.cjs` uses another isolated account to check removal dependencies/redirects, native routing drag/drop, saved positions, insertion/removal renumbering, and mobile controls. Screenshots go under ignored `test-results/`. Windows development needs complete PostgreSQL server binaries and their `share/` data files, not a client-only installation. Pass `-PostgresBin` to use a portable distribution. The loopback-only local database uses trust authentication and is not a production configuration. The script serves a copy of the executable so Cargo can rebuild while it runs. Read [testing.md](testing.md) when changing rules and [deployment.md](deployment.md) before preparing GKE deployment. ## Demo lifecycle `MEGURI_SEED_DEMO=true` enables disposable demo mode, not just seed insertion. It is limited to loopback and a single `all` or `web` process. Startup verifies the previous database mode before migrations, resets only positively marked demo application data, migrates, and seeds two examples. Normal startup records `normal`, including migration/worker roles. A missing or unreadable provenance marker never grants deletion authority. The existing development `meguri` DB will therefore be preserved on its first transition to this mode. When the configured DB is protected, Meguri selects a separate `meguri_demo__` DB. The application login needs CREATEDB, or an administrator must supply an empty `MEGURI_DEMO_DATABASE_URL` with suitable permissions. Credentials are never shown in the browser/log notice. Protected fallback candidates are skipped, never dropped or overwritten. Isolation failure aborts startup. Do not manually mark a production database as demo. Another active client blocks reset; stop the old demo process before restarting. The permanent header explains creation-based expiry and any protected-DB fallback. Defaults: workspaces 24 hours; visitor accounts 48 hours; requests 2 hours; audit/history 6 hours; physical purge 10 minutes after soft deletion. Configure seconds with the `MEGURI_DEMO_*` settings in `.env.example` (60 seconds–30 days). Sweeps run every minute. Nested configuration expires with its owning aggregate to preserve dependencies. Seed accounts remain; baseline workspaces are reseeded after expiry. No cleanup runs in normal mode. Demo rejects real provider integrations/publication. Alice (`meguri-demo-only`) leads both examples. Bob belongs to Engineering; Carol belongs to Support. Engineering uses `projects`, `responsible`, and `on_call`; Support has independent `queues`, `agents`, and `lead` variables. All generated state is activated through the regular preview/commit code path with the mock provider. Additional browser suites: `browser-absence.cjs` checks collapsed holidays, DD-MM-YYYY input, live bulk absence impact, range replacements and force; `browser-generation.cjs` checks demos, their permanent notice and isolated memberships, visual data/binding editing, early errors, preview without writes, stable generated IDs, and mobile forms. Restart after browser tests to return to the four clean examples. OIDC is intentionally deferred; local password authentication is implemented first. No external JSM account is needed to run the mock provider. JSM writes require explicit integration configuration and workspace-scoped environment credentials. Contract tests use a fake HTTP server, never a production account. Workspace configuration edits take effect when saved. Historical queries use saved configuration revisions. There is no user-configurable delayed activation of a whole configuration revision in the first release. `tests/browser-cover.cjs` exercises daily volunteering/approval and optional comments in a separate disposable workspace, with desktop and mobile screenshots. Configuration navigation is grouped under Setup. Navigation and language coverage: tests/browser-navigation.cjs checks direct menu/workspace links, reload and browser history, saved language versus browser preference, Russian/French display, safe interpolation, catalog completeness and the prohibition on literal template copy. It runs in npm run test:browser. Demo workspaces import `src/demo-holidays-2026.csv` through the regular holiday service: 15 Cyprus dates supplied by the project owner and 18 Japanese holidays/days off from https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html (2026 table, verified 2026-09-24). This is a fixed 2026 example, not a recurring calendar or an annual-date extrapolation. Demo workspaces: Acme Engineering (project priorities + weekly cover), Customer Support (daily queues), Regional Platform (dictionary regions → nested enabled services, region-specific handovers/rotation lengths, shared commander), Commerce Operations (product → tier dictionary lookup, variable escalation delays/repeats/working windows, shared weekly fallback). Alice owns all four; Bob is a member in Acme/Regional, Carol in Support/Commerce. Regional times use the workspace scheduling zone, not a per-region zone. Disabled Sandbox and Legacy export illustrate filtering; enabling the latter requires adding its missing retired tier or choosing an existing tier. All examples use normal generation preview/apply and demo cleanup; provider remains local preview. The main Acme Engineering demo contains six services (Payments, Search, Billing, Identity, Data platform, Developer portal), each with two or three ordered owners drawn from five login members: alice, bob, carol, dave, erin. All five share the weekly Monday 11:00 Time off rotation. Dave and Erin only access Acme; Carol also retains Support/Commerce access. Other demo workspaces remain separate. Login password remains `meguri-demo-only`. ## Single workspace schema Migration 8 replaces the former tenant/team tables with workspaces and workspace memberships. It requires an empty legacy schema; it refuses to erase a populated non-demo database. Demo startup resets only provenance-verified demo data before migrations and recreates four independent workspaces. No history conversion or runtime compatibility layer is provided. All settings and generation state share the workspace revision. API paths are `/api/workspaces/{workspace}`; navigation uses `?workspace=...`. PostgreSQL integration tests use the dedicated `meguri_workspace_test` database. The default Engineering example stores projects as one list of dictionaries: each entry has `name` and an ordered `responsible` person list. The Project iteration reads both fields directly from its current entry; no parallel responsible lookup variable is needed. The independent `on_call` list still defines the shared weekly rotation. Generation map uses locally vendored Cytoscape.js 3.33.1 (`static/vendor/cytoscape.js`, adjacent MIT license), with no CDN requests or Node build requirement. Its preset lane layout and inspector live in `static/generation-map.js` / `.html`; engine trace data is returned by the authorized generation-preview endpoint. Run `node tests/browser-generation-map.cjs` against the disposable demo for nested iterations, filtering, diagnostics, read-only behavior, canvas interactions and mobile layout.