From 657fcc241a384ceae267657af815c027b203ec51 Mon Sep 17 00:00:00 2001 From: Lars Date: Thu, 14 May 2026 08:36:31 +0200 Subject: [PATCH] chore(version): update version and changelog for release 0.8.116 - Bumped APP_VERSION to 0.8.116 and updated the changelog to reflect changes, including the implementation of a new loading strategy for the Org-Inbox that utilizes requestIdleCallback to optimize API calls during dashboard initialization. - Updated documentation to reflect the new app version and its corresponding changes. --- backend/version.py | 9 +++++- docs/HANDOVER.md | 4 +-- docs/architecture/UMSETZUNGSPLAN_ROADMAP.md | 4 +-- frontend/src/context/OrgInboxContext.jsx | 32 +++++++++++++++++++-- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/backend/version.py b/backend/version.py index c3e9e88..084702b 100644 --- a/backend/version.py +++ b/backend/version.py @@ -1,6 +1,6 @@ # Shinkan Jinkendo Version Information -APP_VERSION = "0.8.115" +APP_VERSION = "0.8.116" BUILD_DATE = "2026-05-12" DB_SCHEMA_VERSION = "20260514060" @@ -36,6 +36,13 @@ MODULE_VERSIONS = { } CHANGELOG = [ + { + "version": "0.8.116", + "date": "2026-05-14", + "changes": [ + "Frontend: Org-Posteingang lädt beim ersten Mount per requestIdleCallback (Fallback setTimeout), um parallele API-Aufrufe beim Dashboard-Start zu entzerren; refresh/Inbox-Seite unverändert sofort.", + ], + }, { "version": "0.8.115", "date": "2026-05-14", diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md index 93da39b..91a18df 100644 --- a/docs/HANDOVER.md +++ b/docs/HANDOVER.md @@ -1,7 +1,7 @@ # Shinkan Jinkendo – Entwicklungsstand & Handover **Stand:** 2026-05-14 -**App-Version / DB-Schema:** App **0.8.115**, DB-Schema **`20260514060`** (`backend/version.py`: `APP_VERSION`, `DB_SCHEMA_VERSION`) +**App-Version / DB-Schema:** App **0.8.116**, DB-Schema **`20260514060`** (`backend/version.py`: `APP_VERSION`, `DB_SCHEMA_VERSION`) Diese Datei ist die **Einstiegs-Doku für neue Chat-Sessions**: Anforderungen im Detail stehen in `.claude/docs/` (siehe unten); hier der **implementierte Stand**, **Medien-Meilenstein** und **sinnvolle nächste Schritte**. @@ -76,7 +76,7 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl - **036 / 037:** Bibliotheks-Rahmen, Slot-Inhalt als **`training_units`** mit **`framework_slot_id`**; **`POST /api/training-units/from-framework-slot`**. - **Code:** `training_framework_programs.py`, `training_planning.py`; Frontend **`TrainingFrameworkProgramEditPage.jsx`**, **`createTrainingUnitFromFrameworkSlot`** in `api.js`. -### Trainingsmodule, Kombinationsübungen und Coach (Stand **0.8.115**) +### Trainingsmodule, Kombinationsübungen und Coach (Stand **0.8.116**) - **Fachspez & Drift-Schutz:** `.claude/docs/functional/Shinkan Trainingsmodule Kombinationsuebungen Spezifikation V2.md` (**§ 10.2.1** IDs, **§ 10.4** Coaching-Stufen, **§ 10.6** Produkt-Backlog, **Anhang A** Abgleich). - **Umsetzungsplan:** `.claude/docs/working/TRAINING_MODULES_IMPLEMENTATION_PLAN.md` (Phase **2** / **4** teilweise; Pakete **4a–g** — u. a. **4e** Archetyp-Admin, **4f** Massen-Vorbelegung, **4g** Backend-Validierung). diff --git a/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md b/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md index 44fe8ad..1be7704 100644 --- a/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md +++ b/docs/architecture/UMSETZUNGSPLAN_ROADMAP.md @@ -7,7 +7,7 @@ - **Phase 1 (Teil):** Org-Inbox: **ein** gemeinsamer Ladepfad `fetchOrgInboxSnapshot` für Mount-`useEffect` und `refreshOrgInbox` (gleiche Requests, weniger Drift-Risiko; Verhalten unverändert). - **Phase 1 / 2 (Teil):** Dashboard-KPIs: **`GET /api/dashboard/kpis`** (ein Roundtrip); Playwright-Test 8 angepasst. - **Phase 2 (Teil):** Listen-Indizes **058** (`exercises` Sortierung/`created_by`) und **059** (`training_units` Kalenderliste ohne Blueprint). -- **Offen Phase 1:** Inbox zeitlich entkoppeln nur nach Messung (optional). +- **Offen Phase 1:** Inbox nur noch Feinschliff (TTL); **verzögertes Erstlade** per Idle (weniger parallele Requests beim Dashboard-Start). **Ziel:** Nach MVP eine **nachhaltige** Architektur für Wachstum, **Performance** (Server + schwache Clients) und **sichere Feature-Erweiterung**. **Leitdokumente:** [ZIELBILD_ARCHITEKTUR.md](./ZIELBILD_ARCHITEKTUR.md), [SCHULDEN_UND_REMEDIATION.md](./SCHULDEN_UND_REMEDIATION.md), [VERBINDLICHE_REGELN_SHINKAN.md](./VERBINDLICHE_REGELN_SHINKAN.md). @@ -46,7 +46,7 @@ | Dashboard: `listTrainingUnits`-Reduktion (ein Call statt zweier identischer) | A3 | erledigt | | Dashboard: `listExercises`-Doppelabruf / Summary-Call | A3, B1 | erledigt (`GET /api/dashboard/kpis`) | | Org-Inbox: Ladestrategie; Umsetzung Teil 1 (gemeinsamer Ladepfad, keine doppelte Logik) | A3 | erledigt | -| Org-Inbox: TTL / verzögertes Laden (nur nach Bedarf) | A3 | optional, nach Messung | +| Org-Inbox: TTL / verzögertes Laden (nur nach Bedarf) | A3 | teils (Erstlade per `requestIdleCallback`, max. 1,5s) | **Abnahme:** Kein funktionales Leck; Netzwerk-Tab zeigt messbar weniger parallele gleiche Muster beim ersten Dashboard-Load. diff --git a/frontend/src/context/OrgInboxContext.jsx b/frontend/src/context/OrgInboxContext.jsx index a565204..5c6b6db 100644 --- a/frontend/src/context/OrgInboxContext.jsx +++ b/frontend/src/context/OrgInboxContext.jsx @@ -78,15 +78,43 @@ export function OrgInboxProvider({ user, children }) { return undefined } let cancelled = false - ;(async () => { + let idleId = null + let timeoutId = null + + const load = async () => { const snap = await fetchOrgInboxSnapshot(canAccess, canAccessReports) if (cancelled) return setItems(snap.items) setContentReports(snap.contentReports) setContentReportsError(canAccessReports ? snap.contentReportsError : null) - })() + } + + const schedule = () => { + if (cancelled) return + if (typeof window.requestIdleCallback === 'function') { + idleId = window.requestIdleCallback( + () => { + idleId = null + void load() + }, + { timeout: 1500 }, + ) + } else { + timeoutId = window.setTimeout(() => { + timeoutId = null + void load() + }, 0) + } + } + + schedule() + return () => { cancelled = true + if (idleId != null && typeof window.cancelIdleCallback === 'function') { + window.cancelIdleCallback(idleId) + } + if (timeoutId != null) window.clearTimeout(timeoutId) } }, [canAccess, canAccessReports, user?.id])