chore(version): update version and changelog for release 0.8.134
All checks were successful
Deploy Development / deploy (push) Successful in 42s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m12s
All checks were successful
Deploy Development / deploy (push) Successful in 42s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m12s
- Bumped APP_VERSION to 0.8.134 and updated the changelog to reflect recent changes. - Continued Frontend Phase 4 with the introduction of the `frontend/src/api/planning.js` module for training planning. - Updated architecture documentation to include details on the new `planning.js` API and its integration with the existing client structure. - Enhanced `utils/api.js` to re-export the new planning module, streamlining API access.
This commit is contained in:
parent
8f5af49a6f
commit
8175e239b4
|
|
@ -1,6 +1,6 @@
|
|||
# Shinkan Jinkendo Version Information
|
||||
|
||||
APP_VERSION = "0.8.133"
|
||||
APP_VERSION = "0.8.134"
|
||||
BUILD_DATE = "2026-05-12"
|
||||
DB_SCHEMA_VERSION = "20260514062"
|
||||
|
||||
|
|
@ -36,6 +36,13 @@ MODULE_VERSIONS = {
|
|||
}
|
||||
|
||||
CHANGELOG = [
|
||||
{
|
||||
"version": "0.8.134",
|
||||
"date": "2026-05-14",
|
||||
"changes": [
|
||||
"Frontend Phase 4 Welle 2: frontend/src/api/planning.js (Trainingsplanung); utils/api.js re-exportiert Modul, api-Objekt spread planning.",
|
||||
],
|
||||
},
|
||||
{
|
||||
"version": "0.8.133",
|
||||
"date": "2026-05-14",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ Dieses Bündel ist die **Leitlinie für die große Refaktorierung** nach dem MVP
|
|||
| [ZIELBILD_ARCHITEKTUR.md](./ZIELBILD_ARCHITEKTUR.md) | Zielarchitektur (Frontend, API, Daten), Qualitätsziele, Einbindung neuer Features |
|
||||
| [SCHULDEN_UND_REMEDIATION.md](./SCHULDEN_UND_REMEDIATION.md) | Erfasste Architekturschuld, Reihenfolge und Massnahmen zur Behebung |
|
||||
| [UMSETZUNGSPLAN_ROADMAP.md](./UMSETZUNGSPLAN_ROADMAP.md) | Phasen, Meilensteine, Abnahmekriterien, Aufwandsschwerpunkte |
|
||||
| [`frontend/src/api/client.js`](../../frontend/src/api/client.js) | Phase 4: zentraler HTTP-Client (`request`); `utils/api.js` bleibt Facade |
|
||||
| [`frontend/src/api/client.js`](../../frontend/src/api/client.js) | Phase 4: zentraler HTTP-Client (`request`, `ACTIVE_CLUB_STORAGE_KEY`) |
|
||||
| [`frontend/src/api/planning.js`](../../frontend/src/api/planning.js) | Phase 4: Trainingsplanung (Einheiten, Vorlagen, Module, Rahmen, KPIs) |
|
||||
| [BASELINE_SNAPSHOT.md](./BASELINE_SNAPSHOT.md) | Phase 0: Bundle-, API- und Last-Baseline (Messvorlagen, Vergleich nach Phase 2) |
|
||||
| [VERBINDLICHE_REGELN_SHINKAN.md](./VERBINDLICHE_REGELN_SHINKAN.md) | **Verbindliche** Shinkan-spezifische Regeln (Ergänzung zu den globalen Rules) |
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
- **Phase 2:** **abgeschlossen** (2026-05-14) — Indizes 058–062, Keyset `/api/exercises` + `/api/training-units`, **`/api/dashboard/kpis`** inkl. `training_home`, EXPLAIN-Vorlagen **`scripts/load/explain-readpaths.sql`**.
|
||||
- **Offen Phase 1:** Inbox optional **TTL** / nur bei sichtbarem Widget.
|
||||
- **Phase 3 (abgeschlossen 2026-05-14):** Übungsliste modularisiert; Trainingsplanung/Übungsformular: **Page-Dateien unter Soft-Limit** — Implementierung in `TrainingPlanningPageRoot.jsx`, `ExerciseFormPageRoot.jsx`, `ExercisesListPageRoot.jsx`; `pages/*.jsx` nur Re-Export. Playwright **Tests 9–10**.
|
||||
- **Phase 4 (gestartet 2026-05-14):** API **Welle 1** — `frontend/src/api/client.js` (`request`); `utils/api.js` bleibt Facade.
|
||||
- **Phase 4 (fortlaufend 2026-05-14):** API **Welle 1** `client.js`; **Welle 2** `planning.js`; `utils/api.js` bleibt Facade (`export *`, `api`-Objekt `...planning`).
|
||||
|
||||
**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).
|
||||
|
|
@ -93,13 +93,14 @@
|
|||
|
||||
## Phase 4 – API-Client Modularisierung
|
||||
|
||||
**Status:** **gestartet** (2026-05-14) — Welle 1: **`frontend/src/api/client.js`** (`request`, `ACTIVE_CLUB_STORAGE_KEY`); **`utils/api.js`** bleibt vollständige Facade (bestehende Importe unverändert).
|
||||
**Status:** **fortlaufend** (2026-05-14) — Welle 1: **`client.js`**; Welle 2: **`planning.js`**; **`utils/api.js`** bleibt vollständige Facade.
|
||||
|
||||
**Fokus:** Wartbarkeit für viele neue Features.
|
||||
|
||||
| Task | Bezug | Status |
|
||||
|------|-------|--------|
|
||||
| `frontend/src/api/client.js` — zentraler HTTP-Client | A2 | erledigt (Welle 1) |
|
||||
| `frontend/src/api/planning.js` — Trainingsplanung (Einheiten, Vorlagen, Module, Rahmen, Dashboard-KPIs) | A2 | erledigt (Welle 2) |
|
||||
| Domänen-Module unter `frontend/src/api/` + schrittweise Entlastung von `api.js` | A2 | offen |
|
||||
| Neue Endpoints primär in Domänen-Dateien | S3 | offen |
|
||||
|
||||
|
|
|
|||
171
frontend/src/api/planning.js
Normal file
171
frontend/src/api/planning.js
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* Trainingsplanung: Einheiten, Vorlagen, Module, Rahmenprogramme, Dashboard-KPIs.
|
||||
* Facade: weiterhin `utils/api.js` (default + Named Exports).
|
||||
*/
|
||||
import { request } from './client.js'
|
||||
|
||||
/** Query-Parameter wie GET /api/training-units. */
|
||||
export async function listTrainingUnits(filters = {}) {
|
||||
const q = new URLSearchParams()
|
||||
if (filters.group_id != null && filters.group_id !== '') {
|
||||
q.set('group_id', String(filters.group_id))
|
||||
}
|
||||
if (filters.club_id != null && filters.club_id !== '') {
|
||||
q.set('club_id', String(filters.club_id))
|
||||
}
|
||||
if (filters.start_date) q.set('start_date', filters.start_date)
|
||||
if (filters.end_date) q.set('end_date', filters.end_date)
|
||||
if (filters.status) q.set('status', filters.status)
|
||||
if (filters.debrief_pending === true) q.set('debrief_pending', 'true')
|
||||
if (filters.assigned_to_me === true) q.set('assigned_to_me', 'true')
|
||||
if (filters.sort) q.set('sort', String(filters.sort))
|
||||
if (filters.limit != null && filters.limit !== '') q.set('limit', String(filters.limit))
|
||||
if (filters.cursor_planned_date) q.set('cursor_planned_date', String(filters.cursor_planned_date))
|
||||
if (filters.cursor_planned_time != null && filters.cursor_planned_time !== '') {
|
||||
q.set('cursor_planned_time', String(filters.cursor_planned_time))
|
||||
}
|
||||
if (filters.cursor_id != null && filters.cursor_id !== '') q.set('cursor_id', String(filters.cursor_id))
|
||||
const qs = q.toString()
|
||||
return request(`/api/training-units${qs ? `?${qs}` : ''}`)
|
||||
}
|
||||
|
||||
/** Dashboard Kurzüberblick: Entwürfe / meine Übungen / YTD abgeschlossene Einheiten (ein Roundtrip). */
|
||||
export async function getDashboardKpis() {
|
||||
return request('/api/dashboard/kpis')
|
||||
}
|
||||
|
||||
/** Dashboard: Übungen in geplanten Einheiten, die für den Verein noch auf Sichtbarkeit „Verein“ gehören. */
|
||||
export async function getTrainingExerciseClubVisibilityQueue(filters = {}) {
|
||||
const q = new URLSearchParams()
|
||||
if (filters.start_date) q.set('start_date', String(filters.start_date))
|
||||
if (filters.end_date) q.set('end_date', String(filters.end_date))
|
||||
if (filters.assigned_to_me === false) q.set('assigned_to_me', 'false')
|
||||
if (filters.limit_units != null && filters.limit_units !== '') {
|
||||
q.set('limit_units', String(filters.limit_units))
|
||||
}
|
||||
const qs = q.toString()
|
||||
return request(`/api/training-units/exercises-club-visibility-queue${qs ? `?${qs}` : ''}`)
|
||||
}
|
||||
|
||||
export async function getTrainingUnit(id) {
|
||||
return request(`/api/training-units/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingUnit(data) {
|
||||
return request('/api/training-units', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingUnit(id, data) {
|
||||
return request(`/api/training-units/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingUnit(id) {
|
||||
return request(`/api/training-units/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
export async function quickCreateTrainingUnit(data) {
|
||||
return request('/api/training-units/quick-create', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
/** Rahmen-Slot → geplante Einheit (tiefe Kopie, origin_framework_slot_id). */
|
||||
export async function createTrainingUnitFromFrameworkSlot(data) {
|
||||
return request('/api/training-units/from-framework-slot', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function listTrainingPlanTemplates() {
|
||||
return request('/api/training-plan-templates')
|
||||
}
|
||||
|
||||
export async function getTrainingPlanTemplate(id) {
|
||||
return request(`/api/training-plan-templates/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingPlanTemplate(data) {
|
||||
return request('/api/training-plan-templates', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingPlanTemplate(id, data) {
|
||||
return request(`/api/training-plan-templates/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingPlanTemplate(id) {
|
||||
return request(`/api/training-plan-templates/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
export async function listTrainingModules() {
|
||||
return request('/api/training-modules')
|
||||
}
|
||||
|
||||
export async function getTrainingModule(id) {
|
||||
return request(`/api/training-modules/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingModule(data) {
|
||||
return request('/api/training-modules', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingModule(id, data) {
|
||||
return request(`/api/training-modules/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingModule(id) {
|
||||
return request(`/api/training-modules/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
/** Kopiert Modul-Inhalte ans Ende eines Abschnitts (section_order_index 0-basiert). */
|
||||
export async function applyTrainingModuleToTrainingUnit(unitId, data) {
|
||||
return request(`/api/training-units/${unitId}/apply-training-module`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function listTrainingFrameworkPrograms() {
|
||||
return request('/api/training-framework-programs')
|
||||
}
|
||||
|
||||
export async function getTrainingFrameworkProgram(id) {
|
||||
return request(`/api/training-framework-programs/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingFrameworkProgram(data) {
|
||||
return request('/api/training-framework-programs', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingFrameworkProgram(id, data) {
|
||||
return request(`/api/training-framework-programs/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingFrameworkProgram(id) {
|
||||
return request(`/api/training-framework-programs/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
|
@ -7,8 +7,10 @@
|
|||
import { stripHtmlToText } from './htmlUtils'
|
||||
import { normalizeAdvanceMode, parseComboRepSeriesCountUi } from './combinationMethodProfileUi'
|
||||
import { request, ACTIVE_CLUB_STORAGE_KEY } from '../api/client.js'
|
||||
import * as planning from '../api/planning.js'
|
||||
|
||||
export { ACTIVE_CLUB_STORAGE_KEY }
|
||||
export * from '../api/planning.js'
|
||||
|
||||
// ============================================================================
|
||||
// Auth
|
||||
|
|
@ -1253,176 +1255,6 @@ export async function deleteTrainerContext(id) {
|
|||
return request(`/api/trainer-contexts/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Training Planning
|
||||
// ============================================================================
|
||||
|
||||
/** Query-Parameter wie GET /api/training-units. */
|
||||
export async function listTrainingUnits(filters = {}) {
|
||||
const q = new URLSearchParams()
|
||||
if (filters.group_id != null && filters.group_id !== '') {
|
||||
q.set('group_id', String(filters.group_id))
|
||||
}
|
||||
if (filters.club_id != null && filters.club_id !== '') {
|
||||
q.set('club_id', String(filters.club_id))
|
||||
}
|
||||
if (filters.start_date) q.set('start_date', filters.start_date)
|
||||
if (filters.end_date) q.set('end_date', filters.end_date)
|
||||
if (filters.status) q.set('status', filters.status)
|
||||
if (filters.debrief_pending === true) q.set('debrief_pending', 'true')
|
||||
if (filters.assigned_to_me === true) q.set('assigned_to_me', 'true')
|
||||
if (filters.sort) q.set('sort', String(filters.sort))
|
||||
if (filters.limit != null && filters.limit !== '') q.set('limit', String(filters.limit))
|
||||
if (filters.cursor_planned_date) q.set('cursor_planned_date', String(filters.cursor_planned_date))
|
||||
if (filters.cursor_planned_time != null && filters.cursor_planned_time !== '') {
|
||||
q.set('cursor_planned_time', String(filters.cursor_planned_time))
|
||||
}
|
||||
if (filters.cursor_id != null && filters.cursor_id !== '') q.set('cursor_id', String(filters.cursor_id))
|
||||
const qs = q.toString()
|
||||
return request(`/api/training-units${qs ? `?${qs}` : ''}`)
|
||||
}
|
||||
|
||||
/** Dashboard Kurzüberblick: Entwürfe / meine Übungen / YTD abgeschlossene Einheiten (ein Roundtrip). */
|
||||
export async function getDashboardKpis() {
|
||||
return request('/api/dashboard/kpis')
|
||||
}
|
||||
|
||||
/** Dashboard: Übungen in geplanten Einheiten, die für den Verein noch auf Sichtbarkeit „Verein“ gehören. */
|
||||
export async function getTrainingExerciseClubVisibilityQueue(filters = {}) {
|
||||
const q = new URLSearchParams()
|
||||
if (filters.start_date) q.set('start_date', String(filters.start_date))
|
||||
if (filters.end_date) q.set('end_date', String(filters.end_date))
|
||||
if (filters.assigned_to_me === false) q.set('assigned_to_me', 'false')
|
||||
if (filters.limit_units != null && filters.limit_units !== '') {
|
||||
q.set('limit_units', String(filters.limit_units))
|
||||
}
|
||||
const qs = q.toString()
|
||||
return request(`/api/training-units/exercises-club-visibility-queue${qs ? `?${qs}` : ''}`)
|
||||
}
|
||||
|
||||
export async function getTrainingUnit(id) {
|
||||
return request(`/api/training-units/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingUnit(data) {
|
||||
return request('/api/training-units', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingUnit(id, data) {
|
||||
return request(`/api/training-units/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingUnit(id) {
|
||||
return request(`/api/training-units/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
export async function quickCreateTrainingUnit(data) {
|
||||
return request('/api/training-units/quick-create', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
/** Rahmen-Slot → geplante Einheit (tiefe Kopie, origin_framework_slot_id). */
|
||||
export async function createTrainingUnitFromFrameworkSlot(data) {
|
||||
return request('/api/training-units/from-framework-slot', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
export async function listTrainingPlanTemplates() {
|
||||
return request('/api/training-plan-templates')
|
||||
}
|
||||
|
||||
export async function getTrainingPlanTemplate(id) {
|
||||
return request(`/api/training-plan-templates/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingPlanTemplate(data) {
|
||||
return request('/api/training-plan-templates', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingPlanTemplate(id, data) {
|
||||
return request(`/api/training-plan-templates/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingPlanTemplate(id) {
|
||||
return request(`/api/training-plan-templates/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
export async function listTrainingModules() {
|
||||
return request('/api/training-modules')
|
||||
}
|
||||
|
||||
export async function getTrainingModule(id) {
|
||||
return request(`/api/training-modules/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingModule(data) {
|
||||
return request('/api/training-modules', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingModule(id, data) {
|
||||
return request(`/api/training-modules/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingModule(id) {
|
||||
return request(`/api/training-modules/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
/** Kopiert Modul-Inhalte ans Ende eines Abschnitts (section_order_index 0-basiert). */
|
||||
export async function applyTrainingModuleToTrainingUnit(unitId, data) {
|
||||
return request(`/api/training-units/${unitId}/apply-training-module`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function listTrainingFrameworkPrograms() {
|
||||
return request('/api/training-framework-programs')
|
||||
}
|
||||
|
||||
export async function getTrainingFrameworkProgram(id) {
|
||||
return request(`/api/training-framework-programs/${id}`)
|
||||
}
|
||||
|
||||
export async function createTrainingFrameworkProgram(data) {
|
||||
return request('/api/training-framework-programs', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateTrainingFrameworkProgram(id, data) {
|
||||
return request(`/api/training-framework-programs/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteTrainingFrameworkProgram(id) {
|
||||
return request(`/api/training-framework-programs/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Version & Health
|
||||
// ============================================================================
|
||||
|
|
@ -1534,32 +1366,8 @@ export const api = {
|
|||
createExerciseProgressionSequence,
|
||||
deleteExerciseProgressionEdgesBatch,
|
||||
|
||||
// Training Planning
|
||||
listTrainingUnits,
|
||||
getDashboardKpis,
|
||||
getTrainingExerciseClubVisibilityQueue,
|
||||
getTrainingUnit,
|
||||
createTrainingUnit,
|
||||
updateTrainingUnit,
|
||||
deleteTrainingUnit,
|
||||
quickCreateTrainingUnit,
|
||||
createTrainingUnitFromFrameworkSlot,
|
||||
listTrainingPlanTemplates,
|
||||
getTrainingPlanTemplate,
|
||||
createTrainingPlanTemplate,
|
||||
updateTrainingPlanTemplate,
|
||||
deleteTrainingPlanTemplate,
|
||||
listTrainingModules,
|
||||
getTrainingModule,
|
||||
createTrainingModule,
|
||||
updateTrainingModule,
|
||||
deleteTrainingModule,
|
||||
applyTrainingModuleToTrainingUnit,
|
||||
listTrainingFrameworkPrograms,
|
||||
getTrainingFrameworkProgram,
|
||||
createTrainingFrameworkProgram,
|
||||
updateTrainingFrameworkProgram,
|
||||
deleteTrainingFrameworkProgram,
|
||||
// Training Planning → frontend/src/api/planning.js
|
||||
...planning,
|
||||
|
||||
// Catalogs
|
||||
listFocusAreas,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user