Skip to content

Demo / seed data

seed_demo_data is a management command that creates three demo households at different usage levels, so you can see the app empty, lightly used, and heavily used — handy for design review, screenshots, and sanity-checking how tiles, feeds, and reminders behave as data scales.

cd maud
python3 manage.py seed_demo_data              # create all three
python3 manage.py seed_demo_data --reset      # wipe demo-* and rebuild
python3 manage.py seed_demo_data --tier heavy # just one tier
python3 manage.py seed_demo_data --password '<pw>'  # set the login password

The accounts

Login is by email (allauth), at /login/. All three share one password, set with --password. There is a local-only default (see the command's --help or DEMO_PASSWORD in the source) — it is deliberately not written down here.

Email Tier What it shows
demo-new@example.com New 0 documents — the empty-state hero + full "Get documents in" onboarding panel.
demo-light@example.com Light ~6 documents across 3 topics, one house (with a property profile), a partner, a couple of tags. Onboarding graduated → the transition "pill".
demo-heavy@example.com Heavy ~39 documents across all ten topics, a house + two vehicles (with profiles), a family of five, tags, and pending triage findings, with expiring MOT / insurance / passport driving reminders. Onboarding graduated + dismissed → steady state.

The three tiers deliberately land on the three different onboarding states (panel / pill / hidden).

The password is the only thing protecting these accounts

They are real, login-able accounts. The built-in default is fine on your own machine and nowhere else. On any shared or production environment, pass a strong --password and keep it in your password manager — never in a commit, an issue, or a docs page. This site is behind Cloudflare Access, but that is a second line, not a reason to write secrets here (it has already lapsed once — see Deploying the docs).

What it builds

Data is created directly via the ORM rather than through the classifier stub (which only recognises four topics from filenames), so the topic spread, dates, providers, named items, and people are fully controlled. It still reuses the real service helpers — bootstrap_new_user_household, get_or_create_named_item, set_tags_for_document, the activity record, and maybe_mark_onboarding_graduated — so the shape matches production paths. created_at is backdated so the activity feed and "recently added" ordering read as a believable history. Each document gets a small valid PDF so files open; thumbnails stay blank (a worker generates those, same as a fresh upload).

Because everything is built via the ORM, seeding makes no external API calls — no Anthropic classification, no DVLA/DVSA lookups — so it is free and safe to run anywhere.

allauth / email verification

Production runs allauth with ACCOUNT_EMAIL_VERIFICATION="mandatory", which blocks login for any account whose email isn't verified. The command creates a verified, primary EmailAddress for each account (mirroring accounts/0004_grandfather_verified_emails) so the demo logins work under mandatory verification. It finishes with a per-account login OK line — if you ever see LOGIN BROKEN, it prints whether the password or the verified-email check failed.

The demo Gmail connection

The heavy household has a Gmail connection so its triage findings render, but it is created DISCONNECTED on purpose: the weekly scan_all cron enqueues a real scan for every active connection across all households, and a demo connection with no valid OAuth tokens would fail that scan every week and pollute the logs. Disconnected keeps it out of the cron; the findings still show because the triage list is keyed on finding status, not connection status.

Reset / teardown

--reset wipes and rebuilds. It only ever touches usernames starting with demo-, so it can't affect a real account. It deletes each household's Documents first because Document.person is on_delete=PROTECT and would otherwise block the household cascade.

Running on production

The command must be in the deployed image first — merge it to main (CI auto-deploys), then run it over SSH. Never fly deploy from a feature branch (see Deploying the app).

fly auth whoami   # confirm the personal account first
fly ssh console -a maud -C "python manage.py seed_demo_data --password '<strong-password>'"

The production demo password lives in the password manager alongside the Fly credentials. Confirm the login OK lines, then sign in at https://heymaud.com/login/ with the three emails above. If there is ever any doubt about the password having leaked, re-run with --reset and a fresh one — it only touches the demo-* accounts.