v1.3.1: Smart Cache Strategy + REQUIREMENTS.md überarbeitet
- Feature: isCacheFresh() – initialer API-Refresh nur wenn Cache >1h alt oder <5 Arbeitstage abgedeckt (FR-024) - REQUIREMENTS.md komplett überarbeitet: lösungsneutral, alle Features dokumentiert, Versions-Spalte - Build-Script: Git-Tag wird bei Rebuild auf aktuellen Commit verschoben (git tag -f) - Neue Regel 7: Requirements-Konsistenz im Implementation Plan - test_logic.js: statischer Check für isCacheFresh
This commit is contained in:
@@ -48,3 +48,10 @@ trigger: always_on
|
||||
## 6. Workspace Scopes
|
||||
- **Browser**: Allowed for documentation and safe browsing. No automated logins without permission.
|
||||
- **Terminal**: No `rm -rf`. Run tests (`pytest` etc.) after logic changes.
|
||||
|
||||
## 7. Requirements-Konsistenz 📋
|
||||
Alle umgesetzten Anforderungen müssen mit `REQUIREMENTS.md` übereinstimmen.
|
||||
1. **Vor der Umsetzung prüfen**: Passt die neue Anforderung zu den bestehenden Requirements?
|
||||
2. **Fehlende Requirements**: Wenn eine umzusetzende Anforderung in `REQUIREMENTS.md` fehlt, muss dies im **Implementation Plan** explizit dokumentiert und freigegeben werden.
|
||||
3. **Widersprüche**: Wenn eine neue Anforderung im Widerspruch zu bestehenden Requirements steht, muss dies im **Implementation Plan** als ⚠️ Warning hervorgehoben werden.
|
||||
4. **Nach Freigabe**: Bei Genehmigung des Implementation Plans muss `REQUIREMENTS.md` entsprechend erweitert oder korrigiert werden (neue ID, Version, Beschreibung). Obsolet gewordene Requirements werden nicht aus `REQUIREMENTS.md` gelöscht sondern nur als durchgestrichen markiert und ein Kommentar mit dem Grund hinzugefügt.
|
||||
@@ -9,51 +9,65 @@ Das System umfasst die Darstellung von Menüplänen in einer Wochenübersicht, d
|
||||
|
||||
## 2. Funktionale Anforderungen
|
||||
|
||||
| ID | Anforderung (Satzschablone nach Chris Rupp) | Priorität | Status |
|
||||
| ID | Anforderung (Satzschablone nach Chris Rupp) | Priorität | Seit |
|
||||
|:---|:---|:---|:---|
|
||||
| **Authentifizierung** | | | |
|
||||
| FR-001 | Das System muss dem Benutzer die Möglichkeit bieten, sich mit Mitarbeiternummer und Passwort anzumelden. | Hoch | ✅ |
|
||||
| FR-002 | Das System muss eine bestehende Bessa-Session erkennen und automatisch wiederverwenden, um eine erneute Anmeldung zu vermeiden. | Hoch | ✅ |
|
||||
| FR-003 | Das System darf keine Zugangsdaten dauerhaft speichern. Die Authentifizierung muss sitzungsbasiert sein. | Hoch | ✅ |
|
||||
| FR-004 | Dem Benutzer muss angezeigt werden, ob und als wer er angemeldet ist (Name oder ID). | Mittel | ✅ |
|
||||
| **Authentifizierung & Zugang** | | | |
|
||||
| FR-001 | Das System muss dem Benutzer die Möglichkeit bieten, sich mit Mitarbeiternummer und Passwort anzumelden. | Hoch | v1.0.1 |
|
||||
| FR-002 | Das System muss eine bestehende Bessa-Session erkennen und automatisch wiederverwenden, um eine erneute Anmeldung zu vermeiden. | Hoch | v1.0.1 |
|
||||
| FR-003 | Das System darf keine Zugangsdaten dauerhaft speichern. Die Authentifizierung muss sitzungsbasiert sein. | Hoch | v1.0.1 |
|
||||
| FR-004 | Dem Benutzer muss angezeigt werden, ob und als wer er angemeldet ist (Vorname, Name oder ID). | Mittel | v1.0.1 |
|
||||
| FR-005 | Nicht authentifizierte Benutzer müssen die Menüdaten einsehen können (eingeschränkter Lesezugriff). | Mittel | v1.0.1 |
|
||||
| FR-006 | Das System muss eine explizite Logout-Funktion bereitstellen, die alle sitzungsbezogenen Daten entfernt. | Mittel | v1.0.1 |
|
||||
| **Menüanzeige** | | | |
|
||||
| FR-010 | Das System muss dem Benutzer alle verfügbaren Tagesmenüs einer Woche gleichzeitig in einer Übersicht darstellen. | Hoch | ✅ |
|
||||
| FR-011 | Das System muss dem Benutzer die Navigation zwischen der aktuellen und der kommenden Woche ermöglichen. | Mittel | ✅ |
|
||||
| FR-012 | Für jedes Gericht müssen Name, Beschreibung, Preis und Verfügbarkeitsstatus angezeigt werden. | Hoch | ✅ |
|
||||
| FR-013 | Bereits bestellte Menüs müssen visuell von nicht bestellten unterscheidbar sein (farbliche Markierung, Badge). | Mittel | ✅ |
|
||||
| FR-014 | Die Tageskarten-Header müssen den Bestellstatus des Tages farblich signalisieren (bestellt / bestellbar / nicht bestellbar). | Niedrig | ✅ |
|
||||
| FR-015 | Wenn neue Menüdaten geladen werden, muss der Fortschritt dem Benutzer in Echtzeit angezeigt werden. | Niedrig | ✅ |
|
||||
| FR-016 | Das System muss bereits geladene Menüdaten zwischenspeichern (Caching), um bei erneutem Aufruf sofort eine Übersicht anzeigen zu können. | Mittel | ✅ |
|
||||
| FR-010 | Das System muss dem Benutzer alle verfügbaren Tagesmenüs einer Woche gleichzeitig in einer Übersicht darstellen. | Hoch | v1.0.1 |
|
||||
| FR-011 | Das System muss dem Benutzer die Navigation zwischen der aktuellen und der kommenden Woche ermöglichen. | Mittel | v1.0.1 |
|
||||
| FR-012 | Für jedes Gericht müssen Name, Beschreibung, Preis und Verfügbarkeitsstatus angezeigt werden. | Hoch | v1.0.1 |
|
||||
| FR-013 | Bereits bestellte Menüs müssen visuell von nicht bestellten unterscheidbar sein (farbliche Markierung, Badge). | Mittel | v1.0.1 |
|
||||
| FR-014 | Die Tageskarten-Header müssen den Bestellstatus des Tages farblich signalisieren (bestellt / bestellbar / nicht bestellbar). | Niedrig | v1.0.1 |
|
||||
| FR-015 | Bestellte Menü-Codes (z.B. M1, M2) müssen als Badges im Tageskarten-Header angezeigt werden. | Niedrig | v1.0.1 |
|
||||
| FR-016 | Am heutigen Tag müssen bestellte Menüs an erster Stelle sortiert werden. | Niedrig | v1.0.1 |
|
||||
| FR-017 | Wenn keine Menüdaten für eine Woche vorliegen, muss ein aussagekräftiger Leertext angezeigt werden. | Niedrig | v1.0.1 |
|
||||
| **Daten-Aktualisierung** | | | |
|
||||
| FR-020 | Wenn Menüdaten geladen werden, muss der Fortschritt dem Benutzer in Echtzeit angezeigt werden (Fortschrittsbalken, Statustext). | Niedrig | v1.0.1 |
|
||||
| FR-021 | Das System muss bereits geladene Menüdaten zwischenspeichern, um bei erneutem Aufruf sofort eine Übersicht anzeigen zu können. | Mittel | v1.0.1 |
|
||||
| FR-022 | Das System muss dem Benutzer die Möglichkeit bieten, die Menüdaten manuell neu zu laden. | Niedrig | v1.0.1 |
|
||||
| FR-023 | Der Zeitpunkt der letzten Aktualisierung muss für den Benutzer sichtbar sein. | Niedrig | v1.0.1 |
|
||||
| FR-024 | Das System darf beim Start keinen automatischen API-Refresh durchführen, wenn der Cache frisch (< 1 Stunde) und vollständig ist (nächste 5 Arbeitstage abgedeckt). | Mittel | v1.3.1 |
|
||||
| **Bestellfunktion** | | | |
|
||||
| FR-020 | Authentifizierte Benutzer müssen ein verfügbares Menü direkt aus der Übersicht bestellen können. | Hoch | ✅ |
|
||||
| FR-021 | Authentifizierte Benutzer müssen eine bestehende Bestellung direkt aus der Übersicht stornieren können. | Hoch | ✅ |
|
||||
| FR-022 | Nach Bestellschluss (Cutoff-Zeit) dürfen keine neuen Bestellungen oder Stornierungen für diesen Tag möglich sein. | Hoch | ✅ |
|
||||
| FR-023 | Es muss möglich sein, dasselbe Menü mehrfach zu bestellen. | Niedrig | ✅ |
|
||||
| FR-030 | Authentifizierte Benutzer müssen ein verfügbares Menü direkt aus der Übersicht bestellen können. | Hoch | v1.0.1 |
|
||||
| FR-031 | Authentifizierte Benutzer müssen eine bestehende Bestellung direkt aus der Übersicht stornieren können. | Hoch | v1.0.1 |
|
||||
| FR-032 | Nach Bestellschluss (Cutoff-Zeit) dürfen keine neuen Bestellungen oder Stornierungen für diesen Tag möglich sein. | Hoch | v1.0.1 |
|
||||
| FR-033 | Es muss möglich sein, dasselbe Menü mehrfach zu bestellen. Bei Mehrfachbestellungen muss die Anzahl angezeigt werden. | Niedrig | v1.0.1 |
|
||||
| **Kostentransparenz** | | | |
|
||||
| FR-030 | Das System muss die Gesamtkosten aller Bestellungen einer Woche automatisch berechnen und anzeigen. | Mittel | ✅ |
|
||||
| FR-040 | Das System muss die Gesamtkosten aller Bestellungen einer Woche automatisch berechnen und anzeigen. | Mittel | v1.1.0 |
|
||||
| **Bestell-Countdown** | | | |
|
||||
| FR-040 | Das System muss eine Stunde vor Bestellschluss einen visuellen Countdown anzeigen. | Mittel | ✅ |
|
||||
| FR-050 | Das System muss vor Bestellschluss einen visuell hervorgehobenen Countdown anzeigen. | Mittel | v1.1.0 |
|
||||
| **Menü-Flagging & Benachrichtigungen** | | | |
|
||||
| FR-050 | Authentifizierte Benutzer müssen ausverkaufte Menüs zur Beobachtung markieren können ("flaggen"). | Mittel | ✅ |
|
||||
| FR-051 | Das System muss geflaggte Menüs periodisch auf Verfügbarkeitsänderungen prüfen. | Mittel | ✅ |
|
||||
| FR-052 | Bei Statusänderung eines geflaggten Menüs auf „verfügbar" muss der Benutzer benachrichtigt werden (In-App Toast + Systembenachrichtigung). | Mittel | ✅ |
|
||||
| FR-053 | Geflaggte Menüs müssen im UI visuell hervorgehoben werden (gelber Glow bei ausverkauft, grüner Glow bei verfügbar). | Mittel | ✅ |
|
||||
| FR-054 | Wenn die Bestell-Cutoff-Zeit erreicht ist, muss das System ein Flag automatisch entfernen. | Mittel | ✅ |
|
||||
| FR-060 | Authentifizierte Benutzer müssen ausverkaufte Menüs zur Beobachtung markieren können ("flaggen"). | Mittel | v1.0.1 |
|
||||
| FR-061 | Das System muss geflaggte Menüs periodisch auf Verfügbarkeitsänderungen prüfen. | Mittel | v1.0.1 |
|
||||
| FR-062 | Bei Statusänderung eines geflaggten Menüs auf „verfügbar" muss der Benutzer benachrichtigt werden (In-App + Systembenachrichtigung). | Mittel | v1.0.1 |
|
||||
| FR-063 | Geflaggte Menüs müssen im UI visuell hervorgehoben werden (gelber Glow bei ausverkauft, grüner Glow bei verfügbar). | Mittel | v1.0.1 |
|
||||
| FR-064 | Wenn die Bestell-Cutoff-Zeit erreicht ist, muss das System ein Flag automatisch entfernen. | Mittel | v1.0.1 |
|
||||
| **Personalisierung: Smart Highlights** | | | |
|
||||
| FR-060 | Benutzer müssen Schlagwörter (Tags) definieren können, nach denen Menüs automatisch visuell hervorgehoben werden. | Mittel | ✅ |
|
||||
| FR-061 | Die Hervorhebung muss anhand von Menüname und Beschreibung erfolgen (Substring-Matching, case-insensitive). | Niedrig | ✅ |
|
||||
| FR-062 | Hervorgehobene Menüs müssen ein Tag-Badge mit dem matchenden Schlagwort anzeigen. | Niedrig | ✅ |
|
||||
| FR-063 | Die nächste-Woche-Navigation muss die Anzahl der dort gefundenen Highlights als Badge anzeigen. | Niedrig | ✅ |
|
||||
| FR-070 | Benutzer müssen Schlagwörter (Tags) definieren können, nach denen Menüs automatisch visuell hervorgehoben werden. | Mittel | v1.1.0 |
|
||||
| FR-071 | Die Hervorhebung muss anhand von Menüname und Beschreibung erfolgen (Substring-Matching, case-insensitive). | Niedrig | v1.1.0 |
|
||||
| FR-072 | Hervorgehobene Menüs müssen ein Tag-Badge mit dem matchenden Schlagwort anzeigen. | Niedrig | v1.2.4 |
|
||||
| FR-073 | Die Nächste-Woche-Navigation muss die Anzahl der dort gefundenen Highlights als Badge anzeigen. | Niedrig | v1.2.5 |
|
||||
| **Darstellung & Theming** | | | |
|
||||
| FR-070 | Das System muss einen hellen und einen dunklen Darstellungsmodus (Light/Dark Theme) unterstützen. | Niedrig | ✅ |
|
||||
| FR-071 | Die Theme-Präferenz des Benutzers muss persistent gespeichert werden. | Niedrig | ✅ |
|
||||
| FR-072 | Das System muss beim erstmaligen Laden die System-Präferenz (`prefers-color-scheme`) berücksichtigen. | Niedrig | ✅ |
|
||||
| FR-080 | Das System muss einen hellen und einen dunklen Darstellungsmodus (Light/Dark Theme) unterstützen. | Niedrig | v1.0.1 |
|
||||
| FR-081 | Die Theme-Präferenz des Benutzers muss persistent gespeichert werden. | Niedrig | v1.0.1 |
|
||||
| FR-082 | Das System muss beim erstmaligen Laden die Betriebssystem-Präferenz für das Farbschema berücksichtigen. | Niedrig | v1.0.1 |
|
||||
| **Benutzer-Feedback** | | | |
|
||||
| FR-090 | Alle benutzerrelevanten Aktionen (Bestellung, Stornierung, Fehler) müssen durch nicht-blockierende Benachrichtigungen (Toasts) bestätigt werden. | Mittel | v1.0.1 |
|
||||
| FR-091 | Bei einem Verbindungsfehler muss ein Fehlerdialog mit Fallback-Link zur Originalseite angezeigt werden. | Mittel | v1.0.1 |
|
||||
| **Nächste-Woche-Badge** | | | |
|
||||
| FR-100 | Die Navigation zur nächsten Woche muss ein Badge anzeigen, das den Überblick über den Bestellstatus der kommenden Woche visualisiert (bestellt / bestellbar / gesamt). | Niedrig | v1.0.1 |
|
||||
| **Update-Management** | | | |
|
||||
| FR-080 | Das System muss periodisch prüfen, ob eine neuere Version verfügbar ist. | Niedrig | ✅ |
|
||||
| FR-081 | Bei Verfügbarkeit einer neueren Version muss ein diskreter Indikator im Header angezeigt werden. | Niedrig | ✅ |
|
||||
| FR-082 | Benutzer müssen eine Versionsliste mit Installationslinks einsehen können (Versionsmenü). | Niedrig | ✅ |
|
||||
| FR-083 | Es muss möglich sein, zu einer älteren Version zurückzukehren (Downgrade). | Niedrig | ✅ |
|
||||
| FR-084 | Ein Dev-Mode muss es ermöglichen, zwischen stabilen Releases und Entwicklungs-Tags umzuschalten. | Niedrig | ✅ |
|
||||
| FR-110 | Das System muss periodisch prüfen, ob eine neuere Version verfügbar ist. | Niedrig | v1.0.3 |
|
||||
| FR-111 | Bei Verfügbarkeit einer neueren Version muss ein diskreter Indikator im Header angezeigt werden. | Niedrig | v1.0.3 |
|
||||
| FR-112 | Benutzer müssen eine Versionsliste mit Installationslinks einsehen können (Versionsmenü). | Niedrig | v1.3.0 |
|
||||
| FR-113 | Es muss möglich sein, zu einer älteren Version zurückzukehren (Downgrade). | Niedrig | v1.3.0 |
|
||||
| FR-114 | Ein Dev-Mode muss es ermöglichen, zwischen stabilen Releases und Entwicklungs-Tags umzuschalten. | Niedrig | v1.3.0 |
|
||||
|
||||
## 3. Nicht-funktionale Anforderungen
|
||||
|
||||
@@ -66,7 +80,7 @@ Das System umfasst die Darstellung von Menüplänen in einer Wochenübersicht, d
|
||||
| **Benutzbarkeit** | NFR-005 | Die Oberfläche muss auf mobilen Geräten fehlerfrei nutzbar sein. | Viewports ab 320px Breite |
|
||||
| **Benutzbarkeit** | NFR-006 | Alle interaktiven Elemente müssen Tooltips oder Hilfetexte bieten. | 100% Coverage |
|
||||
| **Benutzbarkeit** | NFR-007 | Die Benutzeroberfläche muss vollständig in deutscher Sprache sein. | Vollständige Lokalisierung |
|
||||
| **Wartbarkeit** | NFR-008 | Die Build-Artefakte müssen durch automatisierte Tests validiert werden. | Build-Tests vorhanden |
|
||||
| **Wartbarkeit** | NFR-008 | Die Build-Artefakte müssen durch automatisierte Tests validiert werden. | Build-Tests + Logik-Tests |
|
||||
|
||||
## 4. Technische Randbedingungen
|
||||
* **Deployment**: Das System wird als Bookmarklet ausgeliefert, das auf der Bessa-Webseite ausgeführt wird.
|
||||
|
||||
@@ -271,7 +271,8 @@ echo "✅ All build tests passed."
|
||||
echo ""
|
||||
echo "=== Tagging $VERSION ==="
|
||||
if git rev-parse "$VERSION" >/dev/null 2>&1; then
|
||||
echo "ℹ️ Tag $VERSION already exists, skipping."
|
||||
git tag -f "$VERSION"
|
||||
echo "🔄 Tag $VERSION moved to current commit."
|
||||
else
|
||||
git tag "$VERSION"
|
||||
echo "✅ Created tag: $VERSION"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
## v1.3.1 (2026-02-17)
|
||||
- **Feature**: Smart Cache – Initialer API-Refresh wird übersprungen wenn Cache < 1h alt und nächste 5 Arbeitstage abgedeckt. ⚡
|
||||
|
||||
## v1.3.0 (2026-02-16)
|
||||
- **Feature**: GitHub Release Management 📦
|
||||
- Version-Menü: Klick auf Versionsnummer zeigt alle verfügbaren Versionen
|
||||
|
||||
2
dist/bookmarklet-payload.js
vendored
2
dist/bookmarklet-payload.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bookmarklet.txt
vendored
2
dist/bookmarklet.txt
vendored
File diff suppressed because one or more lines are too long
16
dist/install.html
vendored
16
dist/install.html
vendored
File diff suppressed because one or more lines are too long
48
dist/kantine-standalone.html
vendored
48
dist/kantine-standalone.html
vendored
@@ -1807,7 +1807,7 @@ body {
|
||||
<div class="brand">
|
||||
<span class="material-icons-round logo-icon">restaurant_menu</span>
|
||||
<div class="header-left">
|
||||
<h1>Kantinen Übersicht <small class="version-tag" style="font-size: 0.6em; opacity: 0.7; font-weight: 400; cursor: pointer;" title="Klick für Versionsmenü">v1.3.0</small></h1>
|
||||
<h1>Kantinen Übersicht <small class="version-tag" style="font-size: 0.6em; opacity: 0.7; font-weight: 400; cursor: pointer;" title="Klick für Versionsmenü">v1.3.1</small></h1>
|
||||
<div id="last-updated-subtitle" class="subtitle"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1919,7 +1919,7 @@ body {
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<strong>Aktuell:</strong> <span id="version-current">v1.3.0</span>
|
||||
<strong>Aktuell:</strong> <span id="version-current">v1.3.1</span>
|
||||
</div>
|
||||
<div class="dev-toggle">
|
||||
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;">
|
||||
@@ -2532,6 +2532,34 @@ body {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FR-024: Check if cache is fresh enough to skip API refresh
|
||||
function isCacheFresh() {
|
||||
const cachedTs = localStorage.getItem(CACHE_TS_KEY);
|
||||
if (!cachedTs) return false;
|
||||
|
||||
// Condition 1: Cache < 1 hour old
|
||||
const ageMs = Date.now() - new Date(cachedTs).getTime();
|
||||
if (ageMs > 60 * 60 * 1000) return false;
|
||||
|
||||
// Condition 2: Data covers next 5 working days
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const cachedDates = new Set();
|
||||
allWeeks.forEach(w => (w.days || []).forEach(d => cachedDates.add(d.date)));
|
||||
|
||||
let coveredDays = 0;
|
||||
for (let i = 0; i < 7 && coveredDays < 5; i++) {
|
||||
const check = new Date(today);
|
||||
check.setDate(check.getDate() + i);
|
||||
const dow = check.getDay();
|
||||
if (dow === 0 || dow === 6) continue; // Skip weekends
|
||||
const dateStr = check.toISOString().split('T')[0];
|
||||
if (cachedDates.has(dateStr)) coveredDays++;
|
||||
}
|
||||
|
||||
return coveredDays >= 5;
|
||||
}
|
||||
|
||||
// === Menu Data Fetching (Direct from Bessa API) ===
|
||||
async function loadMenuDataFromAPI() {
|
||||
const loading = document.getElementById('loading');
|
||||
@@ -3243,7 +3271,7 @@ body {
|
||||
|
||||
// Periodic update check (runs on init + every hour)
|
||||
async function checkForUpdates() {
|
||||
const currentVersion = 'v1.3.0';
|
||||
const currentVersion = 'v1.3.1';
|
||||
const devMode = localStorage.getItem('kantine_dev_mode') === 'true';
|
||||
|
||||
try {
|
||||
@@ -3284,7 +3312,7 @@ body {
|
||||
const modal = document.getElementById('version-modal');
|
||||
const container = document.getElementById('version-list-container');
|
||||
const devToggle = document.getElementById('dev-mode-toggle');
|
||||
const currentVersion = 'v1.3.0';
|
||||
const currentVersion = 'v1.3.1';
|
||||
|
||||
if (!modal) return;
|
||||
modal.classList.remove('hidden');
|
||||
@@ -3487,13 +3515,19 @@ body {
|
||||
updateAuthUI();
|
||||
cleanupExpiredFlags();
|
||||
|
||||
// Load cached data first for instant UI, then refresh from API
|
||||
// Load cached data first for instant UI, refresh only if stale (FR-024)
|
||||
const hadCache = loadMenuCache();
|
||||
if (hadCache) {
|
||||
// Hide loading spinner since cache is shown
|
||||
document.getElementById('loading').classList.add('hidden');
|
||||
if (!isCacheFresh()) {
|
||||
console.log('Cache stale or incomplete – refreshing from API');
|
||||
loadMenuDataFromAPI();
|
||||
} else {
|
||||
console.log('Cache fresh & complete – skipping API refresh');
|
||||
}
|
||||
} else {
|
||||
loadMenuDataFromAPI();
|
||||
}
|
||||
loadMenuDataFromAPI();
|
||||
|
||||
// Auto-start polling if already logged in
|
||||
if (authToken) {
|
||||
|
||||
40
kantine.js
40
kantine.js
@@ -796,6 +796,34 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
// FR-024: Check if cache is fresh enough to skip API refresh
|
||||
function isCacheFresh() {
|
||||
const cachedTs = localStorage.getItem(CACHE_TS_KEY);
|
||||
if (!cachedTs) return false;
|
||||
|
||||
// Condition 1: Cache < 1 hour old
|
||||
const ageMs = Date.now() - new Date(cachedTs).getTime();
|
||||
if (ageMs > 60 * 60 * 1000) return false;
|
||||
|
||||
// Condition 2: Data covers next 5 working days
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const cachedDates = new Set();
|
||||
allWeeks.forEach(w => (w.days || []).forEach(d => cachedDates.add(d.date)));
|
||||
|
||||
let coveredDays = 0;
|
||||
for (let i = 0; i < 7 && coveredDays < 5; i++) {
|
||||
const check = new Date(today);
|
||||
check.setDate(check.getDate() + i);
|
||||
const dow = check.getDay();
|
||||
if (dow === 0 || dow === 6) continue; // Skip weekends
|
||||
const dateStr = check.toISOString().split('T')[0];
|
||||
if (cachedDates.has(dateStr)) coveredDays++;
|
||||
}
|
||||
|
||||
return coveredDays >= 5;
|
||||
}
|
||||
|
||||
// === Menu Data Fetching (Direct from Bessa API) ===
|
||||
async function loadMenuDataFromAPI() {
|
||||
const loading = document.getElementById('loading');
|
||||
@@ -1751,13 +1779,19 @@
|
||||
updateAuthUI();
|
||||
cleanupExpiredFlags();
|
||||
|
||||
// Load cached data first for instant UI, then refresh from API
|
||||
// Load cached data first for instant UI, refresh only if stale (FR-024)
|
||||
const hadCache = loadMenuCache();
|
||||
if (hadCache) {
|
||||
// Hide loading spinner since cache is shown
|
||||
document.getElementById('loading').classList.add('hidden');
|
||||
if (!isCacheFresh()) {
|
||||
console.log('Cache stale or incomplete – refreshing from API');
|
||||
loadMenuDataFromAPI();
|
||||
} else {
|
||||
console.log('Cache fresh & complete – skipping API refresh');
|
||||
}
|
||||
} else {
|
||||
loadMenuDataFromAPI();
|
||||
}
|
||||
loadMenuDataFromAPI();
|
||||
|
||||
// Auto-start polling if already logged in
|
||||
if (authToken) {
|
||||
|
||||
@@ -107,7 +107,8 @@ try {
|
||||
[/function\s+fetchVersions/, 'fetchVersions function'],
|
||||
[/function\s+isNewer/, 'isNewer function'],
|
||||
[/function\s+openVersionMenu/, 'openVersionMenu function'],
|
||||
[/kantine_dev_mode/, 'dev-mode localStorage key']
|
||||
[/kantine_dev_mode/, 'dev-mode localStorage key'],
|
||||
[/function\s+isCacheFresh/, 'isCacheFresh function']
|
||||
];
|
||||
|
||||
for (const [regex, label] of checks) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.3.0
|
||||
v1.3.1
|
||||
|
||||
Reference in New Issue
Block a user