Beatplan: guide for AI coding agents
You are working on a licensed copy of Beatplan: an Expo SDK 58 (React Native 0.88) app plus a Supabase backend for field-sales teams and vehicle fleets. The person you're helping is usually the licensee setting it up for their company. They may not be a developer, so do the work and explain results in plain language.
If asked to "set up" or "install" the app
Follow .claude/skills/setup-beatplan/SKILL.md step by step.
Commands
npm install: dependenciesnpm run web,npm start: dev server (web / native)npx expo export --platform web: production web build intodist/(also the quickest compile check for JS changes)npx supabase db push: apply migrations to the linked projectnpx supabase functions deploy send-activity-push: deploy the push function./scripts/test-db.sh: install the schema into a temp Postgres DB and run the smoke + security suites (needsPGHOST/PGUSER)
Architecture
App.js: auth gate, tab navigation, offline banner. Tabs are shown or hidden by role; admins can grant extra screens per user (user_screen_access, managed in Admin).src/config/index.js: the only place for brand and locale values (readsconfig/brand.json). Use its exports (APP_NAME,CUR,NATIONAL_LABEL,PROVINCES,roleLabel(),companyToday()...) and never hard-code names, currencies, countries or regions.src/screens/lib/supabase.js: the Supabase client (env vars),getSafeUser()(works offline), network probes.src/screens/lib/offlineQueue.js(insertOrQueue,rpcOrQueue,enqueue): writes made offline are queued and replayed. New writes on field screens should use these and give rows a clientuuidv4()id so replays are idempotent.src/ui/: design system. Readdocs/DESIGN_GUIDE.mdbefore building UI.src/screens/web/: the browser console (WebApp.js); native code never imports from it.src/screens/fleet(manager screens, data) andsrc/screens/fleethome(the fleet shell: home, car details, intro).
Database rules (important)
supabase/migrations/20260101000000_beatplan_init.sqlis the whole schema. Never edit it after it has been applied to a project. Add a new timestamped migration for every change.- Every table has RLS. New tables need
enable row level securityplus explicit policiesto authenticated. Never grant anything toanon. - Role checks belong in the database:
exists (select 1 from public.users u where u.id = auth.uid() and u.role in (...)). App-side hiding is cosmetic. - SECURITY DEFINER functions must
set search_path to 'public'and check the caller's role themselves. - Users must not be able to change
role,province,region_labelorarea_nameon themselves. Onlyfull_nameandphoneare self-editable (column grants). - Dates: use
public.app_tz()(never a literal timezone). The company-wide label comes frompublic.app_national_label(). - Columns named
*_pkrare historical names for "amount in the base currency". Keep them; don't rename. - After any DB change, run
./scripts/test-db.shand extendsupabase/tests/security.sqlwhen you add a permission rule.
Conventions
- Plain JavaScript (no TypeScript in
src/), function components, TanStack Query for server state. - Dates as
YYYY-MM-DDstrings from local or company time. NevertoISOString().slice(0,10)for calendar dates (it shifts days in UTC+ zones). - Role codes (
AL,TL,BL,KM,ADMIN,DIRECTOR,ACCOUNTS,LOGISTICS) are fixed identifiers. Change labels inbrand.json, not codes. - Keep
.envout of git. Theservice_rolekey never goes in the app.
Licensing
This code is under the commercial license in LICENSE.md. Use or deployment in Pakistan is not permitted. Don't remove the license file or the notices.