netops/netops-todo-server/CLAUDE.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

180 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NetOps To-Do — Handoff / Project context
> Også egnet som `CLAUDE.md` for fremtidige Claude-sesjoner som jobber videre med koden.
> **Merk (2026-06-12):** Det finnes nå en videreutviklet Node/npm-versjon i
> `../netops-todo-node/` med WebSocket-sanntidssynk, kanban-tavle, kommentarer,
> aktivitetslogg og konfliktdeteksjon. Se `CLAUDE.md` der. Denne PHP-versjonen
> beholdes som den er for ren Apache/mod_php-hosting.
## Hva er dette
En enkel, selvstendig to-do-applikasjon tilpasset en network engineer som jobber bredt: L1 felt-kabling, L2 switching, L3 ruting, L4 lastbalansering, BGP, peering, security, NMS, automatisering, dokumentasjon, incident og prosjekt. Hver oppgave har prioritet (P1P4), estimert tid, status, lokasjon/site, frist, tags og eier.
Det finnes **to versjoner** levert i samme arbeidsstrøm:
| Versjon | Fil | Lagring | Bruksområde |
|---|---|---|---|
| Standalone | `netops-todo.html` (ligger ved siden av denne mappa) | `localStorage` i nettleseren | Personlig bruk på én maskin, ingen server nødvendig |
| Server / Apache | Hele `netops-todo-server/`-mappa | `data/tasks.json` på server, fil-låst | Delt for et team, auth i Apache eller proxy |
Server-versjonen er der man kommer til å være etter første "single user, deretter delt"-overgang.
## Filer i server-pakka
```
netops-todo-server/
├── index.php Frontend (HTML + JS). Tynt PHP-lag øverst leser brukernavn fra Apache.
├── api.php REST-API (single file). Alle actions ligger i én switch.
├── seed.json 16 eksempel-oppgaver. Lastes via "Last inn eksempel-data"-knappen.
├── .htaccess Auth-skeleton + sperrer data/ for direkte web-tilgang.
├── data/
│ ├── .htaccess Nekter all web-tilgang til lagringskatalogen.
│ ├── tasks.json Opprettes av api.php ved første skriv. Liste av task-objekter.
│ └── known_users.json Liste over brukere som har vært innom (for owner-dropdown).
├── INSTALL.txt Installasjonsguide for Apache.
└── CLAUDE.md (denne filen)
```
## Arkitektur
Frontend er én HTML-side med vanilig JS (ingen rammeverk) og Chart.js fra CDN.
Backend er to PHP-filer, null dependencies, kjører rett på Apache mod_php / php-fpm.
### Dataflyt
1. Apache autentiserer brukeren (Basic Auth, ekstern proxy, eller hva enn man velger).
2. `index.php` leser `REMOTE_USER` / `PHP_AUTH_USER` / `HTTP_X_REMOTE_USER`, injiserer det i siden som `CURRENT_USER`.
3. JS kaller `api.php?action=list` ved oppstart, så `create` / `update` / `delete` ved endringer.
4. `api.php` validerer input mot whitelister, normaliserer task-objektet, og skriver `data/tasks.json` med `flock(LOCK_EX)`.
5. Hvert minutt pollere frontend `list`-endepunktet for å hente endringer fra andre brukere.
### API
Alle endepunkt: `POST api.php?action=<name>` med JSON-body. `list` godtar også GET.
| Action | Body | Svar |
|----------|---------------------|--------------------------------------------|
| list | — | `{ user, tasks: [...], known_users: [...] }` |
| create | task uten id | `{ task }` (med tildelt id og audit-felt) |
| update | task med id | `{ task }` |
| delete | `{ id }` | `{ ok: true }` |
| replace | array av tasks | `{ ok: true, count }` (for import) |
| seed | — | `{ ok: true, count }` (kun hvis db er tom) |
### Task-skjema (kanonisk form)
```json
{
"id": "t_abc123",
"title": "string ≤200",
"desc": "string ≤4000",
"category": "L1|L2|L3|L4|BGP|PEER|SEC|NMS|AUTO|DOC|INC|PROJ",
"priority": "P1|P2|P3|P4",
"status": "todo|progress|blocked|done",
"estHours": 0,
"location": "string ≤120",
"deadline": "YYYY-MM-DD eller tom",
"tags": ["≤20 strings, hver ≤40"],
"owner": "brukernavn eller tom = utildelt",
"created": "ISO timestamp",
"createdBy": "brukernavn",
"updated": "ISO timestamp",
"updatedBy": "brukernavn",
"completed": "YYYY-MM-DD eller null",
"completedBy": "brukernavn eller null"
}
```
`normalize_task()` i `api.php` er kilden til sannhet. Den whitelister enums, klamper strenger, valider deadline-format, og setter audit-feltene automatisk basert på `current_user()`.
## Designvalg som er verdt å vite
- **Ingen database.** JSON-fil + `flock` holder fint helt opp i tusenvis av oppgaver. Hvis det skulle bli ytelsestrøbbel, er det enkleste å bytte til SQLite (PHP `pdo_sqlite` følger med).
- **Auth utenfor koden.** Innloggings-logikk er bevisst utelatt. Apache / proxy gjør jobben. Det gjør at koden er trivielt enkel å revidere og bytte ut.
- **Felles datalager, ikke per-bruker.** Brukerne ser samme oppgaveliste, men `owner` per oppgave + audit-felt gir attribusjon.
- **No-framework frontend.** Holdt bevisst gammeldags vanlig JS for at det skal være lett å patche av neste vakthavende.
- **Polling, ikke websocket.** En `list`-request hvert 60s er nok for et team. Hvis flere skal jobbe samtidig kan intervallet senkes, men brukerne kan også trykke ↻.
## Sikkerhetsstatus
| Risiko | Tiltak |
|---|---|
| XSS i task-tekst | `escapeHtml()` i alle render-paths, `htmlspecialchars()` for brukernavn i PHP |
| Path traversal | Filsti er hardkodet (`__DIR__ . '/data/tasks.json'`), ingen brukerinput i path |
| Direct read av tasks.json | Egen `.htaccess` i `data/` med `Require all denied` |
| Race conditions | `flock(LOCK_EX)` ved skriving, `LOCK_SH` ved lesing |
| Injection i enums | Whitelist-validering: `in_array($val, $VALID_*, true)` |
| Sanitering av brukernavn | `preg_replace('/[^A-Za-z0-9._@\-]/', '', $user)`, maks 64 tegn |
| CSRF | Ikke håndtert eksplisitt. For en intern admin-side bak proxy med Basic Auth er det typisk akseptabelt, men hvis det monteres på offentlig nett bør det legges til en `X-Requested-With`-sjekk eller token. |
## Vanlige utvidelser
Hvis du jobber videre med dette, dette er de mest sannsynlige neste stegene og hvor du putter dem:
**Nye kategorier eller prioriteter:**
- Frontend: legg til i `CATEGORIES`-array og `CAT_COLORS`-map i `index.php` (JS-delen).
- Backend: legg til i `$VALID_CATEGORIES` / `$VALID_PRIORITIES` i `api.php`.
**Nytt felt per oppgave:**
- Legg til input i modal i `index.php`.
- Plukk opp i `saveForm()` (JS) og send med i body.
- Legg til i `normalize_task()` (PHP) med passende sanitering.
- Vis det i `renderTable()` om ønskelig.
**Bedre samarbeid:**
- Server-Sent Events fra PHP: ny `?action=stream` som holder en åpen koblet med `Cache-Control: no-cache`, sjekker fil-mtime og pusher endringer.
- Eller bare senke `setInterval(loadAll, 60000)` i `init()`.
**Audit-logg / historikk:**
- I `normalize_task()` legg til append til `data/audit.log` med `[$updatedBy] $action $taskId`.
- Vis logg under hver oppgave-modal med en ny `?action=history&id=...`.
**Per-bruker syn:**
- Endre `list` til å filtrere på `$user` hvis et flagg er satt.
- Eller bare la frontend defaulte filter "Eier=Meg" — enklere.
**SQLite-migrering** (hvis JSON blir tregt):
- Bytt `read_tasks()` og `write_tasks()` mot PDO-kall.
- Skjemaet matcher allerede et fornuftig SQL-skjema.
## Kjente begrensninger
- Ingen optimistisk locking på enkeltoppgave-nivå. Hvis to brukere lagrer samme oppgave samtidig, vinner den siste. Dette er hentet inn ved at filen i sin helhet låses, men man får ikke conflict-deteksjon.
- Ikke i18n. Norsk er hardkodet i UI. Strings er samlet, så det er ikke vondt å trekke ut.
- Ingen pagination i tabellen. Fungerer fint opp til noen hundre åpne oppgaver, deretter bør man legge til virtual scrolling eller side-knapper.
- Klokken nederst i hover er klient-tid, ikke server-tid.
## Testing-status
- PHP-syntaks verifisert med AST-parser (`php-parser` via node, PHP 8-modus).
- Kryssreferanse JS ↔ PHP: alle `api('X')`-kall fra frontend har matchende `case 'X':` i api.php.
- Kryssreferanse DOM-IDer ↔ JS: alle `getElementById('x')` har matchende `id="x"` i HTML.
- Onclick-handlere ↔ funksjonsdefinisjoner: ingen referanser til udefinerte funksjoner.
- Ikke kjørt end-to-end (sandbox manglet PHP-runtime). Første ekte test bør være: `php -S localhost:8080` i mappa og åpne i nettleser.
## Hurtigreferanse — installasjon
```bash
# 1. Kopier til server
sudo cp -r netops-todo-server /var/www/netops-todo
# 2. Skriverettigheter for data/
sudo chown -R www-data:www-data /var/www/netops-todo/data
sudo chmod 750 /var/www/netops-todo/data
# 3. Basic Auth-brukere (utenfor docroot!)
sudo htpasswd -c /etc/apache2/netops.htpasswd jon
sudo htpasswd /etc/apache2/netops.htpasswd kari
# 4. Aktiver auth-blokken i .htaccess (kommenter ut linjene under "1) Basic Auth")
sudo nano /var/www/netops-todo/.htaccess
# 5. Sørg for at AllowOverride All er aktivt i vhost
# <Directory /var/www/netops-todo>
# AllowOverride All
# Require all granted
# </Directory>
sudo systemctl reload apache2
# Åpne http://din-server.no/netops-todo/ → "Last inn eksempel-data"
```
Se `INSTALL.txt` for fyldigere variant og feilsøking.