neue Archivfunktion und Optimierung an Artikelbearbeitung

This commit is contained in:
2026-08-09 18:24:04 +02:00
parent dd51532533
commit b80e2d5a6c
23 changed files with 1185 additions and 77 deletions

114
README.md
View File

@@ -551,6 +551,7 @@ Einzeln:
bash tools/check-env.sh .env # doppelte oder fehlerhafte .env-Einträge
python3 tools/check-routes.py # Endpunkte ohne Berechtigungsprüfung
python3 tools/check-schema.py # db/schema.sql gegen die Modelle
python3 tools/check-editable.py # Felder eines Eintrags überall verdrahtet?
python3 tools/check-nginx.py web # Kopfzeilen, doppelte Direktiven
node tools/check-js.mjs # undefinierte Bezeichner in den JS-Modulen
node tools/test-barcode.mjs # Strichcode-Decoder
@@ -575,6 +576,16 @@ der weder eine Prüfung noch einen Eintrag in der Ausnahmeliste hat. FastAPI
mahnt fehlende Absicherung nicht an beim Hinzufügen einer Route ist sie schnell
vergessen.
### `check-editable.py`
Prüft, dass jedes änderbare Feld eines Listeneintrags auch tatsächlich überall
eingetragen ist: Modell, `ItemUpdateIn`, `ItemOut`, `items.py`, `sync.py` und
die Oberfläche.
Ein Feld hinzuzufügen bedeutet sechs Stellen. Fehlt eine, merkt es niemand: Die
Anwendung startet, die Oberfläche zeigt ein Eingabefeld, der Server verwirft den
Wert stillschweigend. Genau so ist der Artikelname zunächst untergegangen.
### `check-schema.py`
Vergleicht `db/schema.sql` mit den SQLAlchemy-Modellen: fehlende oder
@@ -1119,12 +1130,14 @@ das geht bewusst nur direkt in der Datenbank.
### Automatische Bereinigung
Zwei Fristen, in der Verwaltung einstellbar:
Vier Fristen, in der Verwaltung einstellbar:
| Einstellung | Voreinstellung | Wirkung |
|---|---|---|
| Deaktivieren nach … Monaten ohne Anmeldung | 12 | Konto wird gesperrt, Person bekommt eine Nachricht |
| Löschen nach … Monaten Deaktivierung | 12 | Konto wird endgültig entfernt |
| Konto deaktivieren nach … Monaten ohne Anmeldung | 12 | Konto wird gesperrt, Person bekommt eine Nachricht |
| Konto löschen nach … Monaten Deaktivierung | 12 | Konto wird endgültig entfernt |
| Liste archivieren nach … Monaten ohne Öffnen | 12 | **Je Person** die Liste verschwindet nur aus deren Übersicht |
| Liste löschen nach … Monaten im Archiv | 12 | Nur nach dem Archivdatum des **Eigentümers** |
**0 bedeutet abgeschaltet, nicht „sofort".** Ein Tippfehler soll nicht dazu
führen, dass beim nächsten Durchlauf alle Konten verschwinden.
@@ -1137,6 +1150,101 @@ Grundlage ist `user.last_seen_at`. Der Wert wird bei der Anmeldung gesetzt und
danach höchstens stündlich nachgeführt, damit auch jemand mitzählt, der sich
monatelang nicht neu anmeldet, weil die Sitzung hält.
## Archiv
Jede Liste kann archiviert werden **je Person getrennt.** Wer eine gemeinsame
Liste nicht mehr braucht, nimmt sie aus seiner Übersicht, ohne sie den anderen
wegzunehmen.
In der Listenübersicht erscheint unterhalb der aktiven Listen ein aufklappbarer
Abschnitt „Archiv". Archivieren und Zurückholen stehen im „⋯"-Menü jeder Zeile
und stehen allen Mitgliedern offen, nicht nur dem Eigentümer.
| Methode | Pfad |
|---|---|
| GET | `/api/lists?archived=false\|true` ohne Parameter alle |
| POST | `/api/lists/{id}/archive`, `/unarchive` |
### Automatisch archivieren
Wer eine Liste zwölf Monate nicht geöffnet hat, findet sie danach im Archiv.
Grundlage ist `list_member.last_opened_at`, gesetzt bei jedem Zugriff und
höchstens stündlich nachgeführt.
Das wirkt sich **individuell** aus: Öffnet ein Mitglied die Liste regelmäßig
und ein anderes nie, bleibt sie beim einen aktiv und wandert beim anderen ins
Archiv.
### Automatisch löschen
Maßgeblich ist **allein das Archivdatum des Eigentümers.** Dass ein
eingeladenes Mitglied die Liste weggeräumt hat, sagt nichts darüber, ob sie
noch gebraucht wird sonst könnte jemand, der einmal eingeladen wurde und
nie wieder hineinschaut, eine Löschung auslösen, die den Eigentümer trifft.
Zwei Sicherungen gegen Datenverlust:
**Vorwarnungen per E-Mail** an den Eigentümer, 7 Tage und 1 Tag vor der
Löschung. Jede Stufe genau einmal eine tägliche Erinnerung wäre Belästigung
statt Warnung. Ein Klick auf „Aus dem Archiv holen" setzt die Frist zurück und
löscht auch die Warnvermerke, damit beim nächsten Mal wieder gewarnt wird.
**Wer die Liste zwischenzeitlich geöffnet hat, verliert sie nicht** auch wenn
das Archivdatum alt ist. Ohne diese Prüfung könnte eine manuell archivierte,
aber weiterhin benutzte Liste verschwinden.
Gelöscht wird per Soft Delete: Offline gebliebene Geräte erfahren noch davon,
endgültig entfernt der Aufräumlauf nach `CLEANUP_DELETED_DAYS`.
## Einträge bearbeiten
Im „⋯"-Menü eines Eintrags lässt sich alles ändern: **Artikel**, Anzahl,
Gebinde, Einheit, Eigenschaft, Notiz, Markt, Warengruppe, Preis und Status.
### Artikel wechseln oder umbenennen
Der Name gehört nicht dem Eintrag, sondern dem Artikel dahinter und der kann
von mehreren Einträgen benutzt werden, trägt einen Strichcode, Vorgaben für
Markt und Warengruppe und hängt an der Preishistorie. Ein Namenswechsel am
Eintrag ist deshalb mehrdeutig:
```
"Mlich" → "Milch" ein Tippfehler soll verschwinden
"Milch" → "Butter" dieser Eintrag soll etwas anderes sein
```
Die Regel: **Benutzt außer diesem Eintrag niemand den Artikel, wird er
umbenannt** der Tippfehler verschwindet dann restlos. Sonst hängt der Eintrag
auf einen anderen Artikel um, und die übrigen Einträge bleiben unberührt.
Bleibt der bisherige Artikel dabei ohne Einträge zurück und hängt nichts
Gepflegtes daran (kein Strichcode, keine Eigenschaften, keine Vorgaben, keine
beobachteten Preise), verschwindet er mit. Wo etwas dranhängt, bleibt er
stehen dort stört er nicht und lässt sich von Hand löschen.
Wer einen Artikel ausdrücklich **überall** umbenennen will, tut das unter
„Artikel"; dort ist der Name ein Feld wie jedes andere.
## Vorschläge beim Eintippen
Ab drei Zeichen im Feld „Artikel hinzufügen" erscheint eine Liste dessen, was
auf dieser Liste schon eingetragen wurde von **allen** Mitgliedern, aus den
letzten 24 Monaten.
Quelle sind die Listeneinträge, **auch die bereits gelöschten**: Gerade die
abgehakten und aufgeräumten sind die interessanten. Was jemand vor drei Jahren
einmal gekauft hat, hilft dagegen nicht mehr und würde die Liste nur
verlängern.
Ein Antippen füllt Name, Anzahl, Gebinde, Eigenschaft sowie Markt und
Warengruppe mit den zuletzt verwendeten Werten **trägt den Artikel aber noch
nicht ein.** Der Fokus springt ins Gebinde-Feld, damit noch Änderungen möglich
sind. Erst „Hinzufügen" oder Enter übernimmt.
Sortiert nach Häufigkeit, dann nach Aktualität; höchstens acht Vorschläge.
`GET /api/lists/{id}/articles/suggest?q=…`
## Datenbankschema
`db/schema.sql` enthält das vollständige Schema (Revision `0011`).