Single Source of Truth for workflows, testing, and committing.
Follow docs/setup/local_development.md for
the supported Flutter/FVM and isolated database setup. Project-specific agent
rules are tracked in AGENTS.md, CLAUDE.md, and
docs/architecture/ai_context.md; no third-party skill repository is required.
Runs all project tests: Web Client (JavaScript), Database (SQL), Flutter, Deno Edge Functions, and Integration tests.
./automation/test_all.shUse when modifying SQL functions or migrations.
# Rebuild the isolated local DB from the schema baseline (destructive only to
# the dedicated festapp-db-tests-pg15 Docker volume).
./automation/bootstrap_local_db.sh
# Run all DB tests
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres?sslmode=disable' \
node web_client/scripts/run_db_tests.js
# Run specific test file
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres?sslmode=disable' \
node web_client/scripts/run_db_tests.js database/tests/path/to/test.sqlKey concept: Tests run in a transaction and auto-rollback. Any data inserted during a test is undone automatically.
If a test fails saying "function does not exist":
- Rebuild the isolated local database:
./automation/bootstrap_local_db.sh. - Check that every active migration has a unique 14-digit timestamp.
- Run schema check tests if available.
Do not use a remote database as a substitute for the isolated test database.
Version every SQL change in the repository and deploy it through the approved
release workflow. Until the self-hosted cutover is complete, schema, function,
and data-contract changes must remain semantically identical on the self-hosted
target and cloud sources default and a.
Resolve the live target from SUPABASE_URL in automation/project.conf, then
verify FORCE_OCCASION_LINK in that same database. Never select a target from
the project ref in .env.local. Deploy Deno functions from their checked-in
supabase/functions/<name>/ source and follow
docs/backend/edge_functions.md.
- Local: Keys in
.env.local(NOT committed). This file is automatically loaded by local scripts and Vite. Put all secrets here. - Web Client: Public keys in
web_client/src/app_config.js. - Database:
DATABASE_URLrequired for test runner.
CRITICAL: Every time you write a new PostgreSQL function (RPC), especially
with SECURITY DEFINER, you MUST verify:
- Search Path: Use
SET search_path = public, extensions. Qualify everyeshopobject explicitly (for exampleeshop.orders); never addeshopto the search path.- Why? Prevents search_path hijacking where malicious users create objects in public schema.
- Permissions Check: If the function modifies data or returns sensitive
info, it MUST check permissions.
- Example:
PERFORM public.check_is_admin_for_bank_account(p_account_id); - Why?
SECURITY DEFINERruns with superuser-like (or owner) privileges, bypassing RLS. explicit checks are mandatory.
- Example:
- Input sanitization: Avoid
EXECUTEwith raw strings. Useformat()or parameter binding.
Shared application, SQL, Edge, worker, test and generic automation changes are
made on a branch from main. A prod/* change may contain only an approved
tenant overlay path and must record the main SHA it overlays. Before proposing a
production-branch commit, run the checker extracted from that recorded main SHA
as documented in docs/architecture/tenant_overlays.md.
Tenant releases are sequential. Push exactly one prod/* release, then run the
canonical automation/deploy_direct.sh path or explicitly dispatch the GitHub
Deploy workflow for that exact branch. Wait for deployment to finish and
complete the public production smoke test before preparing or pushing the next
tenant release. A push alone never starts a production build. Do not batch,
queue, or run several Flutter tenant builds in parallel unless the user
explicitly asks for that specific release batch.
Follow this checklist before every commit:
Ensure your local configuration is applied to the code:
./automation/apply_config.shEnsure the codebase is clean:
- Remove Temporary Files:
rm database/tests/temp_*.sql,rm web_client/scripts/temp_*.js,rm analysis.txt test_results.txt. - Remove Dead Code: Delete unused files/comments.
- Remove Debug Logs: No
console.login production code.
If you are dealing with a complex issue (e.g., data leaks, wide-spread API changes):
- Search: Use
rgandrg --filesto identify all affected files.- Example:
rg -l "CREATE OR REPLACE FUNCTION" database/tests
- Example:
- List: Create a checklist in
task.mdor a temporary artifact. - Execute: systematically go through each file in the list.
- Mark and Verify: Check off each item as you fix it. Verify after each batch.
Run the full test suite (Web, DB, Integration, and Edge Functions).
./automation/test_all.shAll tests must PASS.
If you modified en.json or cs.json:
- Unify (Flutter <-> Web):
node web_client/scripts/unify_translations.js
- Reorder (CS structure matches EN):
node web_client/scripts/reorder_cs_like_en.js
Review status, stage, and commit.
Stage only the files belonging to the change. Agents follow AGENTS.md and the
user's explicit commit and publication scope.
git status
git add path/to/changed-files
git commit -m "feat: description of changes"The web_client/ directory contains a standalone vanilla JavaScript application
for public-facing features (forms, blueprints, e-shop). It is separate from the
Flutter app but shares the same Supabase backend.
cd web_client
npm install
npm run dev # Vite dev server
npm test # Node.js native test runnerAll components extend a base class (src/components/base/component.js) with a
standard lifecycle:
init()- Initialize state and fetch datarender()- Build DOM elementsclear()- Cleanup listeners and DOM
src/components/- UI components (forms, blueprint, eshop, feedback, etc.)src/services/- Singleton services (supabase, router, auth, theme, localization, rights, seo, time)scripts/- Build tools (version sync, DB test runner, translation scripts)tests/- Test files organized by area (components, core, forms, logic, issues)
- Both apps share the same Supabase backend (same PostgreSQL functions/RPC)
- Configuration is shared via
automation/project.conf(propagated byapply_config.shto bothlib/app_config.dartandweb_client/src/app_config.js) - Translation keys should be kept in sync using
unify_translations.js
Edge Functions live in supabase/functions/ and are written in TypeScript for
the Deno runtime.
# Serve locally
supabase functions serve <function-name> --env-file .env.local
# Deploy
supabase functions deploy <function-name>Common code lives in supabase/functions/_shared/:
supabaseUtil.ts- Admin client, template fetchingemailClient.ts- Email sending (SMTP via nodemailer)auth.ts- Request authorization (authorizeRequest)utilities.ts- General helpers
Edge Functions are tested as part of the full test suite
(./automation/test_all.sh). For manual testing, use curl or the Supabase
Dashboard.
Before submitting code for review, verify:
- No
print()statements in production code (use proper logging) - No hardcoded strings in UI (use
*_strings.dartlocalization pattern) -
ExceptionHandler.guard()used instead of rawtry-catchin UI code -
RightsServicechecked before displaying admin/editor features - No
dart:ioimports in shared UI code (breaks web)
-
SECURITY DEFINERfunctions haveSET search_path = public, ... - Permission checks present (e.g.,
check_is_editor_order_on_occasion,check_is_manager_on_unit) - No
EXECUTEwith raw string concatenation (useformat()) - Function follows
verb_nounnaming convention - Corresponding test in
database/tests/
- No
console.login production code - Event listeners cleaned up in
clear()method - Supabase calls use service layer (not direct client access)
- CORS headers present on all responses
- Auth check via
authorizeRequest()for sensitive operations - Error responses include proper HTTP status codes
- Shared code imported from
_shared/(no duplication)