# UbuntuPlay — Setup & Operations Guide

**Version 10.48.0 · Zipangile · Lusaka, Zambia**

---

## Overview

UbuntuPlay is the first **Offline AI-powered** eLearning platform for Africa.

| Component | What it does | Who runs it |
|---|---|---|
| **Classroom Server** (`classroom/`) | The local school server. Serves the games, the **Gogo AI Tutor**, the Teacher Dashboard, and the **Headmaster LMS**. | Teacher's phone or laptop |

### Offline AI Features
Next-generation AI runs directly in the classroom — browser-first, pure WASM, no internet required:
- **Gogo AI Student Tutor:** Context-aware hints and dialogue-based support for learners.
- **Adaptive Difficulty:** Automatically scales challenge levels based on student accuracy.
- **AI Level Generation:** Dynamic topic-based generation for all games (LiteRT-LM + Gemma 4 E2B via the Gogo AI Bridge).
- **Language Switcher:** Instant translation into Bemba, Nyanja, Tonga, and Lozi.
- **Gesture Control:** MediaPipe-powered hand tracking for interactive play (Rangi game).

To use these features offline, run `ubuntuplay setup-ai` on the server to download the model weights.

---

## Official Games

UbuntuPlay ships 6 curriculum-aligned games:

| Game | Subject | Description |
|---|---|---|
| **Assegai — Spear of the Ancestors** | Social Studies / History | Turn-based tactics campaign across African history with quizzes between battles |
| **Chenjela** | Critical Thinking | Pattern recognition and logical sequencing puzzles |
| **Madzi — Guardians of the Flow** | Science (Water) | Physics-driven liquid puzzle game teaching water conservation. Six chapters, 30 levels, built-in conservation quizzes. |
| **Mankwala — The Word Doctor** | Literacy | Spelling and sentence tile game — cure patients by assembling withered words |
| **Nzelu** | Maths / Literacy | Match, sequence, and quiz game with AI level generation |
| **Rangi** | Art / Colour Theory | Gesture-controlled colour-mixing and pattern game |

All games support local language translation (Bemba, Nyanja, Tonga, Lozi).

---

## Prerequisites

The classroom server requires **Node.js** (v18+).

### Android (Termux)
Install via F-Droid (not Google Play):
```bash
pkg update && pkg upgrade
pkg install nodejs
```

### Linux (Ubuntu/Debian/WSL)
```bash
sudo apt update
sudo apt install nodejs npm unzip python3 python3-pip -y
```

### macOS
```bash
brew install node unzip python
```

Verify:
```bash
node --version    # should show v18 or higher
npm --version
```

---

## Part 1 — Server Setup (Classroom Server)

> **Tip:** On Android the one-line installer does all of this for you:
> `curl -fsSL https://ubuntuplay.fly.dev/downloads/install.sh | bash`

### 1. Extract the server

Download `uplay-server.zip` from `https://ubuntuplay.fly.dev/downloads/uplay-server.zip` (or receive it offline), copy it to your device, and extract it:

```bash
cd ~
unzip /path/to/uplay-server.zip
```

This creates `~/classroom/`.

### 2. Install dependencies

**Always run this fresh — never copy node_modules from another device.**

```bash
cd ~/classroom
npm install
```

If `npm install` fails with a Python error:
```bash
pkg install python
npm install
```

### 3. Start the server

```bash
cd ~/classroom
node server.js
```

You should see:
```
╔══════════════════════════════════════════════════════╗
║  UBUNTUPLAY CLASSROOM v10.48.0                       ║
╠══════════════════════════════════════════════════════╣
║  Teacher:   https://localhost:3443/teacher           ║
║  Students:  https://10.x.x.x:3443/play               ║
║  Developer: https://localhost:3443/developer         ║
║  HTTP:      http://10.x.x.x:3000 (auto-upgrades)     ║
║  Trust setup: http://10.x.x.x:3000/trust             ║
╠══════════════════════════════════════════════════════╣
║  Setup code: XXXXXX (needed at /setup)               ║
╚══════════════════════════════════════════════════════╝
```

The server listens on plain HTTP (port 3000) **and** HTTPS (port 3443) with an automatically generated self-signed certificate. Browser navigations on HTTP redirect to HTTPS automatically. See Part 4 for certificate trust setup.

