65 lines
3.0 KiB
Markdown
65 lines
3.0 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```json
|
|
{
|
|
"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 from
|
|
`sessions` rows with `ended_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_stats`** is 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`, so `ORDER BY created_at DESC` sorts
|
|
correctly without needing SQLite's more limited native datetime type.
|