Live school timetable for S2-05, SST Singapore — Term 2 2026.
Production: https://timetable.edmundlim.systems
Testing: https://testing.timetable.edmundlim.systems
Admin: https://timetable.edmundlim.systems/admin
- Live timetable — odd/even week toggle with auto-detection from term calendar
- Now bar — highlights the current class and counts down to the next one
- Exam countdown — amber bar appears within 7 days of each exam
- Schedule overrides — admin marks specific dates as holidays or one-off custom days
- Announcements — admin posts class-wide notices; new ones pop up as toasts within 10 s
- Personal journal — free-form notes saved on-device, side-by-side with announcements
- Subject notes — per-cell sticky notes, also on-device
- PWA — installable, works offline with cached data
- Demo mode — preview any day/week combination from settings
| Layer | Tech |
|---|---|
| Frontend | Vanilla HTML + CSS + JS — no build step |
| API | Node.js + Express (server.js) |
| Storage | Local JSON file (data/timetable-data.json), atomic write via tmp + rename |
| Auth | JWT (HS256) in an HTTP-only cookie, bcrypt password hashing |
| Hosting | Hack Club Nest (free Linux LXC container), managed by PM2 |
Static site only (API calls won't work without env vars):
open index.htmlWith the API (requires a .env file — see .env.example):
npm install
npm startRequired environment variables (copy .env.example → .env):
| Variable | Description |
|---|---|
PORT |
3000 for local dev (production uses 80) |
ADMINS_JSON |
[{"username":"...","passwordHash":"..."}] |
JWT_SECRET |
32-byte random hex |
To generate a password hash:
node scripts/hash-password.js <password>| Branch | Deploys to | How |
|---|---|---|
dev |
testing.timetable.edmundlim.systems |
GitHub Actions → webhook → PM2 restart |
main |
timetable.edmundlim.systems |
GitHub Actions → webhook → PM2 restart |
Workflow: all new work goes on dev → open PR to main when ready → merge to ship.
The admin panel (/admin) lets authorised users:
- Edit the odd/even week timetable
- Toggle school day display between 3 PM and 5 PM
- Manage upcoming exam dates
- Post and delete class announcements
- Add schedule overrides (holidays, custom days)
Changes are live on the public site within 10 seconds.
Any Claude client can be given full admin access via the hosted MCP server — no local install required.
Claude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"timetable": {
"url": "https://mcp.timetable.edmundlim.systems/mcp",
"headers": {
"Authorization": "Bearer your-raw-token-here"
}
}
}
}Claude Code — .mcp.json in the repo root (gitignored):
{
"mcpServers": {
"timetable": {
"url": "https://mcp.timetable.edmundlim.systems/mcp",
"headers": {
"Authorization": "Bearer your-raw-token-here"
}
}
}
}Available tools: get_timetable, set_week, add_announcement, delete_announcement, add_exam, delete_exam, add_override, delete_override, add_custom_subject, delete_custom_subject, list_custom_subjects, save_timetable.
Tokens are managed via API_TOKENS_JSON in ~/.env on the server. See AGENTS.md for the full setup guide.
You can run your own instance of this app for any class with a repeating odd/even week schedule.
- Fork this repo on GitHub
- Get a server with Node.js — Hack Club Nest is free for students
- Clone your fork onto the server and run
npm install - Copy
.env.example→.envand fill in the variables - Start with PM2:
pm2 start ecosystem.config.cjs
| Variable | How to get it |
|---|---|
PORT |
80 for production (or any open port) |
JWT_SECRET |
Run node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" |
ADMINS_JSON |
Run node scripts/hash-password.js yourpassword, then format as [{"username":"you","passwordHash":"<hash>"}] |
Use the AGENT_SETUP.md file — fill in your class details and hand it to Claude (or any AI coding assistant) to update the code and seed data automatically.
Or do it manually:
- Edit
TIMETABLEinscript.js(odd/even week, Mon–Fri blocks) - Update
TERM_STARTandTERMS_2026for your school's calendar - Update
ABBREVand subject colours instyle.cssto match your subjects - Edit
EXAMSinapi/_lib/seed.jsfor your exam schedule
Point a CNAME at your server's hostname (or an A record at its IP) in your DNS provider.