Skoolsewa - School Management System Docs
Developer ResourcesArchitecture

Demo School Seed

The API-driven seed that builds a populated demonstration school - what it creates, the environment it reads, the checks that refuse a run, and the five demo logins.

Audience: Backend developers - anyone who needs a populated development database Scope: pnpm --filter @skoolsewa/api seed:demo-school; the bootstrap seed (pnpm db:seed) is covered only where the two meet

Demo School Seed

The demo seed creates a working school - staff, pupils, guardians, a published timetable, attendance, exams, fees, salary and assets - by calling the running API as the superadmin. It writes through the same controllers, validation, outbox and workers as the admin panel, so every side effect the product has also runs here. It lives in apps/api/scripts/seed-demo-school/ and is not part of the Nest application.

1. Two seeds, two jobs

CommandCreatesNeeds the API running
pnpm db:seedPermissions, roles, one superadmin, reference lists, geography lists and the school structure. Idempotent.No - it writes to the database directly
pnpm --filter @skoolsewa/api seed:demo-schoolThe demonstration school described below. Run once per database.Yes

pnpm db:seed runs first: the demo seed logs in as the superadmin it creates and relies on the roles, grades, sections and the current academic session it leaves behind.

2. Running it

  1. Migrate and bootstrap the database: pnpm db:migrate, then pnpm db:seed.
  2. Start the API with the full runtime profile (API_RUNTIME_PROFILE unset or full): pnpm dev:server.
  3. Run the seed:
pnpm --filter @skoolsewa/api seed:demo-school

The full profile is required because several steps wait on queue workers that the fast profile does not start: approved leave writing attendance, fee generation runs, and salary approval. Each of those is polled to its terminal state; a step times out rather than assuming the worker ran.

The runner prints ▶ <step> and ✔ <step> <counts> <ms> lines, then a summary of every step's counts. The first failing step prints one ✖ line (step name, HTTP status, error code, method, path and message - never a request body or a password), sets exit code 1 and stops the run.

3. Environment

config.ts loads apps/api/.env without overriding variables already exported in the shell.

VariableRequiredDefaultMeaning
SEED_API_BASE_URLNohttp://127.0.0.1:5002/apiAPI base URL, trailing slash removed. Must be https, or http on localhost, 127.0.0.0/8 or ::1, so the superadmin password never crosses a network in cleartext.
SUPERADMIN_EMAILNosuperadmin@skoolsewa.localAccount the seed signs in as.
SUPERADMIN_PASSWORDYes-Password of that account.
DEMO_PASSWORDNodemo1234Password given to the five demo logins. 8 to 32 characters, the range the login DTO accepts.
SEED_EXPECT_DBYes-Name of the database the seed must be connected to. Must not end in _test.
DIRECT_DATABASE_URL, else DATABASE_URLOne of them-Direct PostgreSQL connection used for the run lock, the identity checks and writing the demo credentials. Its database name must not end in _test.

A missing required variable, a _test database name (in SEED_EXPECT_DB or in the URL, including a percent-encoded skoolsewa%5Ftest), an unparsable database URL, an unsafe SEED_API_BASE_URL or a DEMO_PASSWORD outside 8 to 32 characters stops the run before any request is sent.

4. Preflight refusals

The preflight runs before the first write and refuses, with a message naming the condition:

CheckRefusal
API healthGET /health/ready (outside the /api prefix) gives no answer within 10 seconds, or answers a non-2xx status.
Same databaseThe direct connection reports a database other than SEED_EXPECT_DB, or the superadmin's user id seen through the API differs from the one in the direct connection - the API and the seed point at different databases.
Empty rosterGET /students or GET /guardians (removed records included) reports any rows. Reset the database first.
Demo logins freeAny of the five demo emails already exists.
Current sessionThere is not exactly one current academic session, or it does not run 2026-04-15 to 2027-04-14 - the only session the BS 2083 data fits.
Run windowThe date in Asia/Kathmandu is outside 2026-09-17 to 2027-02-17. The floor guarantees Bhadra 2083 has ended (salary periods need it) and the First Terminal is in the past; the ceiling leaves at least eight weeks before the session ends.
Run lockAnother seed run holds the PostgreSQL advisory lock.

When NODE_ENV is production, the preflight also prints whether RESEND_API_KEY and SMS_PROVIDER are set (never their values), because a run can send mail and SMS.

5. What it creates

The steps run in this order. Names and numbers come from the step files.

