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

8.9 KiB
Raw Blame History

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)

{
  "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

# 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.