Automated Python bot that simulates day-to-day shop activity for PrimeAutocare, so the live demo shows fresh, realistic activity instead of static seed data. Two independent GitHub Actions cron-scheduled workflows provide continuous, zero-touch data generation with no human intervention.
flowchart LR
C1["activity.yml cron<br/>(2x/day)"] --> P1["activity.py"]
P1 -- "login + REST calls" --> API["PrimeAutocare API"]
API --> DB[("PostgreSQL")]
C2["worklogs.yml cron<br/>(nightly)"] --> P2["worklogs.py"]
P2 -- "psycopg2 (direct)" --> DB
- Workflow automation — two independent jobs orchestrated by GitHub Actions on cron schedules, each performing a bounded, idempotent unit of work per trigger
- REST API client integration —
activity.pyauthenticates against a JWT/cookie-based session (via a persistentrequests.Session) and drives the live backend exactly like a real user, exercising the same validation, business-rule constraints, and HTTP status handling a browser client would - Direct database access —
worklogs.pyconnects to PostgreSQL via psycopg2, bypassing the API where the API itself can't express the need (backdating historical timestamps) - Synthetic/test data generation — randomized, bounded data generation algorithms (jittered timestamps, probability-gated actions) that produce realistic-looking records without runaway, unbounded growth
- Idempotency — both scripts check existing state before writing, so re-running a workflow (manually or via retry) never produces duplicate data
- Least-privilege security model — a dedicated, scoped bot service account (role-based) rather than reusing an administrator credential
It's two independent workflows, split by how they reach the data:
| Script | How it writes | Why |
|---|---|---|
scripts/activity.py |
Through the real API, logged in as a bot employee | Jobs, invoices, and payments all go through the backend's own validation, status-transition rules, and constraints — exactly like a real user's actions would |
scripts/worklogs.py |
Directly into Postgres | The attendance endpoints always stamp datetime.now() server-side, so there's no way to give an employee a realistic historical shift (a specific clock-in/out time) through the API |
Runs a bounded, randomized slice of shop activity each time it's triggered: progresses a few pending jobs to in-progress and a few in-progress jobs to completed, occasionally creates a new job (mostly against an existing customer/vehicle, sometimes a brand-new one), raises invoices for newly completed jobs, and records payments (full or partial) against outstanding invoices.
Runs twice a day via .github/workflows/activity.yml.
Required secrets:
API_BASE_URL— the deployed backend URLBOT_USERNAME/BOT_PASSWORD— login for a dedicated bot employee account
The bot needs an employee row with role A or S (job/invoice/payment
writes require one of those roles). Easiest way: log into the app as an
existing admin, go to Employees, and add one — name it something obviously
synthetic like "Bot User", give it role S, and use its username/password as
the two secrets above. No manual SQL required.
Once per simulated day, generates one attendance row per employee directly in
the attendance table: a clock-in and clock-out time jittered around shop
hours (some early, some late, some short shifts, some long/overtime), with a
small chance any given employee is simply absent that day (no row at all).
Skips a day entirely if attendance already exists for it, so re-runs or manual
triggers don't double-insert.
Runs nightly via .github/workflows/worklogs.yml, after the simulated
shop day ends. Trigger manually with a specific date to backfill history:
gh workflow run worklogs.yml -f date=2026-07-15
Required secret:
DATABASE_URL— same Postgres connection string used by PrimeAutocare's own keepalive workflow
Shop hours, jitter ranges, absence rate, and the closed weekday are constants
at the top of worklogs.py; per-run volume caps and probabilities for
activity.py are constants at the top of that file. Adjust either directly
rather than adding configuration plumbing — this is a two-script repo, not a
framework.
pip install -r requirements.txt
DATABASE_URL=... python scripts/worklogs.py
API_BASE_URL=... BOT_USERNAME=... BOT_PASSWORD=... python scripts/activity.py