Solvo Solvo

Demo Data

db/seeds/demo_data.sql populates a complete, realistic demonstration environment — two schools, a financing partner, a standalone ElimuPay API client, and every role — so a prospective customer can log in and actually use the product before committing to anything.

Every account below signs in from the same page — there's no separate login per role.

Sign in at /login.php →

Running it

Run this once, after db/01_schema.sql (or install.php) has been applied, and after you've created your own Super Admin account. This file deliberately creates no super_admin row, so it can never interfere with that one-time, deliberately-singleton setup flow.

mysql yourdb < db/seeds/demo_data.sql

The whole file runs inside a single transaction — it either fully succeeds or fully rolls back. That matters in practice: if an import gets interrupted partway (a timeout on shared hosting, a dropped connection, or clicking import twice in phpMyAdmin), the transaction wrapping means nothing gets left half-committed for a retry to collide with.

Every ID in this file — every school, user, student, and everything else — starts at 500,000, not 1. That's deliberate: this file is meant to run after you've already created your own Super Admin account (which takes users.id = 1 on a fresh table), and possibly after you've already clicked around and created other real data too. Starting at a high, clearly out-of-the-way number means the demo data can never collide with anything real, without needing to check what's already there first.

Not designed to be re-run against a database that already has this demo data (or real school data) in it — it uses explicit primary keys throughout, matching what a fresh install's auto-increment would produce, so a second run against a database that already has that data will hit duplicate-key errors. That's intentional, not a bug: a one-time bootstrap for a fresh environment, not an idempotent seed.

If you hit "Duplicate entry '1' for key 'PRIMARY'"

If you're reading this because you just hit that error: it almost certainly means you correctly followed the instructions above and created your Super Admin via install.php before running this file — which is exactly right — but an earlier version of this file used low, hardcoded IDs starting at 1, the same ID your Super Admin account takes on a fresh users table. That's fixed now: every ID in this file is offset by 500,000 (a school is id = 500001, not id = 1), so it's structurally unable to collide with your own account or anything else created through normal use, however many real schools, staff, or students already exist. If you're on the current version of this file, this specific error shouldn't happen again — if it does, it means something in your database is also at a 500,000+ ID, which would be worth a closer look with the diagnostic query below.

If you still have partial rows left over from hitting this before the fix:

  1. db/seeds/check_before_import.sql — read-only, shows you exactly what's currently in the tables this seed touches. Run this first if you're not sure what's there.
  2. db/seeds/reset_demo_data.sql — removes anything already created by this specific demo dataset (identified by name — Riverside Academy, Greenfield Primary, Jamii Finance Partners, Sunrise Schools Group — not a blind sweep, so your real Super Admin and any other real data is untouched), then you can safely re-run demo_data.sql from a clean slate. Leaves subscription_plans alone, since those are shared infrastructure a real school might already be using, not demo-specific data.

Both were tested against the exact scenario that causes this — a real MariaDB instance, a Super Admin account created first via the same insert install.php uses (so it lands on users.id = 1 exactly as it would on a real install), then the demo data imported on top: zero collisions, both the real account and all ten demo accounts coexist correctly.

Tested, not just written. This file was verified end-to-end against a real MariaDB 10.11 instance running the actual db/01_schema.sql — schema applies cleanly, the demo data loads with zero errors or warnings, and every table passed a CHECK TABLE integrity pass. One real bug was caught and fixed in the process: the schema itself already seeds six catalog curricula (844, CBE, BRITISH, IB, AMERICAN, MADRASA) — an early draft of this file tried to insert its own CBC curriculum row, colliding with that pre-seeded data on primary key. Fixed by referencing the existing CBE curriculum (the current name for what used to be called CBC) via a subquery instead.

Every demo account shares one password

Demo@2026

Login directory

Riverside Academy — the fully-featured demo school

RoleEmailWhoWhat to look for
School Adminadmin@riverside.ac.keGrace Wanjiru Full administrative view across every module
Teacherteacher@riverside.ac.kePeter Otieno Teaches Mathematics to Grade 5 and Grade 7
Accountantaccountant@riverside.ac.keDavid Mwangi Fee balances, payroll, the accounting ledger
Librarianlibrarian@riverside.ac.keEsther Njoki Book catalog, active loans, one overdue fine
Parentparent1@riverside.ac.keAlice Muthoni Mother of two enrolled children (Brian, Faith) — sibling discount active; Brian has a self-serve ElimuPay plan with one instalment already paid
Parentparent2@riverside.ac.keDaniel Kimani Father of Cynthia — her ElimuPay plan is financing-partner backed (Jamii Finance Partners), already disbursed
Studentstudent1@riverside.ac.keBrian Muthoni An open Head Boy election is waiting for his vote, and he's one of the two candidates — a genuine live-voting demo moment
Studentstudent2@riverside.ac.keCynthia Kimani Appointed Class Prefect for Grade 5
Alumnialumni@riverside.ac.keKevin Otieno Graduated 2023, has a donation on record

Greenfield Primary — a second, smaller school

RoleEmailWho
School Adminadmin@greenfieldprimary.ac.keMichael Ndungu

Deliberately lighter (3 classes, 8 students, core academic + fee data only, still on its trial subscription) — its main purpose is proving multi-tenant isolation: logging in here shows nothing from Riverside, and vice versa.

Affiliate portal — a separate login, not /login.php

An affiliate isn't a users row and doesn't share the platform's regular session (see AffiliateAuth.php — deliberately isolated the same way ApiAuth.php is). Sign in at /affiliates/login.php, not the main login page.

RoleEmailWhoWhat to look for
Affiliatebrenda.blogger@example.comBrenda Otieno Referral code DEMO01 — credited with referring Riverside Academy, with one real paid commission (KES 432, 10% of Riverside's KES 4,320 subscription payment) already on record. Visit the Marketing Toolkit from her dashboard for downloadable banner images and HTML embed codes, each with her referral link already baked in.

What's covered

Every module has real, interconnected data: academic setup (curricula, classes, sections, subjects, teacher assignments), attendance (last 5 weekdays for every student), exams and results (Grade 5 and Grade 7, where the demo logins are, so report cards have real substance), fee structures and balances in deliberately varied payment states (fully paid, partial, untouched), four ElimuPay instalment plans covering every real status (self-serve active, partner-financed active, completed, pending partner confirmation), library (including one overdue loan with a fine), transport (one vehicle has a live GPS ping so the parent view's map feature has something real to show), hostel, admissions (five applications across every review stage), student leadership (one open election ready to vote in, one finalized election with real tallies, one appointive holder), alumni, homework/assignments, live classes, messaging, announcements, payroll (a fully processed run), the accounting ledger, subscription billing (one paid invoice, one pending), and the standalone ElimuPay API client's own activity log.

What's deliberately NOT included