feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
{{define "content"}}
|
|
|
|
|
<article>
|
|
|
|
|
{{with .Data}}
|
|
|
|
|
{{if .IsNew}}
|
|
|
|
|
<h1>Ny favoritt</h1>
|
|
|
|
|
{{else}}
|
|
|
|
|
<h1>Rediger favoritt</h1>
|
|
|
|
|
{{end}}
|
|
|
|
|
|
|
|
|
|
<form method="POST"
|
|
|
|
|
enctype="multipart/form-data"
|
|
|
|
|
{{if .IsNew}}
|
|
|
|
|
action="{{basePath}}/faves"
|
|
|
|
|
{{else}}
|
|
|
|
|
action="{{basePath}}/faves/{{.Fave.ID}}"
|
|
|
|
|
{{end}}>
|
|
|
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
|
|
|
|
|
|
|
|
<label for="description">
|
|
|
|
|
Beskrivelse *
|
|
|
|
|
<input type="text" id="description" name="description"
|
|
|
|
|
value="{{.Description}}" required autofocus
|
|
|
|
|
placeholder="F.eks. «Blade Runner 2049» eller «Rød tulipan»">
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
<label for="url">
|
|
|
|
|
Lenke (valgfri)
|
|
|
|
|
<input type="url" id="url" name="url"
|
|
|
|
|
value="{{.URL}}"
|
|
|
|
|
placeholder="https://...">
|
|
|
|
|
</label>
|
|
|
|
|
|
feat: add notes field to favorites and enhance OG meta tags
Add an optional long-form "notes" text field to each favorite for
reviews, thoughts, or extended descriptions. The field is stored in
SQLite via a new migration (002_add_fave_notes.sql) and propagated
through the entire stack:
- Model: Notes field on Fave struct
- Store: All SQL queries (Create, GetByID, Update, list methods,
scanFaves) updated with notes column
- Web handlers: Read/write notes in create, edit, update forms
- API handlers: Notes in create, update, get, import request/response
- Export: Notes included in both JSON and CSV exports
- Import: Notes parsed from both JSON and CSV imports
- Feed: Notes used as Atom feed item summary when present
- Form template: New textarea between URL and image fields
- Detail template: Display notes, enhanced og:description with
cascade: notes (truncated) → URL → generic fallback text
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:40:08 +02:00
|
|
|
<label for="notes">
|
|
|
|
|
Notater (valgfri)
|
|
|
|
|
<textarea id="notes" name="notes"
|
|
|
|
|
rows="4"
|
|
|
|
|
placeholder="Utfyllende tekst, anmeldelse, tanker...">{{.Notes}}</textarea>
|
|
|
|
|
</label>
|
|
|
|
|
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
<label for="image">
|
|
|
|
|
Bilde (valgfri)
|
|
|
|
|
<input type="file" id="image" name="image"
|
|
|
|
|
accept="image/jpeg,image/png,image/gif,image/webp">
|
|
|
|
|
</label>
|
|
|
|
|
{{if not .IsNew}}
|
|
|
|
|
{{if .Fave.ImagePath}}
|
|
|
|
|
<div class="current-image">
|
|
|
|
|
<img src="{{basePath}}/uploads/{{.Fave.ImagePath}}"
|
|
|
|
|
alt="Nåværende bilde"
|
|
|
|
|
style="max-width: 200px; max-height: 200px;">
|
|
|
|
|
<label>
|
|
|
|
|
<input type="checkbox" name="remove_image" value="1">
|
|
|
|
|
Fjern bilde
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
{{end}}
|
|
|
|
|
{{end}}
|
|
|
|
|
|
|
|
|
|
<label for="tags">
|
|
|
|
|
Merkelapper (kommaseparert)
|
|
|
|
|
<input type="text" id="tags" name="tags"
|
|
|
|
|
value="{{.Tags}}"
|
|
|
|
|
placeholder="film, sci-fi, favoritt"
|
|
|
|
|
autocomplete="off"
|
2026-03-29 17:54:24 +02:00
|
|
|
role="combobox"
|
|
|
|
|
aria-expanded="false"
|
|
|
|
|
aria-haspopup="listbox"
|
|
|
|
|
aria-autocomplete="list"
|
|
|
|
|
aria-controls="tag-suggestions"
|
|
|
|
|
aria-describedby="tags-help"
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
hx-get="{{basePath}}/tags/search"
|
|
|
|
|
hx-trigger="keyup changed delay:300ms"
|
|
|
|
|
hx-target="#tag-suggestions"
|
2026-04-04 00:17:38 +02:00
|
|
|
hx-params="none"
|
2026-03-29 17:54:24 +02:00
|
|
|
hx-vals='{"q": ""}'>
|
|
|
|
|
<small id="tags-help">Skriv for å søke i eksisterende merkelapper. Maks {{maxTags}} stk. Bruk piltaster for å velge.</small>
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
</label>
|
|
|
|
|
<ul id="tag-suggestions" role="listbox" class="tag-suggestions" aria-label="Merkelappforslag"></ul>
|
2026-03-29 17:54:24 +02:00
|
|
|
<div id="tag-status" class="sr-only" aria-live="polite"></div>
|
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00
|
|
|
|
|
|
|
|
<fieldset>
|
|
|
|
|
<legend>Synlighet</legend>
|
|
|
|
|
<label>
|
|
|
|
|
<input type="radio" name="privacy" value="public"
|
|
|
|
|
{{if eq .Privacy "public"}}checked{{end}}
|
|
|
|
|
{{if .IsNew}}{{if eq .DefaultPrivacy "public"}}checked{{end}}{{end}}>
|
|
|
|
|
Offentlig
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input type="radio" name="privacy" value="private"
|
|
|
|
|
{{if eq .Privacy "private"}}checked{{end}}
|
|
|
|
|
{{if .IsNew}}{{if eq .DefaultPrivacy "private"}}checked{{end}}{{end}}>
|
|
|
|
|
Privat
|
|
|
|
|
</label>
|
|
|
|
|
</fieldset>
|
|
|
|
|
|
|
|
|
|
<button type="submit">
|
|
|
|
|
{{if .IsNew}}Legg til{{else}}Lagre{{end}}
|
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
{{end}}
|
|
|
|
|
</article>
|
|
|
|
|
{{end}}
|