Installation Guide
Requirements
| Minimum | |
|---|---|
| Node.js | 20 LTS |
| PostgreSQL | 14+ |
| npm | 10+ |
| Disk | ~1 GB for the app and dependencies |
Uploads do not go to disk — they go to object storage — so the application filesystem stays small and can be read-only.
1. Install dependencies
npm install
2. Environment
SkoolyHub reads configuration from .env in the project root. Only two values are required:
DATABASE_URL="postgresql://user:password@host/dbname?sslmode=require"
JWT_SECRET="a-long-random-string"
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL |
yes | PostgreSQL connection string |
JWT_SECRET |
yes | Signs portal and admin sessions; also derives the key that encrypts stored integration credentials |
SECRET_KEY |
no | Separate encryption key. Falls back to JWT_SECRET |
ADMIN_EMAIL / ADMIN_PASSWORD |
no | Seeds the first admin. Without them a random password is generated in production and printed once |
NODE_ENV |
no | production on a live server |
Everything else is configuration held in the database, not in env: storage, payments, email, SMS, branding, currency and timezone. That is why they survive and travel with a database dump.
The install wizard can write .env for you on a writable filesystem, generating JWT_SECRET itself. On a read-only host such as Vercel, set the values in the host's environment configuration instead.
3. Provision the schema
npm run db:init
This creates the core, auth and platform tables. Every school table is also created on first use by its own idempotent ensure*Schema() function, so a table you have not touched yet simply appears when you do.
There are no migration files and no migration command. Running db:init twice is safe.
4. Seed
npm run db:seed:master # lookup lists: blood groups, designations, payment modes…
npm run db:seed:templates # email / SMS / push message templates
The first two are essential — they populate the dropdowns the admin screens depend on. Optionally add a demo school to explore with:
npm run db:seed:school
It prints working sign-in details for all three portals when it finishes. Do not run it on a real school's database — it creates fictional children.
5. Start
npm run dev # development, http://localhost:3000
# or
npm run build && npm start
The install wizard
On first run, /install walks through:
| Step | What happens |
|---|---|
| Welcome | Confirms the environment |
| Database | Tests the connection, writes .env if it can, provisions the whole school schema, seeds master data and templates |
| Admin account | Creates the first administrator |
| School | Name, timezone, currency |
| License | Purchase-code activation. Skipped automatically on localhost |
| Finish | Marks the install complete |
The wizard is disabled once installation completes, so it cannot be replayed against a live school.
After installing
- Sign in at
/admin. - Change the admin password immediately if one was auto-generated.
- Connect storage — Settings → Channels → Storage. Photo uploads fail until you do.
- Create the academic year — Academics → Academic Setup. Nothing else works without one.
Verify
npx tsc --noEmit -p tsconfig.json
npx next build
Troubleshooting
| Symptom | Cause |
|---|---|
DATABASE_URL is not set |
No .env, or the process was started before it existed |
| Connection refused / SSL required | Missing ?sslmode=require on a managed database |
| "Storage is not configured" on upload | Expected until you connect a provider under Settings → Channels |
| A route 404s in dev though the file exists | Turbopack de-registered a neighbour after a folder was added. Touch the file or restart |
server-only throws in a script |
A script imported a module that only resolves inside Next. Import the database client dynamically instead |