Spike 50 parts board: photos, offline mode, mobile viewer, login page

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 11:31:46 +02:00
commit 9b9516026b
17 changed files with 1088 additions and 0 deletions

66
README.md Normal file
View File

@@ -0,0 +1,66 @@
# Spike 50 Parts Board (self-hosted)
Parts tracker for the 2005 Rieju Spike 50: factory drawings with clickable markers, status per part
(Have / Missing / Ordered / Not needed), notes, links and comments. Everything is stored on your server.
- Backend: one Node file (`server.js`), no npm packages. Uses Node 22's built-in SQLite.
- Data: `data/board.db` (SQLite) and `data/images/` (drawings you upload).
## Run with Docker (recommended)
```bash
# copy this folder to the server, then:
cd spike-board
mkdir -p data && sudo chown 1000:1000 data # the container runs as user "node" (uid 1000)
docker compose up -d --build
```
Open `http://<server-ip>:8085`.
To set a password, put one in `BOARD_PASSWORD` in `docker-compose.yml` and run `docker compose up -d` again.
The browser then asks for `BOARD_USER` / `BOARD_PASSWORD`.
## Run without Docker
Needs Node 22.13 or newer.
```bash
cd spike-board
node server.js # http://localhost:8080, data in ./data
PORT=9000 DATA_DIR=/srv/spike node server.js
```
## Reaching it from outside your home
Keep it on your LAN or VPN (Tailscale/WireGuard) if you can. If you put it behind a reverse proxy
(Caddy, Nginx Proxy Manager, Traefik) on the internet, set `BOARD_PASSWORD` and use HTTPS, because
basic auth sends the password with every request.
Caddy example:
```
spike.example.com {
reverse_proxy 127.0.0.1:8085
}
```
## Backup
Copy the `data/` folder (stop the container first for a guaranteed consistent copy), or click
**Download backup** in the page header for a JSON export of all statuses, notes, links, comments and markers.
## API
| Method | Path | Body |
| --- | --- | --- |
| GET | `/api/state` | |
| GET | `/api/export` | (same as state, as a download) |
| PUT | `/api/parts/{group}__{ref}` | `{"s":"have"\|"miss"\|"ord"\|"skip"\|"none","note":"…"}` |
| POST | `/api/parts/{group}__{ref}/links` | `{"url":"https://…","label":"…"}` |
| DELETE | `/api/links/{id}` | |
| POST | `/api/parts/{group}__{ref}/comments` | `{"text":"…"}` |
| DELETE | `/api/comments/{id}` | |
| PUT | `/api/drawings/{group}/pins` | `{"pins":{"12":[[x%,y%],…]}}` |
| POST | `/api/drawings/{group}/image` | raw image bytes, `Content-Type: image/png` (or jpeg/webp/gif) |
Groups: `chassis`, `controls-steer`, `electrics`, `exhaust-radiator-tank-airfilter`, `motord`, `plastics`, `suspension`, `wheels`.