### 4. Run the Setup Wizard

Open `http://localhost:3000/setup` and enter the **setup code** shown in the startup banner. The wizard configures the school, creates the head teacher account, and optionally connects to the Hub (you will need your Hub URL — e.g. `https://ubuntuplay.fly.dev` — and a Connection Token).

### 5. First login

Open `http://localhost:3000/teacher` and sign in with the credentials you created in the wizard.

**Change the password immediately if it was shared with you** — Settings → Change Password.

### 6. Optional: license activation for offline-only schools

If your school is not Hub-connected, set your Ed25519 public key before starting the server so license keys can be validated (see Part 2), then paste your license key in the Setup Wizard under **Offline Only**.

```bash
export DEV_PUBLIC_KEY=<base64url-SPKI-public-key>
node server.js
```

On Android builds, the key can instead be placed in `data/dev_public_key.txt` (one key per line; when the file exists it fully replaces the env trust set).

---

## Part 2 — Environment Variables Reference

### Classroom Server (`classroom/`)

| Variable | Required | Description |
|---|---|---|
| `DEV_PUBLIC_KEY` | For licensing | Ed25519 public key for license validation and signed ZIP verification. Without it the server still starts, but license activation and game ZIP uploads are disabled. |
| `DEV_PUBLIC_KEYS` | No | Additional trusted public keys (comma/semicolon/whitespace-separated) for key rotation. |
| `PORT` | No | HTTP port. Default: `3000` |
| `HTTPS_PORT` | No | HTTPS port for the self-signed TLS listener. Default: `3443` |
| `DISABLE_HTTPS` | No | Set to `1` to disable the HTTPS listener entirely. |
| `DISABLE_HTTPS_REDIRECT` | No | Set to `1` to stop browser navigations on HTTP being redirected to HTTPS. |
| `WS_BRIDGE_PORT` | No | Gogo AI Bridge WebSocket port. Default: `3001` (also available as `wss://<host>:<HTTPS_PORT>/gogo-bridge`). |

> `JWT_SECRET` and `ANON_SECRET` are generated automatically on first run and saved to `classroom/data/`. Do not set these manually.

---

## Part 3 — School Onboarding Flow

### Hub-Connected School (recommended)

1. **In hub dashboard** → Connected Schools → **+ Add School**
2. Fill in school name, country, plan, billing type
3. Click **Create School & Generate Token**
4. A modal shows a **Connection Token** and **License Key** — copy both
5. Send the connection token to the school teacher
6. Teacher opens `http://localhost:3000/setup`
7. Teacher chooses **Connect to Hub**, enters the Hub URL and connection token
8. License activates automatically — teacher never needs to enter a key

### Offline-Only School

1. **In hub dashboard** → License Key Gen → generate a key for the correct plan
2. Send the license key to the teacher (WhatsApp, print, or in person)
3. Teacher opens `http://localhost:3000/setup`
4. Teacher chooses **Offline Only**, pastes the license key
5. License activates locally — no internet needed

> Credentials can also be delivered as a **QR card** generated in Hub Admin; the Setup Wizard and Teacher Hub can scan it to auto-fill the Hub URL, token, and license key.

---

## Part 4 — HTTPS & Certificate Trust

The server provisions its own self-signed certificate (stored in `data/ssl/`, regenerated automatically when it expires or the device joins a new network). Some browser features used by the games — camera-based gesture control and voice commands — require a secure context, which is why HTTPS is on by default.

- **Trust guide:** open `http://<server-ip>:3000/trust` on any device for step-by-step, per-platform certificate install instructions.
- **Certificate download:** `http://<server-ip>:3000/cert`
- **Status:** `GET /api/ssl/status`

If you prefer plain HTTP only, start the server with `DISABLE_HTTPS=1`.

---

## Part 5 — Troubleshooting

### License keys won't activate

`DEV_PUBLIC_KEY` is not set (the startup log shows a warning). Set it in your environment or `data/dev_public_key.txt`, then restart. If you export it in the shell, remember a new Termux session loses it — use a start script that sets it before `node server.js`.

