Fra code review av ea07f34:
- /theme/* fikk max-age=1 år + immutable også uten ?v=; url("favicon.svg")
inne i CSS ville da sittet fast etter en temaendring. Nå bare med hash.
- asset() feiler ved bygging på ukjent temafil i stedet for å gi en
uversjonert URL i stillhet.
- rel() defineres én gang og gjenbrukes av asset(); dødt is_dir-guard
fjernet; docstring peker på asset() for temafiler.
- Tester: uversjonert forespørsel skal ikke være immutable; hash-format
sjekkes på nestede sider; ukjent asset gir feil.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Malene får asset('theme/style.css') som gir en relativ URL med
innholdshash (?v=…), beregnet ved bygging. Temafiler serveres nå med
max-age=1 år + immutable; URL-en endres når innholdet gjør det, så
besøkende får ny stil umiddelbart etter oppgradering.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Alle brukere kan skrive en valgfri beskrivelse (Markdown, uten rå HTML)
under Profil. /brukere/ lister hovedbruker øverst og gjester alfabetisk
etter visningsnavn; brukersiden viser navn, beskrivelse, e-post og
innlegg. Signaturen under innlegg lenker til brukersiden. «brukere» er
reservert. Siden bygges nå også når brukere opprettes/slettes.
Retter også ugyldig pattern-regex for brukernavn i admin.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Kommaseparert tagg-felt i editoren, lagret som liste i frontmatter
(dedup case-ufølsomt). /tag/<slug>/ lister alle innlegg med taggen,
også gjesters; /tag/ lister alle tagger med antall. Tagger vises som
piller på innlegg og i lister, som <category> i feeden og i sitemap.
«tag» er reservert som slug/brukernavn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Alle brukere kan sette visningsnavn og valgfri e-post under Profil i
admin. Innlegg avsluttes med «– Visningsnavn», med e-post som mailto-
lenke hvis satt. Frontmatter lagrer nå brukernavnet (stabilt), og
visningsnavn/e-post slås opp i brukertabellen ved bygging, så en
endring gjelder alle innlegg. Eldre innlegg med visningsnavn i author-
feltet vises uendret. Brukertabellen migreres automatisk (email).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
SOAPBOX_BIND er nå tom som standard = alle adresser, så Caddy på en
annen maskin når appen over Tailscale/MagicDNS uansett om navnet løses
til v4 eller v6. Waitress bandt bare 0.0.0.0 inne i containeren, så
IPv6-tilkoblinger via pasta ble avvist; nå brukes listen="*:8080"
(dual-stack). Verifisert mot maskinens Tailscale-IPv4 og -IPv6.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Standard 127.0.0.1 (Caddy lokalt). Kjører Caddy på en annen maskin over
Tailscale, settes SOAPBOX_BIND til denne maskinens Tailscale-IP så appen
bare lytter på tailnettet. Brukes av run.sh og compose.yaml; nytt
Caddyfile-eksempel for oppsettet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
https://domene.no/blog gir automatisk base-path /blog. SOAPBOX_BASE_PATH
beholdes kun som overstyring (tom verdi) for proxyer som stripper
prefikset. Dokumentasjon og Caddyfile-eksempel oppdatert; README hadde
også utdatert slug-eksempel og beskrivelse av SITE_URL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Før hver oppstart eksporteres datavolumet til
SOAPBOX_BACKUP_DIR/soapbox-data-<UTC-tidsstempel>.tar.gz; de
SOAPBOX_BACKUP_KEEP nyeste beholdes (standard 5, 0 = av). Bind-mounts
pakkes med tar, navngitte volum med podman volume export.
--restart unless-stopped byttet til --restart=always i run.sh og
compose.yaml: podman håndterer ikke unless-stopped som docker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
- sitemap.xml med forside, innlegg (lastmod) og gjesteoversikter.
- Open Graph/Twitter-kort på alle sider; innlegg får article-type,
utdrag som beskrivelse, første bilde som og:image og canonical.
Absolutte URL-er via SOAPBOX_SITE_URL.
- Historikk per innlegg kombinerer `git log --follow` på index.md med
loggen for mappen, så utkast-lagringer fra før slug-omdøpingen vises.
Diffen begrenses ikke lenger til nåværende sti av samme grunn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Merket øverst til venstre går nå til bloggens rot både i admin og på
selve bloggen (der var det allerede relativt til roten). «Innlegg» i
menyen dekker admin-listen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Forsiden viser første avsnitt av hvert innlegg som ren tekst (nytt
Jinja-filter `excerpt`, tilgjengelig for egne temaer). Favicon har
færre og større former med tykkere streker så det holder seg ved 16 px.
Siste to punkter fra UI-gjennomgangen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
WCAG:
- Mørk modus: --on-accent-token gir mørk tekst på lys aksent (knapper,
badges, valgt fane, skip-lenke) – var 1.8:1, nå ~11:1.
- Editor-feltet har label og aria-describedby; forhåndsvisningen er
ikke lenger aria-live (leste opp hele innlegget for hvert tastetrykk).
- Bilder settes inn med alt-plassholder markert for overskriving, som
eget avsnitt etter gjeldende linje.
- Berøringsmål ≥ 44px (nav, verktøylinje, lenkeknapper, select).
- Faner: roving tabindex + piltaster. Knapper med tekst i stedet for
emoji, aria-keyshortcuts på fet/kursiv. h1 på forsiden.
- code bryter lange stier (innstillinger rullet horisontalt på mobil).
UX:
- Ulagret-vakt dekker også tittelen, med synlig «Ulagrede endringer».
- 413 ved for stor fil gir lesbar melding; brukernavn beholdes ved
feil innlogging; full publiserings-URL vises i editoren; historikk-
lenke i meta-linjen; norsk datoformat i historikken; passord-hint.
Design:
- Header med favicon, større brødtekst/overskrifter, smalere måltekst,
bedre avstander i innlegg og liste, footer som flex uten løse «·»,
nøytral sekundærknapp, innrammet faresone, editor-textarea fyller
panelet, valgt fane henger sammen med panelet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Funn fra sikkerhetsgjennomgang:
- HØY: post_id ble ikke validert, så en gjest kunne nå andres innlegg
via gjest/../../posts/<slug> (lese utkast, laste opp/slette bilder,
publisere eierens utkast). Slug og gjestenavn valideres nå mot samme
alfabet de lages med, og stien sjekkes etter oppslag.
- Bilder: pikselantall sjekkes før dekoding (maks 40 MP), og
DecompressionBombError håndteres.
- Innlogging: CSRF-token kreves også på login (login-CSRF), og
innloggingsbrems etter 5 feil per brukernavn.
- Passordbytte ugyldiggjør alle andre sesjoner (stempel i cookien).
- Content-Security-Policy og X-Frame-Options på alle sider; admin har
ingen inline script lenger (admin.js).
- Gjestenavn og eier-slugs kan ikke lenger kollidere på /navn/.
- Healthcheck respekterer SOAPBOX_BASE_PATH; login-redirect beholder
base path; run.sh dropper capabilities og setter minnegrense; uv
pinnet til 0.11.
Rettet også en reell feil: existing_slugs() listet feil katalog
(Path / er identitet), så slug-unikhet virket ikke.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
public/ ble bare bygd hvis mappen manglet, så etter en oppgradering med
endrede maler var siden utdatert til noen lagret et innlegg.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Bokstaver og tall i alle skriftsystemer beholdes, alt annet blir
bindestrek. NFC-normalisering gir samme slug uansett om ø/å kommer
prekomponert eller som base + kombinerende tegn (macOS). URL-er i
feed.xml percent-encodes siden RSS-lesere krever ASCII.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Temaer slås opp i content/themes/<navn>/ før de innebygde, slik at et
eget tema følger med i git, backup og ved flytting – uten ny container.
Et tema kan være delvis: manglende maler/filer arves fra green (Jinja
ChoiceLoader, static kopieres lagvis). Valget lagres i site.toml;
SOAPBOX_THEME er bare standardverdi.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Lenkes relativt fra temaet (theme/favicon.svg) og fra admin-basen, så
nettleseren slipper å gjette på /favicon.ico.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Redigeringssiden lenker til /admin/history/<id> som lister commits som
har rørt innleggets mappe; klikk på en commit viser diffen fargelagt.
Samme tilgangsregler som editoren (gjester ser bare egne innlegg).
README skiller nå tydelig mellom å kopiere hele data-volumet (ingen nye
brukere) og å klone bare innholdsrepoet (brukere må opprettes på nytt).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
AGPL §13 krever at brukere av en nettverkstjeneste kan hente kildekoden;
temaet viser derfor en lenke til repoet på hver side.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
build.sh bygger imaget med build-dato og git-revisjon, run.sh starter
containeren idempotent (podman run --replace) med innstillinger fra .env.
compose.yaml leser nå samme .env. Alle variabler har standardverdier;
.env.example dokumenterer dem.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Jinja escaper for HTML, men nettleseren dekoder attributtverdien før
JS-parseren ser den, så en tittel med ' kunne bryte ut av strengen.
Bekreftelser går nå via data-confirm og én delt handler i base.html.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
next-parameteren godtok "//evil.com", som nettlesere tolker som en
ekstern URL. Nå godtas bare stier som starter med én skråstrek.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
podman stop tok 10 s og endte i SIGKILL fordi waitress ignorerer SIGTERM
som PID 1. Med SIGINT stopper containeren på under et halvt sekund.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
Flask-app som genererer statiske sider til public/ og serverer dem
sammen med et admin-grensesnitt (/admin). Innhold ligger som markdown
og bilder i et git-repo (data/content), brukere i sqlite.
- Editor med toolbar, live server-side forhåndsvisning, bildeopplasting
via knapp, dra-og-slipp og lim inn. Bilder nedskaleres og EXIF fjernes.
- Hovedbruker publiserer under /<slug>/, gjester under /<bruker>/<slug>/.
Slug lages fra tittelen og fryses ved publisering.
- Alle interne lenker er relative, så siden kan flyttes mellom domener og
sub-paths (SOAPBOX_BASE_PATH) uten rebuild.
- Tema 'green' med CSS-variabler, mørk modus og WCAG-kontrast.
- Containerfile (python:alpine + git), compose.yaml og Caddyfile-eksempel.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR