Setup guide (manual)

An AI agent can do all of this for you (see README). These are the same steps by hand. Plan for about an hour the first time.

What you need

1. Install

npm install
cp .env.example .env

2. Create the Supabase project

  1. In the Supabase dashboard, create a new project and choose the region closest to your team.
  2. Go to Project Settings → API. Copy the Project URL and the anon public key into .env: EXPO_PUBLIC_SUPABASE_URL=https://abcd1234.supabase.co EXPO_PUBLIC_SUPABASE_ANON_KEY=eyJ... Never put the service_role key in .env or anywhere in the app.
  3. Go to Authentication → Sign In / Providers and turn off "Allow new users to sign up". Admins create accounts from inside the app.

3. Install the database

npx supabase login
npx supabase link --project-ref abcd1234      # the part before .supabase.co
npx supabase db push                           # applies supabase/migrations/*

This creates every table, function, policy, storage bucket and scheduled job, plus the reference data (roles, seasons, vehicle checklist, service intervals).

Optional demo data (sample areas, crops and products): open SQL Editor, paste supabase/seed.sql and run it.

4. Configure the database settings

In the SQL Editor:

update public.app_settings set value = 'America/Chicago' where key = 'timezone';          -- IANA name
update public.app_settings set value = 'United States'   where key = 'national_label';    -- = countryName in brand.json
update public.app_settings set value = '1'               where key = 'phone_country_code';
update public.app_settings set value = 'https://abcd1234.supabase.co/functions/v1' where key = 'functions_url';
select value from public.app_settings where key = 'webhook_secret';   -- copy this for step 6

national_label must match countryName in config/brand.json exactly. Dashboards use it to find the company-wide totals.

5. Create your first admin

  1. Authentication → Users → Add user: enter your email and a password, and tick "Auto confirm".
  2. In the SQL Editor: sql update public.users set role = 'ADMIN', full_name = 'Your Name' where id = (select id from auth.users where email = 'you@company.com');
  3. Sign in to the app with that email. You create everyone else in Admin → Users.

6. Push notifications

npx supabase secrets set WEBHOOK_SECRET=<the value from step 4> APP_NAME="Your App Name"
npx supabase functions deploy send-activity-push

7. Brand and localise

Edit config/brand.json (every field is described in CONFIGURATION.md) and replace the images in assets/ (icon.png 1024×1024, adaptive-icon.png, splash-icon.png, notification-icon.png white-on-transparent). Also replace public/icon-192.png, public/icon-512.png and public/apple-touch-icon.png for the web console.

8. Run it

npm run web        # web console in the browser
npm start          # scan the QR code with a development build or Expo Go

9. Ship

Web console:

npx expo export --platform web     # static site in dist/, host on Vercel, Netlify, Cloudflare Pages...

Mobile:

npm i -g eas-cli && eas login
eas init                           # creates the Expo project, then put its id in brand.json -> easProjectId
eas build --platform android --profile production
eas build --platform ios --profile production
eas submit --platform all

Over-the-air updates (optional): eas update:configure, then set easUpdatesUrl in brand.json.

10. Scheduled reminders

The fleet and expense reminders run with pg_cron, on UTC schedules:

Job When (UTC)
app_reminder_inspection_1st 04:00 on the 1st
app_reminder_inspection_7th 04:00 on the 7th
app_reminder_inspection_late 04:00 on the 8th
app_reminder_sheet_last_day 12:00 on days 28–31 (the function only acts on the real last day)
app_reminder_sheet_overdue 04:00 on the 5th
app_reminder_weekly_mon / _thu 04:00 Mon / Thu

To move one to your morning, for example 08:00 in New York (13:00 UTC):

select cron.alter_job((select jobid from cron.job where jobname = 'app_reminder_weekly_mon'), schedule := '0 13 * * 1');

Verify the database (optional)

With a local PostgreSQL 15+:

PGHOST=localhost PGUSER=postgres ./scripts/test-db.sh

It installs the schema into a temporary database and runs the functional smoke test and the security suite. The last line should read ALL SECURITY CHECKS PASSED.

Troubleshooting

Symptom Fix
App shows "Missing EXPO_PUBLIC_SUPABASE_URL" .env is missing or Expo was started before you created it. Restart with npx expo start -c
Signed in but dashboards are empty national_label in app_settings doesn't match countryName in brand.json, or there are no areas, targets or users yet
No push notifications Check functions_url is set, WEBHOOK_SECRET matches app_settings.webhook_secret, and the function logs (Edge Functions → send-activity-push → Logs)
"permission denied" for a user Check their role, province, region_label and area_name in public.users. Access follows those fields