Files
WrestleDesk/docs/superpowers/specs/2026-03-23-leistungstest-design.md
Andrej Spielmann 3fefc550fe Initial commit: WrestleDesk full project
- Django backend with DRF (clubs, wrestlers, trainers, exercises, templates, trainings, homework, locations, leistungstest)
- Next.js 16 frontend with React, Shadcn UI, Tailwind
- JWT authentication
- Full CRUD for all entities
- Calendar view for trainings
- Homework management system
- Leistungstest tracking
2026-03-26 13:24:57 +01:00

209 lines
5.8 KiB
Markdown

# Leistungstest Design
## Date: 2026-03-23
## Status: Approved
## Overview
Create a "Leistungstest" (Performance Test) page for creating fitness test templates and assigning them to wrestlers. Each test records exercise results, total time, and rating. Results are tracked over time with progress visualization and leaderboards.
## Design
### Layout
Single page with 4 tabs:
- **Vorlagen** (📋) — Create/edit/delete test templates
- **Zuweisen** (📝) — Assign template to wrestler, record results
- **Ergebnisse** (📊) — View results with progress tracking
- **Leaderboard** (🏆) — Rankings by template
Plus: Sidebar navigation item "Leistungstest"
### Tab 1: Vorlagen
**Template List:**
- Card for each template showing name, exercise list, usage count
- Delete button on each card
**Create Template Form:**
- Name input
- Dynamic list of exercises with target reps
- Add/remove exercise buttons
- Save button
### Tab 2: Zuweisen
**Selection:**
- Wrestler dropdown (shows names, not IDs)
- Template dropdown (shows names, not IDs)
**Test Form (when both selected):**
- List of exercises from template
- For each exercise: target reps input + actual result input
- Total time input (minutes)
- Overall rating (5 stars)
- Notes textarea
- Submit button
### Tab 3: Ergebnisse
**Filters:**
- Wrestler dropdown
- Template dropdown
**Results Table:**
- Columns: Date, Wrestler, Template, Score (%), Rating, Time
- Sorted by date (newest first)
**Progress Section (when one wrestler + one template selected):**
- Shows improvement over time for each exercise
- Progress bars with percentage change
### Tab 4: Leaderboard
**Selection:**
- Template dropdown
**Rankings Table:**
- Columns: Rank, Wrestler, Score %, Rating, Time
- Sorted by score (highest first)
- Medal icons for top 3 (🥇🥈🥉)
## Data Models
### Backend Model: LeistungstestTemplate
```python
class LeistungstestTemplate(models.Model):
name = CharField(max_length=200)
created_at = DateTimeField(auto_now_add=True)
updated_at = DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
```
### Backend Model: LeistungstestTemplateExercise
```python
class LeistungstestTemplateExercise(models.Model):
template = ForeignKey(LeistungstestTemplate, related_name='exercises')
exercise = ForeignKey('exercises.Exercise')
target_reps = PositiveIntegerField()
order = IntegerField(default=0)
class Meta:
ordering = ['template', 'order']
unique_together = ['template', 'exercise']
```
### Backend Model: LeistungstestResult
```python
class LeistungstestResult(models.Model):
template = ForeignKey(LeistungstestTemplate)
wrestler = ForeignKey('wrestlers.Wrestler')
total_time_minutes = PositiveIntegerField(null=True, blank=True)
rating = PositiveSmallIntegerField(choices=[(1,1),(2,2),(3,3),(4,4),(5,5)], default=3)
notes = TextField(blank=True)
completed_at = DateTimeField(default=timezone.now)
created_at = DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-completed_at']
indexes = [
Index(fields=['wrestler']),
Index(fields=['template']),
Index(fields=['completed_at']),
]
```
### Backend Model: LeistungstestResultItem
```python
class LeistungstestResultItem(models.Model):
result = ForeignKey(LeistungstestResult, related_name='items')
exercise = ForeignKey('exercises.Exercise')
target_reps = PositiveIntegerField()
actual_reps = PositiveIntegerField()
order = IntegerField(default=0)
class Meta:
ordering = ['result', 'order']
```
## API Endpoints
```
# Templates
GET /api/v1/leistungstest/templates/ — List templates
POST /api/v1/leistungstest/templates/ — Create template
GET /api/v1/leistungstest/templates/{id}/ — Get template
PATCH /api/v1/leistungstest/templates/{id}/ — Update template
DELETE /api/v1/leistungstest/templates/{id}/ — Delete template
# Template Exercises
POST /api/v1/leistungstest/template-exercises/ — Add exercise to template
DELETE /api/v1/leistungstest/template-exercises/{id}/ — Remove exercise
# Results
GET /api/v1/leistungstest/results/ — List results (filterable)
POST /api/v1/leistungstest/results/ — Create result
GET /api/v1/leistungstest/results/{id}/ — Get result
DELETE /api/v1/leistungstest/results/{id}/ — Delete result
# Leaderboard
GET /api/v1/leistungstest/leaderboard/ — Get rankings by template
```
## Response Shapes
### Template Response
```json
{
"id": 1,
"name": "Kraft-Test",
"exercises": [
{"id": 1, "exercise": 1, "exercise_name": "Klimmzüge", "target_reps": 20, "order": 0},
{"id": 2, "exercise": 2, "exercise_name": "Liegestütze", "target_reps": 50, "order": 1}
],
"usage_count": 12,
"created_at": "2026-03-20T10:00:00Z"
}
```
### Create Result Request
```json
{
"template": 1,
"wrestler": 1,
"total_time_minutes": 12,
"rating": 4,
"notes": "Gute Leistung",
"items": [
{"exercise": 1, "target_reps": 20, "actual_reps": 20},
{"exercise": 2, "target_reps": 50, "actual_reps": 48}
]
}
```
### Leaderboard Response
```json
{
"template": {"id": 1, "name": "Kraft-Test"},
"rankings": [
{"rank": 1, "wrestler": {"id": 2, "name": "Anna S."}, "score_percent": 100, "rating": 5, "time_minutes": 10},
{"rank": 2, "wrestler": {"id": 1, "name": "Max M."}, "score_percent": 96, "rating": 4, "time_minutes": 12}
]
}
```
## Implementation Notes
- Wrestler and template dropdowns show names, not IDs (use SelectValue with find)
- Score = (sum of actual_reps / sum of target_reps) * 100
- Results table shows score as percentage with progress bar
- Leaderboard only shows wrestlers who have done the specific template
- Progress tracking shows change in score between first and latest result for same wrestler+template