175 lines
8.7 KiB
Markdown
175 lines
8.7 KiB
Markdown
# NetOps To-Do — Handoff / Project context
|
||
|
||
> Også egnet som `CLAUDE.md` for fremtidige Claude-sesjoner som jobber videre med koden.
|
||
|
||
## 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 (P1–P4), 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.
|