Files
InsanityLab-web/docs/superpowers/specs/2026-07-25-campus-design.md
T
2026-07-25 15:40:07 +02:00

5.4 KiB
Raw Blame History

Sezione Campus — design

Data: 2026-07-25 · Branch: feature/campus · Stato: approvato (approccio A)

Obiettivo

Integrare le guide di studio del corso Biohacking Campus (progetto esterno /data/Sorgenti/AI-OS/projects/personale/biohacking-campus) come sezione riservata del sito InsanityLab, visibile soltanto agli utenti autenticati con un ruolo dedicato. Le pagine devono adottare lo stile grafico del sito (font, colori, CSS globale), non quello del generatore statico originale.

Requisiti

  1. Nuovo ruolo campus: vede soltanto la sezione /campus; nessun accesso al pannello admin. admin accede a tutto. superuser e user non accedono alla sezione campus.
  2. Generazione contenuti: uno script legge le guide sorgente (*.studio.md) dal progetto biohacking-campus e produce i contenuti nel repo del sito. Rigenerabile a ogni aggiornamento del corso.
  3. Gestione utenti: la pagina /admin/users esistente deve permettere di creare/assegnare il ruolo campus.
  4. Navigazione dedicata: dentro /campus non compaiono Header e Footer del sito; navigazione propria (sidebar aree/capitoli) più un solo richiamo "← Torna alla home" verso /.
  5. Protezione totale: pagine e immagini (assets slide) mai servite a utenti non autorizzati.

Architettura

Ruoli e accessi (src/lib/auth.ts, src/middleware.ts)

  • Role = 'admin' | 'superuser' | 'user' | 'campus'.
  • RULES esteso: /campus/*['campus', 'admin'] (admin passa sempre già oggi per short-circuit).
  • Middleware: /campus/* diventa percorso protetto (oltre a /admin, /api/admin). Non autenticato → redirect a /admin/login.
  • landingFor('campus')/campus. La pagina di login rimandava sempre a /admin: ora usa landingFor sul ruolo dell'utente appena autenticato, così ogni ruolo atterra su una pagina che può davvero aprire.
  • Il ruolo campus NON deve accedere ai percorsi comuni dei loggati del pannello (blog admin, upload): canAccessAdminPath ritorna false per campus su /admin/* e /api/admin/* non esplicitamente consentiti.
  • /admin/users: aggiunta option campus nelle due select (nuovo utente, cambio ruolo).

Sync contenuti (scripts/sync-campus.mjs)

  • Input: root del progetto biohacking-campus (arg CLI, default il path locale di sviluppo).
  • Porta la struttura dati del generatore Python (CHAPTERS, AREAS, regex intestazioni) in JS. Legge i *.studio.md da studio/, qa/, slide/, accelerator/, lezioni-live/, speaker/, consulenze/, masterclass/.
  • Converte markdown → HTML con marked (nuova devDependency) e riscrive i riferimenti alle immagini slide verso /campus/assets/....
  • Output in campus-content/ (root repo, committato):
    • nav.json — aree, capitoli, lezioni ordinate (slug, titolo, sottotitolo, docente, prev/next). La catena prev/next segue l'ordine di navigazione aree → capitoli → guide, non la numerazione dei capitoli: le aree li raggruppano in un ordine diverso;
    • pages/<slug>.html — frammento HTML del corpo di ogni guida;
    • assets/ — immagini slide copiate (~37 MB, commit una tantum).
  • Idempotente: rigenera tutto e rimuove i file orfani.

Rendering (src/pages/campus/, src/layouts/Campus.astro)

  • Campus.astro: usa global.css e i font del sito; nessun Header/Footer; sidebar con aree/capitoli/lezioni (voce corrente evidenziata) e link "← Torna alla home"; responsive con menu mobile.
  • Route SSR (runtime, non prerender — servono i file in campus-content/):
    • /campus — portale con le card delle aree (da nav.json);
    • /campus/[...slug] — pagina area (indice capitoli) o pagina guida (frammento HTML + breadcrumb + prev/next). Slug non trovato → 404.
  • /campus/assets/[...path] — endpoint che serve le immagini da campus-content/assets/ (protetto dal middleware come tutto /campus); path traversal rifiutato; Content-Type da estensione; cache privata.
  • Lettura file a runtime da CAMPUS_DIR (env, default ./campus-content), con cache in memoria di nav.json.

Deploy (Dockerfile)

  • Lo stage runtime copia solo dist e scripts; si aggiunge COPY --from=build /app/campus-content ./campus-content.
  • /app/data e /app/uploads sono volumi: campus-content/ resta fuori da entrambi, dentro l'immagine. Nessuna modifica a compose.yaml.

Error handling

  • campus-content/ assente (sync mai eseguito): /campus risponde 404 con messaggio esplicito nei log; il resto del sito non è impattato.
  • Slug o asset inesistente → 404. Path traversal su assets → 400.
  • Sync: file .studio.md con intestazione non riconosciuta → warning e skip, exit code ≠ 0 solo per errori I/O.

Testing

  • tests/auth-campus.test.ts: matrice ruoli × percorsi (campus su /campus sì, su /admin/content no; user su /campus no; ecc.), landingFor, isRole('campus').
  • tests/sync-campus.test.ts: parsing intestazioni (lezione, Q&A, slide, accelerator, consulenza, masterclass, speaker), generazione nav e frammenti su fixture minima, riscrittura path immagini.
  • Verifica manuale: login con utente campus (vede solo campus), user (non vede campus), navigazione sidebar, immagini slide, mobile.

Fuori scope

  • Nessun tracciamento progressi/completamento lezioni.
  • Nessuna ricerca full-text.
  • Nessuna migrazione automatica degli utenti esistenti al nuovo ruolo.