New /settings page (linked from the header's burger menu) offers:
- CSV export of the user's links, for spreadsheet apps.
- SQL dump export as INSERT INTO links (...) statements, scoped to
the current user only — never a raw full-database dump, since that
would leak other accounts' password hashes and data. Embeddings are
excluded (regenerated via "KI neu beschreiben lassen" if needed).
- SQL import that re-adds a previously exported dump to the current
account (additive, doesn't touch existing links).
Import safety (app/backup.py): uploaded SQL is never executed against
the real database. Each non-comment line is required to start with
"insert into links" and is run one statement at a time against an
isolated in-memory SQLite database with only a whitelisted `links`
schema (no id/user_id columns) — sqlite3.execute() also rejects
multiple statements per call. Only after that succeeds are rows
copied into the real DB via the ORM, with user_id forced to the
logged-in user. Verified this rejects DROP TABLE, ATTACH DATABASE,
stacked statements, cross-table subqueries, and user_id injection.
Upload is capped at 2 MB.
Also adds download/upload icons and a proper file-input styling
pattern (visually-hidden input + <label> trigger + filename readout),
since the browser's ::file-selector-button pseudo-element didn't
render reliably in testing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The app was dark-only with the email shown as plain text and a bare
"Abmelden" button. Header now has:
- A light/dark theme toggle (sun/moon icon). Choice persists via
localStorage and is applied before first paint (inline script in
<head>) to avoid a flash of the wrong theme; falls back to the
system preference on first visit. Added a light CSS variable set
alongside the existing dark palette.
- A circular user icon (head-and-shoulders) showing the email as a
tooltip, replacing the plain-text address.
- A burger-menu dropdown with the email, disabled placeholder items
("Tags verwalten", "Einstellungen" — marked "bald") to make room
for future features, and the actual Abmelden action.
Dropdown opens/closes via a small vanilla-JS handler in base.html
(click outside or Escape closes it), consistent with the project's
no-build-step, mostly-HTMX frontend.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Emoji (📚🔖🏷️ ✎ ✕ 🕓⏳🤖⚠️🔍) rendered in each platform's own
colorful style and looked inconsistent. Add app/templates/_icons.html
with small inline SVG macros (Lucide-style, MIT-licensed path data,
stroke=currentColor) and use them throughout instead, so icons pick
up the muted/accent text colors like the rest of the UI.
The needs-review bookmark toggle now uses an outline vs. filled icon
for its two states instead of swapping emoji.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Links can be bookmarked for a later look via a toggle button on the
card (🏷️/🔖), shown with a yellow border while flagged. A new
sidebar section "Merkliste" links to /?review=1, filtering to just
the flagged links; the count updates live via the existing facets
query.
Since the project has no migration framework, add a minimal
startup check that ALTER TABLEs in the needs_review column for
existing SQLite databases (create_all only creates missing tables).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The layout was capped at 1200px and listed links in a single column.
Drop the cap and lay the cards out in a grid: three per row on wide
screens, two from 1000px, one below that.
To make the narrower cards work, shorten the edit action to an icon
button so the title and URL keep their room, and let the edit form's
field and button rows wrap.
Also fixes pre-existing horizontal overflow on phone widths by
stacking the sidebar above the content and letting the add-link form
wrap. Grid tracks use minmax(0, 1fr) so cards can shrink below their
content's intrinsic width instead of pushing the page wider.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a sort dropdown offering newest/oldest first and name A-Z/Z-A.
Sorting applies to plain listings, text search, and semantic search
results, and the sidebar facet links preserve the current choice.
Invalid sort values fall back to the default.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
FastAPI + HTMX Web-App zum Speichern von Links mit automatischer
KI-Kategorisierung, Zusammenfassung und semantischer Suche (OpenAI).
Mehrbenutzer mit Login, SQLite-Persistenz, Docker/Docker-Compose-Setup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>