netops/netops-todo-node/README.md
Jon Vanvik 6b9dbf8254 Legg til Node/npm-versjon med sanntidssynk + Debian 13-oppsettsskript
Ny app i netops-todo-node/: Express + ws, WebSocket-push i stedet for
polling, kanban med drag & drop, kommentarer, aktivitetslogg, optimistisk
låsing, quick-add-parsing og presence. 12 integrasjonstester (node:test).
setup-debian13.sh setter opp alt på en fersk LXC; README dekker Nginx
Proxy Manager-oppsett. PHP-versjonen er uendret (kun handoff-peker).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 11:54:22 +02:00

179 lines
6.2 KiB
Markdown

# NetOps To-Do (Node-versjon)
Sanntids oppgavetavle for et nettverksdrift-team. Node + Express + WebSockets.
Endringer fra én bruker dukker opp hos alle andre umiddelbart — ingen polling,
ingen manuell refresh.
## Kom i gang
```bash
npm install
npm start # → http://localhost:3000
```
Utvikling med auto-restart ved kodeendring:
```bash
npm run dev
```
Tester:
```bash
npm test
```
## Miljøvariabler
| Variabel | Default | Beskrivelse |
|---|---|---|
| `PORT` | `3000` | HTTP-port |
| `HOST` | `0.0.0.0` | Lytteadresse |
| `DATA_DIR` | `./data` | Katalog for tasks.json / activity.json / users.json |
| `DISABLE_COOKIE_AUTH` | (av) | Sett til `1` for å skru av selvvalgt navn via cookie — da gjelder kun proxy-headere |
## Autentisering
Påloggingslogikk er bevisst holdt utenfor appen. Brukernavn hentes fra,
i prioritert rekkefølge:
1. `X-Remote-User`-header — satt av reverse proxy (oauth2-proxy, Authelia, …)
2. `Authorization: Basic` — Basic Auth terminert i proxy, brukernavnet gjenbrukes
3. `netops_user`-cookie — selvvalgt navn via "Sett navn"-knappen (hjemme/dev-bruk)
4. `anon`
For team-bruk bak proxy: sett `DISABLE_COOKIE_AUTH=1` så ingen kan velge navn selv.
## Rask installasjon på Debian 13 (LXC/VM)
```bash
# Som root i containeren:
apt-get update && apt-get install -y git
git clone <din-remote> /opt/netops
bash /opt/netops/netops-todo-node/setup-debian13.sh
```
`setup-debian13.sh` installerer Node fra apt, kjører `npm ci` og setter opp
systemd-tjenesten (`DynamicUser` + `StateDirectory`, data i
`/var/lib/netops-todo`). Kjør skriptet på nytt etter `git pull` for å
oppgradere. Med proxy-auth: `DISABLE_COOKIE_AUTH=1 bash setup-debian13.sh`.
## Bak reverse proxy
WebSocket-endepunktet er `/ws` og krever upgrade-støtte i proxyen.
Appen må ligge på **rota av et (sub)domene** (f.eks. `todo.hjemme.lan`) —
frontend bruker absolutte stier, så sti-prefiks (`proxy.lan/todo/`) fungerer ikke.
### Nginx Proxy Manager
1. **Hosts → Proxy Hosts → Add Proxy Host**
- *Domain Names:* `todo.dittdomene.no`
- *Scheme:* `http` · *Forward Hostname/IP:* LXC-ens IP · *Forward Port:* `3000`
- **Websockets Support: PÅ** (påkrevd — sanntidssynken bruker `/ws`)
- *Cache Assets:* AV (ellers kan gammel `app.js` serveres etter oppgradering)
- *Block Common Exploits:* valgfritt, fungerer fint sammen med appen
2. **SSL-fanen:** *Request a new SSL Certificate* (Let's Encrypt) + *Force SSL*.
Frontend bytter selv til `wss:` når siden er https.
3. **Auth (valgfritt):** *Access Lists* → lag liste med brukere (Basic Auth) og
knytt den til proxy-hosten. NPM/nginx sender `Authorization`-headeren videre,
og appen bruker brukernavnet derfra — da får hver kollega riktig attribusjon.
Sett i så fall `DISABLE_COOKIE_AUTH=1` på tjenesten. Uten access list velger
folk navn selv i UI-et (cookie).
**nginx:**
```nginx
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Remote-User $remote_user; # ved basic auth i nginx
}
```
**Apache** (`mod_proxy_wstunnel`):
```apache
ProxyPass /ws ws://127.0.0.1:3000/ws
ProxyPassReverse /ws ws://127.0.0.1:3000/ws
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
RequestHeader set X-Remote-User %{REMOTE_USER}s
```
## Kjør som tjeneste (systemd)
```ini
# /etc/systemd/system/netops-todo.service
[Unit]
Description=NetOps To-Do
After=network.target
[Service]
# DynamicUser + StateDirectory: systemd lager bruker og /var/lib/netops-todo
# med riktige rettigheter automatisk — ingen useradd/chown nødvendig.
DynamicUser=yes
StateDirectory=netops-todo
WorkingDirectory=/opt/netops-todo
ExecStart=/usr/bin/node server.js
Environment=PORT=3000
# HOST=127.0.0.1 hvis proxyen kjører på samme maskin. Står proxyen i en annen
# container/host: fjern linjen (lytt på alt) og brannmur port 3000 til kun proxyen.
Environment=HOST=127.0.0.1
Environment=DATA_DIR=/var/lib/netops-todo
Environment=DISABLE_COOKIE_AUTH=1
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
## Funksjoner
- **Sanntidssynk** — alle endringer pushes til alle åpne faner via WebSocket
- **Presence** — se hvem som er pålogget akkurat nå
- **Kanban-tavle** med drag & drop mellom statuskolonner, pluss klassisk tabellvisning
- **Hurtig-registrering** med tokens: `Bytt SFP #l1 p2 @me !imorgen ~1h loc:DC-OSL-1`
- **Kommentarer** per oppgave
- **Aktivitetslogg** — hvem gjorde hva, når (sidepanel)
- **Konfliktdeteksjon** — versjonsnummer per oppgave; lagring fra utdatert
versjon avvises med tydelig varsel i stedet for stille overskriving
- **"Redigerer nå"-indikator** — ser om en kollega har samme oppgave åpen
- **Angre sletting** direkte fra toast
- KPI-er, grafer (kategori/prioritet/eier), filtre, sortering, søk
- Eksport/import av JSON, eksempeldata for demo
- Tastatursnarveier: `n` ny · `/` søk · `v` bytt visning · `a` aktivitet · `esc` lukk
## API
Alle endepunkt under `/api/`, JSON inn/ut. `v` er versjonsnummer for
optimistisk låsing — send med ved update, få 409 hvis noen andre har lagret.
| Metode | Endepunkt | Beskrivelse |
|---|---|---|
| GET | `/api/state` | Bruker, oppgaver, aktivitet, kjente brukere, hvem som er online |
| POST | `/api/tasks` | Opprett oppgave (`title` påkrevd) |
| PUT | `/api/tasks/:id` | Oppdater (delvis OK; send `v` for konfliktsjekk) |
| DELETE | `/api/tasks/:id` | Slett |
| POST | `/api/tasks/:id/comments` | Legg til kommentar `{ text }` |
| DELETE | `/api/tasks/:id/comments/:cid` | Slett egen kommentar |
| POST | `/api/replace` | Erstatt hele listen (import) |
| POST | `/api/seed` | Last eksempeldata (kun hvis tomt) |
| POST | `/api/login` | Sett navn-cookie (hvis cookie-auth er på) |
| GET | `/healthz` | Helsesjekk |
Eksempel:
```bash
curl -s -X POST localhost:3000/api/tasks \
-H 'Content-Type: application/json' \
-H 'X-Remote-User: jon' \
-d '{"title":"Sjekk BGP-sesjon mot AS2119","category":"BGP","priority":"P1"}'
```
## Lagring
JSON-filer i `DATA_DIR` (atomisk skriv via tmp-fil + rename, serialisert i
prosessen). Én node-prosess per datakatalog. Holder fint til tusenvis av
oppgaver; blir det trangt er SQLite (`node:sqlite`) neste naturlige steg.