StepCreates
00-fee-sweep-offSwitches fee auto-generation off for the run and records the original value.
01-school-profileNames the school "Shree Saraswati Demo Secondary School", timezone Asia/Kathmandu, currency NPR.
02-week-configSaturday as the weekend; the school day ends at 17:00.
03-calendarGenerates the current session's calendar and adds four holidays: Buddha Jayanti, Haritalika Teej, the Dashain vacation (2026-10-11 to 2026-10-25) and the Tihar vacation (2026-11-07 to 2026-11-11).
04-departments-designationsTen teaching departments beside the existing Administration department, and their designations.
05-rooms33 rooms: 30 classrooms, two laboratories and the library.
06-subjects17 subjects.
07-staff47 staff: 39 teachers across the teaching departments, plus the principal, vice principal, three office assistants, an accountant, a librarian and a peon.
08-classes30 classes: Nursery to Grade 12, sections A and B.
09-guardians-students150 families: 200 guardians and 180 students, each student enrolled in a class.
10-class-subjectsSubject and teacher assignments for every class.
11-timetableA published weekly timetable for every class, Sunday to Friday.
12-loginsGrants sign-in to the five demo accounts and gives them credentials (section 6).
13-leaveTwo pupil leave requests (one approved, one pending, the pending one on future days) and one approved staff leave. The leave worker writes the approved days into attendance.
14-attendanceA completed register for every class on every school day from the later of the session start and 28 days ago, to yesterday. Marks are drawn 92 percent present, 4 absent, 3 late, 1 excused; days the leave worker already excused are kept.
15-examsTwo exams for all 30 classes (section 7).
16-assignmentsThree published assignments per class (90), and one reviewed submission each for the student and student2 logins.
17-noticesTen published notices, addressed to everyone, to a grade, to a class (or its guardians or teachers) or to a role.
18-feesOne fee category, three components (tuition monthly, admission one-time, examination annual), one fee structure per grade band, a generation run per grade, and payments that leave pupils fully paid, partly paid and unpaid.
19-salary-assetsOne salary structure assigned to every staff member; Shrawan and Bhadra 2083 prepared, approved and sent; 12 assets (6 laptops, 6 desks) assigned to staff.
20-finishRestores fee auto-generation and prints the login emails.

Randomised values (names, attendance marks, payment mix) come from a fixed-seed generator, so two runs on the same date produce the same data.

Fee auto-generation recovery

Step 00 turns the fee auto-generation sweep off so it does not race the seed's own generation runs, and step 20 turns it back on. If a step fails in between, the runner prints a recovery line after the failure:

recovery: fee auto_generate is now false; restore it to true (PATCH /fees/settings {"autoGenerate": true}), or reset the database

The value in the line is whatever the setting was before the run. Restore it through the API, or reset the database and run again.

6. The five demo logins

KeyNameRoleEmail
officeAnita ShresthaStaff (office)office@skoolsewa.local
teacherBikash AdhikariStaff and teacherteacher@skoolsewa.local
parentChandra RaiGuardianparent@skoolsewa.local
studentDeepa RaiStudentstudent@skoolsewa.local
student2Aarav RaiStudentstudent2@skoolsewa.local

All five share the password in DEMO_PASSWORD. The seed grants each account sign-in with no invitation sent, then writes the email and password credential straight to the database in one transaction (bcrypt, cost 12, email marked verified) - all five get a credential or none does. It then signs in as each account and checks the user id matches the one the API created; the teacher also switches to the teacher role. The activity steps reuse these sessions: the leave requests are filed as the parent and teacher logins and the assignment submissions as the two student logins; everything else is written as the superadmin.

parent, student and student2 belong to one family, the Rai family.

7. Exam dates

ExamDatesState at the end of the run
First Terminal Examination 2083School days from 2026-08-02 to 2026-08-31 (fixed)Papers published, marks entered and finalised for every paper, exam completed, results computed for all 180 pupils and published.
Second Terminal Examination 2083Starts 14 days after the run date and spans 33 days (secondTerminalRange in 15-exams.ts); papers sit on school days in that rangePapers published, no marks.

The step refuses to continue unless the last First Terminal paper falls before today and the first Second Terminal paper falls after it. Example: a run on 2026-10-08 places the Second Terminal window from 2026-10-22 to 2026-11-23.

8. Running again

The seed is not idempotent. A second run stops at the preflight because the roster and the demo logins already exist. Reset the database (drop, pnpm db:migrate, pnpm db:seed) to start over.

A run that fails part-way leaves its rows in place; the roster check then blocks a rerun, so reset the database as well.