# Elimika Africa — Course Import System
A reusable, idempotent importer that migrates the exported course JSON files
into the Supabase backend. The website is **not** modified — this lives
entirely under `scripts/` and is only executed on demand.
---
## Architecture
```
scripts/
├── README.md ← this file
├── schema.sql ← prerequisite tables (run once, manually)
├── import-courses.ts ← the importer entry point
└── lib/
├── env.ts ← loads Supabase env vars (no hardcoding)
├── supabase.ts ← service-role client used only by scripts
├── schema.ts ← Zod schemas for every JSON shape
├── logger.ts ← counters + coloured console output
└── importers/
├── courses.ts
├── modules.ts
├── lessons.ts
├── lesson-content.ts
├── lesson-resources.ts
├── lesson-videos.ts
├── quizzes.ts
├── quiz-questions.ts
└── certificates.ts
```
### Design principles
1. **Idempotent** — every insert is an `upsert` on a stable natural key
(`courses.slug`, `modules.(course_slug, position)`,
`lessons.(module_id, position)`, etc.). Re-running the importer never
duplicates rows.
2. **Ordered** — courses → modules → lessons → content/resources/videos →
quizzes → questions → certificates. Each stage resolves and caches the
parent Supabase IDs before the next stage runs.
3. **Validated up front** — every JSON file is parsed with Zod before any
write happens. A single bad file is reported and skipped; the rest of the
migration continues.
4. **Safe** — no `DELETE`, no `DROP`, no truncation. Existing rows are only
updated in place.
5. **Configurable via env** — Supabase URL + service role key are read from
`process.env`; nothing is hardcoded.
---
## Prerequisites
1. **Environment variables** (never commit these):
```
SUPABASE_URL=...
SUPABASE_SERVICE_ROLE_KEY=...
```
The importer refuses to run if either is missing.
2. **Schema** — the current database only has `courses`, `enrollments`,
`lesson_progress`, ` …