Migrated from ideal-git.ddns.net
- JavaScript 95.7%
- Python 2.2%
- Shell 1.4%
- Dockerfile 0.3%
- CSS 0.2%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- useSpeechRecognition: fall back to local Whisper STT on browser SpeechRecognition 'network' errors (common on Android Chrome when Google's cloud speech service is unreachable) instead of silently failing - New badges + activity_log tables; /progress/complete now awards a 1-3 star badge based on real accuracy, idempotent - New GET /badges, GET /analytics/summary, GET /analytics/activity endpoints - CertificateReveal component replaces the static trophy screen on unit completion with a printable certificate (name, unit, stars, date); wired into all 7 Unit*Page.jsx - New /certificates (badge gallery) and /analytics (progress report: per-unit accuracy, 14-day activity trend) pages, linked from Dashboard header - Fix real deploy bug: frontend-build mounted the static_files volume directly at /app/dist, so Docker only auto-seeded it once (on first-ever build) - every later rebuild silently kept serving stale files. Now builds into the image normally and explicitly copies into the volume on every container start. - README roadmap updated to match actual state (units 2-7 were already built, roadmap was stale) + proposed Phase 4 module ideas |
||
| .github/skills/dyscalculia-courseware-designer | ||
| backend | ||
| database | ||
| docs | ||
| frontend | ||
| nginx | ||
| releases | ||
| scripts | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| README.md | ||
| STRUCTURE.md | ||
D-NuRI — Aplikasi Pembelajaran Nombor Interaktif
Courseware berasaskan web untuk murid bermasalah dyscalculia (diskalkulia), bertemakan angkasa lepas dengan watak Kapten Nuri (parrot angkasawan).
Kandungan
- 📐 Full Structure & Architecture → STRUCTURE.md ← COMPLETE MAPPING
- Gambaran Keseluruhan
- Tech Stack
- Struktur Projek
- Setup & Jalankan (Dev)
- Docker Compose
- Deploy ke VPS (Prod)
- 5 Unit Pembelajaran
- API Reference
- Database Schema
- PWA Features
Gambaran Keseluruhan
| Perkara | Details |
|---|---|
| Target | Murid umur ~7 tahun dengan dyscalculia |
| Watak | Kapten Nuri (SVG animated parrot astronaut) |
| Tema | Angkasa lepas, meteor, roket |
| Audio | Browser Web Speech API (TTS Bahasa Malaysia) |
| Auth | Email + kata laluan (JWT 7 hari) |
| Platform | Web + PWA (boleh install kat phone/tablet) |
Tech Stack
Frontend
| Package | Versi | Fungsi |
|---|---|---|
| React | 18 | UI framework |
| Vite | 5 | Build tool + dev server |
| Tailwind CSS | 3 | Styling |
| Framer Motion | 11 | Animasi (Kapten Nuri, meteor, transitions) |
| Zustand | 4 | State management (auth + progress) |
| React Router | 6 | Navigation |
| vite-plugin-pwa | 0.20 | Service worker + PWA manifest |
| Axios | 1.7 | HTTP client |
Backend
| Package | Versi | Fungsi |
|---|---|---|
| Node.js | 20 LTS | Runtime |
| Express | 4 | HTTP server |
| pg | 8 | PostgreSQL client |
| bcryptjs | 2.4 | Password hashing |
| jsonwebtoken | 9 | JWT auth |
| redis | 4 | Session cache (ready untuk future) |
Infrastructure
| Container | Image | Port |
|---|---|---|
| nginx | nginx:alpine | 80, 443 |
| frontend | node:20-alpine | 5173 (dev) |
| backend | node:20-alpine | 4000 |
| postgres | postgres:16-alpine | 5432 |
| redis | redis:7-alpine | 6379 |
Struktur Projek
prestijProject/
├── docker-compose.yml # Dev environment (6 containers)
├── docker-compose.prod.yml # Production VPS deployment
├── .env.example # Template env vars
├── .env # Actual env vars (jangan commit!)
│
├── frontend/
│ ├── Dockerfile
│ ├── package.json
│ ├── vite.config.js # Vite + PWA + proxy config
│ ├── tailwind.config.js # Custom space theme colors + animations
│ ├── index.html
│ └── src/
│ ├── App.jsx # Router + PrivateRoute
│ ├── main.jsx
│ ├── index.css # Tailwind base
│ │
│ ├── api/
│ │ └── client.js # Axios instance + JWT interceptor
│ │
│ ├── store/
│ │ ├── authStore.js # Zustand: token, user, logout
│ │ └── progressStore.js # Zustand: unit progress (persisted)
│ │
│ ├── hooks/
│ │ ├── useTTS.js # Web Speech API wrapper (ms-MY)
│ │ └── useTimer.js # Flash timer helper
│ │
│ ├── components/
│ │ ├── common/
│ │ │ ├── SpaceBackground.jsx # 80 animated stars SVG
│ │ │ └── KaptenNuri.jsx # Parrot SVG + speech bubble
│ │ │
│ │ └── units/unit1/
│ │ ├── Introduction.jsx # Intro screen + TTS
│ │ ├── Interactive.jsx # Touch meteors → colour change → number
│ │ ├── FlashTraining.jsx # Flash timer + answer grid + score
│ │ └── exercises/
│ │ ├── Exercise1.jsx # Corak rawak (random dots)
│ │ ├── Exercise2.jsx # Garis nombor (number line)
│ │ ├── Exercise3.jsx # Petak 10 (10-frame grid)
│ │ └── Exercise4.jsx # Jari robot (robot fingers)
│ │
│ └── pages/
│ ├── Landing.jsx # Home page
│ ├── Login.jsx # Email login form
│ ├── Register.jsx # Registration (Murid/Guru)
│ ├── Dashboard.jsx # Unit cards + progress + unlock logic
│ └── Unit1Page.jsx # Unit 1 orchestrator (intro→interactive→training→complete)
│
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ └── src/
│ ├── index.js # Express app entry
│ ├── config/
│ │ ├── db.js # PostgreSQL pool
│ │ └── redis.js # Redis client
│ ├── middleware/
│ │ └── authMiddleware.js # JWT verify
│ └── routes/
│ ├── auth.js # POST /register, POST /login
│ └── progress.js # GET /, POST /attempt, POST /complete
│
├── database/
│ └── init.sql # PostgreSQL schema (auto-run on first start)
│
└── nginx/
├── Dockerfile
├── nginx.conf # Dev: proxy ke Vite + backend
└── nginx.prod.conf # Prod: SSL, gzip, SPA fallback, cache headers
Setup & Jalankan (Dev)
Prerequisites
- Node.js 20 LTS
- Docker Desktop (WSL2 backend)
- Git
Langkah-langkah
# 1. Clone & masuk folder
cd prestijProject
# 2. Copy env file
cp .env.example .env
# Edit .env — tukar password ikut suka
# 3. Build & run semua containers
docker compose up --build
# App akan available di:
# http://localhost ← main app (via nginx)
# http://localhost:5173 ← frontend direct (Vite HMR)
# http://localhost:4000 ← backend API direct
Frontend Dev Tanpa Docker (preview sahaja)
cd frontend
npm install
npm run dev
# App kat http://localhost:5173
# Note: backend features (login/register) perlu Docker running
Docker Compose
Development (docker-compose.yml)
# 6 containers:
# nginx → reverse proxy port 80
# frontend → Vite dev server port 5173 (hot reload)
# backend → Node.js API port 4000
# postgres → Database port 5432
# redis → Cache port 6379
# Start semua
docker compose up --build
# Start background
docker compose up -d
# Stop
docker compose down
# Tengok logs
docker compose logs -f backend
docker compose logs -f postgres
# Reset database (CAREFUL — delete all data)
docker compose down -v
docker compose up --build
Production (docker-compose.prod.yml)
# Build frontend as static files, serve via nginx
docker compose -f docker-compose.prod.yml up -d --build
Deploy ke VPS (Prod)
Requirements VPS
- Ubuntu 22.04 / 24.04
- Min 1GB RAM (2GB recommended)
- Docker + Docker Compose installed
- Domain name (optional, boleh guna IP terus)
Step-by-step
# 1. SSH masuk VPS
ssh root@<VPS_IP>
# 2. Install Docker
curl -fsSL https://get.docker.com | sh
apt install docker-compose-plugin -y
# 3. Clone projek ke VPS
git clone <repo-url> /opt/dnuri
cd /opt/dnuri
# 4. Setup environment
cp .env.example .env
nano .env # Tukar semua password!
# 5. SSL certificate (Let's Encrypt)
# Letak cert.pem dan key.pem dalam folder ssl/
# 6. Deploy
docker compose -f docker-compose.prod.yml up -d --build
# 7. Verify running
docker compose -f docker-compose.prod.yml ps
curl http://localhost/api/health
Environment Variables (Production)
POSTGRES_USER=dnuri_user
POSTGRES_PASSWORD=<strong-password-min-16-chars>
POSTGRES_DB=dnuri_db
JWT_SECRET=<random-32-char-string>
JWT_REFRESH_SECRET=<random-32-char-string>
Generate random secrets:
openssl rand -base64 32
5 Unit Pembelajaran
| Unit | Tajuk | Status | Kemahiran |
|---|---|---|---|
| 1 | Pengamatan Kuantiti | ✅ Siap | Subitizing 1–6 tanpa mengira |
| 2 | Kepekaan Nombor | 🔒 Belum build | Perbandingan "lebih banyak" |
| 3 | Item Padanan | 🔒 Belum build | 1-to-1 matching, sama banyak |
| 4 | Penghitungan Titik | 🔒 Belum build | Kira titik, simbol 1–10 |
| 5 | Perbandingan Nombor | 🔒 Belum build | Mana lebih besar (2 angka) |
Unit 1 — Pengamatan Kuantiti (Subitizing)
Murid dilatih mengecam kuantiti 1–6 secara spontan dalam masa kurang 3 saat tanpa mengira satu-per-satu.
3 Fasa:
- Pengenalan — Kapten Nuri perkenalkan diri, TTS auto-play, butang roket
- Interaktif — Sentuh meteor satu-satu → tukar warna → nombor muncul
- Latihan Kilat — 4 jenis latihan dengan flash timer 2 saat:
- Exercise 1: Corak rawak (random meteor pattern)
- Exercise 2: Garis nombor (number line dots)
- Exercise 3: Petak 10 (10-frame grid)
- Exercise 4: Jari robot (robot finger hands, 1–6)
Unlock Logic: Unit N akan unlock apabila Unit N-1 completed.
API Reference
Base URL: http://localhost/api (dev) atau https://domain.com/api (prod)
Auth
POST /auth/register
Body: { name, email, password, role: "student"|"teacher" }
Response: { token, user: { id, name, email, role } }
POST /auth/login
Body: { email, password }
Response: { token, user: { id, name, email, role } }
Progress (requires Bearer token)
GET /progress
Response: [ { id, unit_id, exercise, correct_count, attempt_count, completed } ]
POST /progress/attempt
Body: { unit_id, exercise, correct: true|false }
Response: { ok: true }
POST /progress/complete
Body: { unit_id }
Response: { ok: true }
GET /health
Response: { status: "ok", service: "D-NuRI API" }
Database Schema
-- Users table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(120) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) DEFAULT 'student', -- student | teacher | admin
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Progress table
CREATE TABLE progress (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
unit_id INTEGER NOT NULL,
exercise INTEGER DEFAULT 0,
correct_count INTEGER DEFAULT 0,
attempt_count INTEGER DEFAULT 0,
completed BOOLEAN DEFAULT false,
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE (user_id, unit_id, exercise)
);
PWA Features
App boleh diinstall kat phone/tablet macam native app.
| Feature | Details |
|---|---|
| Manifest | name, icons, theme_color, display: standalone |
| Service Worker | vite-plugin-pwa + Workbox (auto-update) |
| Offline | Static assets cached, API NetworkFirst (10s timeout) |
| Icons | 192×192 dan 512×512 PNG |
| Orientation | Portrait (portrait-primary) |
Install PWA
- Android Chrome: Menu → "Add to Home Screen"
- iOS Safari: Share → "Add to Home Screen"
- Desktop Chrome: Address bar → install icon
Roadmap
Phase 1 ✅
- Unit 1 lengkap (Introduction + Interactive + 4 Exercises)
- Auth system (register/login JWT)
- Progress tracking (Zustand + API sync)
- PWA setup
- Docker Compose (dev + prod)
Phase 2 ✅
- Unit 2: Kepekaan Nombor (biskut coklat comparison)
- Unit 3: Item Padanan (1-to-1 matching)
- Scaffolding / hint system untuk setiap unit (corrective TTS hint lepas jawapan salah)
Teacher dashboard— skipped (2026-09-14): app ni untuk satu murid je buat masa ni, tak perlu multi-student view.teacherrole masih wujud dalam DB/register kalau nak sambung balik nanti.
Phase 3 ✅ (2026-09-14)
- Unit 4: Penghitungan Titik
- Unit 5: Perbandingan Nombor
- Unit 6: Banding Nombor (Besar vs Kecil)
- Unit 7: Operasi Tambah — bonus, luar skop asal
- Certificate / badge system —
badgestable (1–3 bintang ikut ketepatan), sijil boleh cetak (CertificateReveal.jsx, gallery kat/certificates) - Analytics dashboard —
/analytics: ketepatan ikut unit, masa belajar, trend aktiviti 14 hari (activity_logtable) - Pre-recorded audio (ganti TTS) — belum buat; ini kerja rakam audio/content, bukan kerja code. TTS Web Speech API sedia ada masih jalan elok.
Phase 4 (dicadangkan — belum dibina)
Modul tambahan berasaskan kaedah intervensi dyscalculia yang terbukti (concrete→pictorial→abstract, subitizing, number sense):
- Unit 8 — Rakan 10 (Number Bonds to 10): penguraian/gabungan nombor (contoh: "7 + berapa = 10?") — asas penting sebelum tambah/tolak sebenar
- Unit 9 — Tambah & Tolak Ringkas (dalam 10): guna pendekatan konkrit→gambar→simbol (CPA), sambung terus dari Unit 7
- Unit 10 — Garis Nombor & Nilai Tempat: anggaran kedudukan pada garis nombor + konsep puluh/sa (bundling visual)
- Working-memory mini-games (ingat & ulang urutan) — kerap jadi cabaran khusus untuk murid dyscalculia, berasingan dari number sense
Built with ❤️ untuk murid-murid diskalkulia Malaysia