### `ENOENT: no such file or directory` on db.json

The `data/` directory doesn't exist yet. Run:
```bash
mkdir -p ~/classroom/data/events
node server.js
```

### `Cannot find module '../encodings'` (iconv-lite error)

Your `node_modules` is incomplete or was copied from another device. Fix with a clean reinstall:
```bash
cd ~/classroom
rm -rf node_modules
npm install
```

### Students can't connect

- Make sure your phone's Wi-Fi hotspot is turned on
- Students connect to your hotspot first, then open Chrome
- They type the `https://10.x.x.x:3443/play` address shown in the startup banner (or the HTTP address, which auto-upgrades)
- The address changes if you switch networks — always check the banner
- If the browser warns about the certificate, follow `http://10.x.x.x:3000/trust`

### Server slow with many students

More than 20 concurrent students may slow the server on low-RAM devices. Ask students who have finished to disconnect from the hotspot.

### Python / Build Errors during `npm install`

If you see errors related to building native modules, ensure Python is installed and in your PATH.
On Linux: `sudo apt install build-essential python3`
On Android/Termux: `pkg install build-essential python`

### Translation Service Errors

The optional NLLB translation fallback service requires Python and several packages. If it fails to start:
```bash
cd translation-service
pip install -r requirements.txt
```
*Note: On some systems you may need to use `pip3` or add `--break-system-packages` if installing globally.*

### Port already in use

```bash
pkill -f "node server.js"   # kill server
```
Then restart. To run on different ports: `PORT=8080 HTTPS_PORT=8443 node server.js`.

### Server crashes and won't restart

Check if a stale process is running:
```bash
ps aux | grep node
```
Kill it by PID:
```bash
kill <PID>
```

---

## Part 6 — Data & Backups

All data is stored in plain JSON files (no SQLite in the classroom server — `better-sqlite3` was removed in v10.6.0 for Android compatibility):

| File | Contains |
|---|---|
| `classroom/data/db.json` | All student accounts, scores, games, license, teacher credentials, attendance (incl. scan check-ins), announcements, terms, parent links, LMS config |
| `classroom/data/events/` | Analytics event logs (one file per day) |
| `classroom/data/translation_cache.json` | Cached translation results (ships pre-seeded with FLORES+ entries; auto-managed) |
| `classroom/data/ssl/` | Self-signed HTTPS certificate (auto-managed) |
| `classroom/data/.jwt_secret` | Persistent signing secret — also signs attendance badge QR codes (a factory reset invalidates printed badges) |

**To back up:** Copy the `classroom/data/` folder to a safe location.

**To restore:** Copy the `data/` folder back before starting the server.

---

## Part 7 — Accessing All Dashboards

| URL | What it is | Login |
|---|---|---|
| `http://localhost:3000/` (or `/lms`) | **Headmaster LMS** — learner enrollment, QR/NFC attendance check-in, printable student ID cards, announcements, terms, whole-school reports | Head teacher, deputy, or a teacher with granted LMS permissions |
| `http://localhost:3000/teacher` | Teacher classroom dashboard | Username + password |
| `http://localhost:3000/teacher/hub` | Teacher Hub — licensing, parent-link approvals, QR tools | Teacher login |
| `http://localhost:3000/setup` | School setup wizard | Setup code (first run) |
| `http://localhost:3000/welcome` | Public landing / games showcase | None |
| `http://localhost:3000/developer` | Developer platform (localhost only) | Developer password |
| `http://[your-ip]:3000/play` | Student game portal | Student username + PIN |
| `http://[your-ip]:3000/trust` | HTTPS certificate trust guide | None |

All pages are also served over HTTPS on port `3443`.

The LMS is the school's management suite: enroll learners (single or bulk) in the Learners tab, print credit-card-size student ID cards whose QR codes double as attendance badges, and check students in at the door by camera QR scan, NFC tap, or any USB/Bluetooth barcode scanner. The head teacher (or a deputy) can grant individual teachers access to specific LMS areas — learners, attendance, announcements, reports, calendar — from Staff &amp; Roles. Full guide: [/docs/lms](https://ubuntuplay.fly.dev/docs/lms).

---

© 2024-2026 Zipangile · UbuntuPlay
