3.0 KiB
3.0 KiB
api
Minimal Express + SQLite API to back the TACHYON site's dynamic sections (News, Media, and the Overview/Statistics panel — current users, recent activity, general stats).
Stack
- Express — HTTP layer
- better-sqlite3 — synchronous SQLite driver, no separate DB process to run
- Plain SQL (no ORM) — the schema is small enough that raw
.prepare()calls stay readable; swap in Drizzle/Prisma later if it grows
Setup
npm install
npm run db:init # creates db/tachyon.db and applies schema.sql
npm run db:seed # (optional) fills it with placeholder rows matching the mockup
npm run dev # starts on http://localhost:3000, restarts on file changes
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Liveness check |
| GET | /api/news?limit=20 |
List news posts, newest first |
| POST | /api/news |
Create a post — { title, content } |
| DELETE | /api/news/:id |
Delete a post |
| GET | /api/media?limit=24 |
List media items, newest first |
| POST | /api/media |
Add media — { title, media_type, url } |
| DELETE | /api/media/:id |
Delete a media item |
| GET | /api/stats/overview |
Bundled currentUsers + recentActivity + general |
| GET | /api/stats/users |
Just the current-users list |
| POST | /api/stats/session/start |
{ username } — opens a session (marks online) |
| POST | /api/stats/session/end |
{ sessionId } — closes a session |
/api/stats/overview is the one the frontend's Overview panel would call —
it returns everything needed for the three stat columns in one round trip:
{
"currentUsers": [{ "id": 1, "username": "...", "started_at": "..." }],
"recentActivity": [{ "id": 1, "description": "...", "created_at": "..." }],
"general": {
"users": { "total": 3, "mostRecent": { "username": "...", "id": 3 } },
"reports": { "named": "00", "associated": "00", "logged": "00" },
"build": { "pipeline": "Completed", "buildNumber": "00000000", "version": "0.0.0" }
}
}
Schema notes
- "Current users" isn't a boolean flag on
users— it's derived fromsessionsrows withended_at IS NULL. That way "who's online right now" falls naturally out of a query instead of needing a background job to flip a flag, and you get session history for free. site_statsis a plain key/value table for the "General Statistics" cards (build number, version, report counts) since those are free-form and don't need their own table each.- Timestamps are ISO-8601
TEXT, soORDER BY created_at DESCsorts correctly without needing SQLite's more limited native datetime type.