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:
2026-02-17 20:38:53 +01:00
parent 4dbd6c930f
commit fe86e68aca
11 changed files with 156 additions and 58 deletions
+7
View File
@@ -48,3 +48,10 @@ trigger: always_on
## 6. Workspace Scopes ## 6. Workspace Scopes
- **Browser**: Allowed for documentation and safe browsing. No automated logins without permission. - **Browser**: Allowed for documentation and safe browsing. No automated logins without permission.
- **Terminal**: No `rm -rf`. Run tests (`pytest` etc.) after logic changes. - **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.
+51 -37
View File
@@ -9,51 +9,65 @@ Das System umfasst die Darstellung von Menüplänen in einer Wochenübersicht, d
## 2. Funktionale Anforderungen ## 2. Funktionale Anforderungen
| ID | Anforderung (Satzschablone nach Chris Rupp) | Priorität | Status | | ID | Anforderung (Satzschablone nach Chris Rupp) | Priorität | Seit |
|:---|:---|:---|:---| |:---|:---|:---|:---|
| **Authentifizierung** | | | | | **Authentifizierung & Zugang** | | | |
| FR-001 | Das System muss dem Benutzer die Möglichkeit bieten, sich mit Mitarbeiternummer und Passwort anzumelden. | Hoch | | | 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 | | | 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 | | | 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 (Name oder ID). | Mittel | | | 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** | | | | | **Menüanzeige** | | | |
| FR-010 | Das System muss dem Benutzer alle verfügbaren Tagesmenüs einer Woche gleichzeitig in einer Übersicht darstellen. | Hoch | | | 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 | | | 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 | | | 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 | | | 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 | | | FR-014 | Die Tageskarten-Header müssen den Bestellstatus des Tages farblich signalisieren (bestellt / bestellbar / nicht bestellbar). | Niedrig | v1.0.1 |
| FR-015 | Wenn neue Menüdaten geladen werden, muss der Fortschritt dem Benutzer in Echtzeit angezeigt werden. | Niedrig | | | FR-015 | Bestellte Menü-Codes (z.B. M1, M2) müssen als Badges im Tageskarten-Header angezeigt werden. | Niedrig | v1.0.1 |
| FR-016 | Das System muss bereits geladene Menüdaten zwischenspeichern (Caching), um bei erneutem Aufruf sofort eine Übersicht anzeigen zu können. | Mittel | ✅ | | 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** | | | | | **Bestellfunktion** | | | |
| FR-020 | Authentifizierte Benutzer müssen ein verfügbares Menü direkt aus der Übersicht bestellen können. | Hoch | | | FR-030 | Authentifizierte Benutzer müssen ein verfügbares Menü direkt aus der Übersicht bestellen können. | Hoch | v1.0.1 |
| FR-021 | Authentifizierte Benutzer müssen eine bestehende Bestellung direkt aus der Übersicht stornieren können. | Hoch | | | FR-031 | Authentifizierte Benutzer müssen eine bestehende Bestellung direkt aus der Übersicht stornieren können. | Hoch | v1.0.1 |
| FR-022 | Nach Bestellschluss (Cutoff-Zeit) dürfen keine neuen Bestellungen oder Stornierungen für diesen Tag möglich sein. | Hoch | | | 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-023 | Es muss möglich sein, dasselbe Menü mehrfach zu bestellen. | Niedrig | | | FR-033 | Es muss möglich sein, dasselbe Menü mehrfach zu bestellen. Bei Mehrfachbestellungen muss die Anzahl angezeigt werden. | Niedrig | v1.0.1 |
| **Kostentransparenz** | | | | | **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** | | | | | **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** | | | | | **Menü-Flagging & Benachrichtigungen** | | | |
| FR-050 | Authentifizierte Benutzer müssen ausverkaufte Menüs zur Beobachtung markieren können ("flaggen"). | Mittel | | | FR-060 | Authentifizierte Benutzer müssen ausverkaufte Menüs zur Beobachtung markieren können ("flaggen"). | Mittel | v1.0.1 |
| FR-051 | Das System muss geflaggte Menüs periodisch auf Verfügbarkeitsänderungen prüfen. | Mittel | | | FR-061 | Das System muss geflaggte Menüs periodisch auf Verfügbarkeitsänderungen prüfen. | Mittel | v1.0.1 |
| FR-052 | Bei Statusänderung eines geflaggten Menüs auf „verfügbar" muss der Benutzer benachrichtigt werden (In-App Toast + Systembenachrichtigung). | Mittel | | | 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-053 | Geflaggte Menüs müssen im UI visuell hervorgehoben werden (gelber Glow bei ausverkauft, grüner Glow bei verfügbar). | Mittel | | | 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-054 | Wenn die Bestell-Cutoff-Zeit erreicht ist, muss das System ein Flag automatisch entfernen. | Mittel | | | FR-064 | Wenn die Bestell-Cutoff-Zeit erreicht ist, muss das System ein Flag automatisch entfernen. | Mittel | v1.0.1 |
| **Personalisierung: Smart Highlights** | | | | | **Personalisierung: Smart Highlights** | | | |
| FR-060 | Benutzer müssen Schlagwörter (Tags) definieren können, nach denen Menüs automatisch visuell hervorgehoben werden. | Mittel | | | FR-070 | Benutzer müssen Schlagwörter (Tags) definieren können, nach denen Menüs automatisch visuell hervorgehoben werden. | Mittel | v1.1.0 |
| FR-061 | Die Hervorhebung muss anhand von Menüname und Beschreibung erfolgen (Substring-Matching, case-insensitive). | Niedrig | | | FR-071 | Die Hervorhebung muss anhand von Menüname und Beschreibung erfolgen (Substring-Matching, case-insensitive). | Niedrig | v1.1.0 |
| FR-062 | Hervorgehobene Menüs müssen ein Tag-Badge mit dem matchenden Schlagwort anzeigen. | Niedrig | | | FR-072 | Hervorgehobene Menüs müssen ein Tag-Badge mit dem matchenden Schlagwort anzeigen. | Niedrig | v1.2.4 |
| FR-063 | Die nächste-Woche-Navigation muss die Anzahl der dort gefundenen Highlights als Badge anzeigen. | Niedrig | | | FR-073 | Die Nächste-Woche-Navigation muss die Anzahl der dort gefundenen Highlights als Badge anzeigen. | Niedrig | v1.2.5 |
| **Darstellung & Theming** | | | | | **Darstellung & Theming** | | | |
| FR-070 | Das System muss einen hellen und einen dunklen Darstellungsmodus (Light/Dark Theme) unterstützen. | Niedrig | | | FR-080 | Das System muss einen hellen und einen dunklen Darstellungsmodus (Light/Dark Theme) unterstützen. | Niedrig | v1.0.1 |
| FR-071 | Die Theme-Präferenz des Benutzers muss persistent gespeichert werden. | Niedrig | | | FR-081 | Die Theme-Präferenz des Benutzers muss persistent gespeichert werden. | Niedrig | v1.0.1 |
| FR-072 | Das System muss beim erstmaligen Laden die System-Präferenz (`prefers-color-scheme`) berücksichtigen. | Niedrig | | | 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** | | | | | **Update-Management** | | | |
| FR-080 | Das System muss periodisch prüfen, ob eine neuere Version verfügbar ist. | Niedrig | | | FR-110 | Das System muss periodisch prüfen, ob eine neuere Version verfügbar ist. | Niedrig | v1.0.3 |
| FR-081 | Bei Verfügbarkeit einer neueren Version muss ein diskreter Indikator im Header angezeigt werden. | Niedrig | | | FR-111 | Bei Verfügbarkeit einer neueren Version muss ein diskreter Indikator im Header angezeigt werden. | Niedrig | v1.0.3 |
| FR-082 | Benutzer müssen eine Versionsliste mit Installationslinks einsehen können (Versionsmenü). | Niedrig | | | FR-112 | Benutzer müssen eine Versionsliste mit Installationslinks einsehen können (Versionsmenü). | Niedrig | v1.3.0 |
| FR-083 | Es muss möglich sein, zu einer älteren Version zurückzukehren (Downgrade). | Niedrig | | | FR-113 | Es muss möglich sein, zu einer älteren Version zurückzukehren (Downgrade). | Niedrig | v1.3.0 |
| FR-084 | Ein Dev-Mode muss es ermöglichen, zwischen stabilen Releases und Entwicklungs-Tags umzuschalten. | Niedrig | | | FR-114 | Ein Dev-Mode muss es ermöglichen, zwischen stabilen Releases und Entwicklungs-Tags umzuschalten. | Niedrig | v1.3.0 |
## 3. Nicht-funktionale Anforderungen ## 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-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-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 | | **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 ## 4. Technische Randbedingungen
* **Deployment**: Das System wird als Bookmarklet ausgeliefert, das auf der Bessa-Webseite ausgeführt wird. * **Deployment**: Das System wird als Bookmarklet ausgeliefert, das auf der Bessa-Webseite ausgeführt wird.
+2 -1
View File
@@ -271,7 +271,8 @@ echo "✅ All build tests passed."
echo "" echo ""
echo "=== Tagging $VERSION ===" echo "=== Tagging $VERSION ==="
if git rev-parse "$VERSION" >/dev/null 2>&1; then 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 else
git tag "$VERSION" git tag "$VERSION"
echo "✅ Created tag: $VERSION" echo "✅ Created tag: $VERSION"
+3
View File
@@ -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) ## v1.3.0 (2026-02-16)
- **Feature**: GitHub Release Management 📦 - **Feature**: GitHub Release Management 📦
- Version-Menü: Klick auf Versionsnummer zeigt alle verfügbaren Versionen - Version-Menü: Klick auf Versionsnummer zeigt alle verfügbaren Versionen
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+10 -6
View File
File diff suppressed because one or more lines are too long
+41 -7
View File
@@ -1807,7 +1807,7 @@ body {
<div class="brand"> <div class="brand">
<span class="material-icons-round logo-icon">restaurant_menu</span> <span class="material-icons-round logo-icon">restaurant_menu</span>
<div class="header-left"> <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 id="last-updated-subtitle" class="subtitle"></div>
</div> </div>
</div> </div>
@@ -1919,7 +1919,7 @@ body {
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div style="margin-bottom: 1rem;"> <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>
<div class="dev-toggle"> <div class="dev-toggle">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;"> <label style="display:flex;align-items:center;gap:8px;cursor:pointer;">
@@ -2532,6 +2532,34 @@ body {
return false; 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) === // === Menu Data Fetching (Direct from Bessa API) ===
async function loadMenuDataFromAPI() { async function loadMenuDataFromAPI() {
const loading = document.getElementById('loading'); const loading = document.getElementById('loading');
@@ -3243,7 +3271,7 @@ body {
// Periodic update check (runs on init + every hour) // Periodic update check (runs on init + every hour)
async function checkForUpdates() { async function checkForUpdates() {
const currentVersion = 'v1.3.0'; const currentVersion = 'v1.3.1';
const devMode = localStorage.getItem('kantine_dev_mode') === 'true'; const devMode = localStorage.getItem('kantine_dev_mode') === 'true';
try { try {
@@ -3284,7 +3312,7 @@ body {
const modal = document.getElementById('version-modal'); const modal = document.getElementById('version-modal');
const container = document.getElementById('version-list-container'); const container = document.getElementById('version-list-container');
const devToggle = document.getElementById('dev-mode-toggle'); const devToggle = document.getElementById('dev-mode-toggle');
const currentVersion = 'v1.3.0'; const currentVersion = 'v1.3.1';
if (!modal) return; if (!modal) return;
modal.classList.remove('hidden'); modal.classList.remove('hidden');
@@ -3487,13 +3515,19 @@ body {
updateAuthUI(); updateAuthUI();
cleanupExpiredFlags(); 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(); const hadCache = loadMenuCache();
if (hadCache) { if (hadCache) {
// Hide loading spinner since cache is shown
document.getElementById('loading').classList.add('hidden'); 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 // Auto-start polling if already logged in
if (authToken) { if (authToken) {
+37 -3
View File
@@ -796,6 +796,34 @@
return false; 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) === // === Menu Data Fetching (Direct from Bessa API) ===
async function loadMenuDataFromAPI() { async function loadMenuDataFromAPI() {
const loading = document.getElementById('loading'); const loading = document.getElementById('loading');
@@ -1751,13 +1779,19 @@
updateAuthUI(); updateAuthUI();
cleanupExpiredFlags(); 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(); const hadCache = loadMenuCache();
if (hadCache) { if (hadCache) {
// Hide loading spinner since cache is shown
document.getElementById('loading').classList.add('hidden'); 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 // Auto-start polling if already logged in
if (authToken) { if (authToken) {
+2 -1
View File
@@ -107,7 +107,8 @@ try {
[/function\s+fetchVersions/, 'fetchVersions function'], [/function\s+fetchVersions/, 'fetchVersions function'],
[/function\s+isNewer/, 'isNewer function'], [/function\s+isNewer/, 'isNewer function'],
[/function\s+openVersionMenu/, 'openVersionMenu 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) { for (const [regex, label] of checks) {
+1 -1
View File
@@ -1 +1 @@
v1.3.0 v1.3.1