Adminoverblik
Brugerstyring
| Brugernavn | Visningsnavn | Rolle | Hold | Oprettet | |
|---|---|---|---|---|---|
Databaseoverblik
| Tabel | Rækker | Størrelse | Sidst opdateret |
|---|---|---|---|
Databaseskema
Holdværktøjer
Vælg et hold for at se spillere.
Holdrøntgen
Brugervejledning
TeamApp er en digital platform til sportshold, der samler coaching, spillerudvikling, træningsplanlægning og taktik på ét sted. Platformen styrker kommunikationen mellem trænere og spillere og giver bedre overblik over holdets udvikling.
Systemet består af to primære brugerflader: Coach-siden (browser-baseret) til trænere og administratorer, og Spiller-appen (PWA) der er optimeret til mobilbrug for spillere.
| Rolle | Adgang | Typisk bruger |
|---|---|---|
| Admin | Fuld adgang inkl. brugeradministration og systemindstillinger | Systemadministrator |
| Træner | Dashboard, kampe, spillere, træninger, åbninger, tegning | Cheftræner |
| Assistent | Fuld adgang til dashboard, kampnoter, spiller-indhold, træning, øvelsesark, tegning, modstander-scouting, styrke/skadeforebyggelse og Beach — men kun læsning i link-bibliotek og ingen adgang til omkostnings-satser/afregning | Assistenttræner |
| Spiller | Spiller-appen (PWA): forside, åbninger, kampe, udvikling. Ingen adgang til dashboard, kampnoter, spiller-indhold, træning, øvelsesark, tegning, modstander-scouting eller omkostninger — kun læsning i styrke- & skadeforebyggelse, Beach og link-bibliotek | Holdspiller |
Assistent har fuld adgang til de daglige coach-værktøjer på linje med træner, men ikke til link-bibliotek eller
omkostnings-satser/afregning. Spiller har slet ingen adgang til coach-værktøjerne eller til omkostninger (kun til spiller-appen,
samt læsning i Beach og link-bibliotek). Håndhæves to steder: i api.php blokerer requireTraener() skrivekald
server-side (assistent slipper igennem, undtagen ved requireTraenerKunIkkeAssistent()-endpoints), og et separat
rolle-tjek blokerer al adgang (læsning og skrivning) for spiller til de coach-specifikke endpoints. Siderne selv
omdirigerer en spiller væk med det samme (til spiller.html), og deaktiverer skriveknapper for assistent/spiller hvor relevant.
| Område | Admin | Træner | Assistent | Spiller |
|---|---|---|---|---|
| Admin-panel (admin.html) | Fuld adgang | — | — | — |
| Dashboard, kampnoter, spiller-indhold, træning, øvelsesark, tegning, modstander-scouting | Fuld adgang | Fuld adgang | Fuld adgang | Ingen adgang |
| Beach håndbold | Fuld adgang | Fuld adgang | Fuld adgang | Kun læsning |
| Styrke & skadeforebyggelse (styrke-skade.html) | Fuld adgang | Fuld adgang | Fuld adgang | Kun læsning |
| Link-bibliotek (links-admin.html) | Fuld adgang | Fuld adgang | Kun læsning | Kun læsning |
| Omkostninger — egne udgifter og profil | ✓ | ✓ | ✓ | — |
| Omkostninger — andres udgifter, satser og afregning | Fuld adgang | Fuld adgang | — | — |
| Kommentarer og reaktioner (like) | Alle + slet andres | Alle + slet andres | Kun egne kan slettes | Kun egne kan slettes |
| Spiller-appen (spiller.html) | Adgang | Adgang | Adgang | Målgruppen |
Alle brugere logger ind via login.html med brugernavn og kodeord. Systemet gemmer en JWT-token lokalt og omdirigerer automatisk til den korrekte side baseret på brugerens rolle.
- Gå til login.html og indtast brugernavn + kodeord
- Systemet validerer og udsteder en JWT-token
- Trænere og admins videresendes til dashboard.html
- Spillere videresendes til spiller.html (PWA)
- Tokens udløber automatisk og kræver nyt login
Hoveddashboardet for trænere. Her oprettes og styres kampe, kampnoter, taktiske åbninger og spillerindhold. Sidebjælken giver hurtig navigation imellem funktioner.
- Log ind som træner og åbn dashboard.html
- Vælg eller opret en kamp i kampmenuen til venstre
- Tilføj taktiske noter, åbninger og spillerobservationer
- Del indhold med spillere via "Spiller-indhold" (spiller-admin.html)
- Se spillernes reaktioner og kommentarer på delt indhold
Den mobilvenlige spiller-app er implementeret som en PWA og kan installeres på spillerens telefon direkte fra browseren uden app store.
- Spilleren åbner spiller.html i mobilbrowseren og installerer appen
- Forside: Overblik over næste kamp og seneste opslag fra træneren
- Åbninger: Taktiske angrebsåbninger med video og tegning
- Kampe: Kampforberedelse og evaluering med noter og video
- Udvikling: Personlig udviklingsindhold opdelt i kategorier
- Refleksion: Personlige refleksioner efter kamp/træning — guidede spørgsmål med hurtigsvar, gemt lokalt på spillerens egen telefon (ingen serveradgang)
- Spilleren kan like og kommentere på alt delt indhold
Det interaktive tegneværktøj bruges til at illustrere taktiske spillesekvenser på et baneudsnit. Tegningerne gemmes og kan vedhæftes åbninger.
- Åbn tegneværktøjet fra dashboardet eller direkte via tegning.html
- Placer spillere (hold A / hold B) på banen med drag & drop
- Tegn bevægelses- og pasningslinjer med penselværktøjet
- Brug pileredskabet til at vise retning og spillerflow
- Gem tegningen – den tilknyttes automatisk den aktuelle åbning
Et scouting-ark pr. modstanderhold, hvor trænerteamet samler observationer før en kamp. Arket er koblet til dashboardet, hvor den aktuelle modstander får et link til sit ark, og noterne kan foldes ud i kampnoter.html under den aktuelle kamp.
- Søg i listen efter modstanderholdet, eller opret et nyt ark med holdets navn
- Noter typisk forsvarsformation (fx 6-0, 5-1) og angrebsstil
- Beskriv farlige spillere og målvogter-tendenser
- Tilføj generelle noter til resten af holdet
- Arket kan tilgås igen fra dashboardet, når holdet igen møder modstanderen
Træningsmodulet bruges til at planlægge og dokumentere træningssessioner med et struktureret øvelsesbibliotek.
- Opret en ny træningssession med dato og titel
- Tilføj øvelser fra biblioteket eller opret nye øvelser
- Angiv varighed og antal gentagelser per øvelse
- Gem sessionen – den er synlig for hele coachingteamet
Modulet har to faner: et fælles øvelsesbibliotek for hele klubben (delt på tværs af hold) og programmer, som det enkelte hold sammensætter af øvelser fra biblioteket.
- Bibliotek: Opret styrke-/skadeforebyggelsesøvelser med kategori, søg og filtrér i det klubfælles bibliotek
- Programmer: Sammensæt et program for jeres hold ved at tilføje øvelser fra biblioteket
- Programmer er hold-specifikke, mens biblioteket deles af hele klubben
En kurateret linksamling til håndbold-ressourcer (taktik, Instagram-profiler, regler, videokanaler m.m.), organiseret i op til to niveauer af kategorier. Den offentlige side links.html kræver ikke login — alle (spillere, forældre, trænere) kan browse og søge frit. Administrationen sker via links-admin.html (kræver login som træner/admin — assistent har kun læseadgang her, spiller slet ingen).
- Log ind som træner/admin og åbn links-admin.html
- Opret hovedkategorier (evt. med billede) og underkategorier under dem
- Opret enkelte links manuelt via "+ Nyt link", eller importér mange på én gang via "⬆ Importer links": vælg en mål-kategori, upload en CSV-fil med kolonnerne
titel,urlogbeskrivelse(en skabelon kan downloades i dialogen), gennemse forhåndsvisningen — rækker med manglende felter, ugyldige URL'er eller dubletter (i filen eller allerede i biblioteket) markeres og springes automatisk over — og bekræft importen - Brug "Tjek alle links" periodisk for at finde og rette døde links
- Se klik-statistik pr. link for at identificere de mest brugte ressourcer
Admin-panelet bruges til systemadministration og er kun tilgængeligt for brugere med admin-rollen.
- Overblik: Statistik over alle hold, brugere og data på tværs af systemet
- Brugere: Opret, nulstil kodeord, spær/genaktivér og slet brugere og spillere — samt importér en eksisterende spiller som login-bruger
- Database: Se diskforbrug og tabelstørrelser for alle tabeller
- Skema: Visualiser databaseskemaet — tabeller grupperet i domæner med kolonner og relationer
- Hold-værktøjer: Flyt spillere ved årgangsskifte, eller kopiér indhold (åbninger/øvelser) ikke-destruktivt til et andet hold
- Hold-røntgen: Se alt tilknyttet data for ét hold i dybden — roster, adgang, sæson, historik og sundhedsadvarsler
Tekniskspecifikation
TeamApp er en serverless-lean webapplikation baseret på statiske HTML/CSS/JS-sider der kommunikerer med en PHP-backend via REST API. Der er ingen build-pipeline – alt deployes direkte som statiske filer.
| Lag | Teknologi | Detaljer |
|---|---|---|
| Frontend | HTML5 · CSS3 · Vanilla JS | Ingen frameworks. Statiske filer på CDN/webhotel |
| Backend | PHP 8+ | api.php og admin2.php – REST-endpoints |
| Database | MySQL / MariaDB | Relationel database med JOINs og indeksering |
| Auth | JWT (JSON Web Tokens) | HS256-signerede tokens, gemt i localStorage |
| Hosting | teamapp.dk | Webhotel med PHP og MySQL support |
| PWA | Service Worker + Web App Manifest | Spiller-appen kan installeres og køre offline |
| Typografi | Google Fonts | Outfit · Space Grotesk · DM Mono |
Systemet anvender JWT-baseret autentificering. Login-flowet er:
- Brugeren sender
brugernavn+kodeordvia POST tilapi.php?action=login - Backend validerer credentials mod databasen (bcrypt-hashet kodeord)
- Returnerer JWT-token med payload:
{ id, navn, rolle, hold_id, exp } - Frontend gemmer token i
localStorage.kn_token - Alle efterfølgende API-kald sender token i
Authorization: Bearer <token> - Backend validerer signaturen og udløbsdatoen på hvert kald
Token-levetid: Sættes af backend-konfiguration. Fornyelse kræver nyt login.
Der er to API-filer: api.php til generel brug og admin2.php til admin-funktioner (kræver admin-rolle i JWT).
| Endpoint | Metode | Beskrivelse |
|---|---|---|
api.php?action=login | POST | Login – returnerer JWT token |
api.php?action=kampe | GET | Hent kampe for holdet |
api.php?action=aabninger | GET | Hent taktiske åbninger |
api.php?action=spillere | GET | Hent spillerliste |
api.php?action=traeninger | GET | Hent træningssessioner |
api.php?action=opret_spiller | POST | Opret ny spillerbruger |
admin2.php?action=overblik | GET | Alle hold med statistik (admin) |
admin2.php?action=brugere | GET | Alle brugere (admin) |
admin2.php?action=opret_bruger | POST | Opret ny bruger (admin) |
admin2.php?action=reset_kodeord | POST | Nulstil kodeord (admin) |
admin2.php?action=slet_bruger | DELETE | Slet bruger (admin) |
admin2.php?action=hold_spillere | GET | Spillere-roster for ét hold (admin) |
admin2.php?action=flyt_spillere | POST | Flyt udvalgte spillere til andet hold (admin) |
admin2.php?action=kopier_indhold | POST | Kopiér åbninger/øvelser/beach-indhold til andet hold, ikke-destruktivt (admin) |
admin2.php?action=hold_detalje | GET | Fuldt røntgenbillede af ét hold på tværs af alle moduler (admin) |
admin2.php?action=tabel_storrelse | GET | Database-statistik (admin) |
api.php?action=link_kategorier | GET | Alle link-kategorier, hierarkisk (offentligt, ingen auth) |
api.php?action=links | GET | Alle links, evt. filtreret på kategori/sortering (offentligt) |
api.php?action=link | POST | Opret nyt link, inkl. CSV-import (træner/admin, ikke assistent) |
api.php?action=valider_links | GET | HTTP HEAD-tjek af alle links – finder døde links (træner/admin) |
api.php?action=omkostninger | GET | Hent udgifter for holdet (egne, eller alles for træner/admin) |
api.php?action=afregninger | GET | Hent afregninger (træner/admin, ikke assistent) |
api.php?action=beach_noter | GET | Hent Beach-noter for holdet |
api.php?action=modstandere | GET | Hent modstander-scouting-ark for holdet |
api.php?action=fysiske_programmer | GET | Hent holdets styrke-/skadeforebyggelses-programmer |
Databasen er relationel MySQL med hold som central entitet. Al data er hold-isoleret via hold_id-fremmednøgler. Tabellisten herunder hentes live fra databasen (samme kilde som "Database"-siden), så den altid matcher den faktiske struktur.
| Tabel | Rækker | Sidst opdateret |
|---|---|---|
Spiller-appen (spiller.html) er implementeret som en PWA og kan installeres på iOS og Android uden en app store.
| Feature | Implementering |
|---|---|
| Installation | Web App Manifest – ikon, navn, display: standalone |
| Offline support | Service Worker cacher statiske assets |
| Ikoner | teamapp.dk/icons/ – 192px og 512px PNG |
| Push-notifikationer | Ikke implementeret (planlagt fremtidig feature) |
Globalt modul uden hold_id – to tabeller: link_kategorier (hierarkisk via selvreferentiel parent_id, max to niveauer) og links (med klik-tæller og manuel sortering).
| Mekanisme | Implementering |
|---|---|
| Thumbnail-fallback | Manuelt uploadet billede → auto-screenshot via thum.io → favicon (onerror-kæde i frontend) |
| Klik-tæller | Fire-and-forget POST action=link_klik ved hvert klik på et link |
| Sortering | Manuel / mest populære / nyeste / alfabetisk – valgt via sort-parameter |
| Link-validering | Sekventielle HTTP HEAD-requests server-side (cURL, 5s timeout pr. link) |
| CSV-import | Ren client-side parsing/validering i links-admin.html (selvskrevet CSV-parser, ingen bibliotek) – dublet-tjek mod eksisterende links, preview før commit, sekventielle kald til det eksisterende POST action=link-endpoint. Ingen nye API-endpoints eller databasetabeller |
| Adgang | requireTraenerKunIkkeAssistent() på alle skrive-endpoints – assistent har bevidst kun læseadgang til link-biblioteket, i modsætning til resten af coach-værktøjerne |
| Område | Implementering |
|---|---|
| Kodeord | bcrypt-hashing i PHP (password_hash() / password_verify()) |
| SQL Injection | PDO prepared statements i alle database-queries |
| XSS | Alle brugerinput escaped med htmlspecialchars() og JS esc() |
| Auth-guard | Alle sider validerer JWT lokalt + backend validerer på hvert API-kald |
| Rolle-check | Admin-endpoints kræver rolle = 'admin' i JWT-payload |
| CORS | Begrænset til teamapp.dk-domænet |
Designmanual
TeamApp følger et dark-first designprincip med et markant accent-orange der skaber energi og sportsfølelse. Interfacet er funktionelt frem for dekorativt – data er i centrum.
Kerneprincipper: Klarhed · Hastighed · Fokus · Sportsenergisk
Kilde til sandhed: alle farver og fonte er samlet i design.css (roden). Siderne bruger var(--token) frem for hardcodede værdier. Mørkt er standard (:root); lyst aktiveres via klassen .light på <html> og huskes i localStorage['kn_theme']. Fuld reference: docs/design-system.md.
Bløde flader (badges, hover, alerts): --accent-soft, --green-dim, --red-soft. Domæne-tokens (kampnoter/dashboard): --taktik, --spiller, --timeout m.fl. — aliaser oven på grundfarverne.
Farverne herunder læses live fra design.css via CSS-variablerne — ændres et token dér, opdateres denne side automatisk.
| Font | Rolle | Vægte | Eksempel |
|---|---|---|---|
| Outfit | Overskrifter, logoer, tal | 400–800 | TeamApp |
| Space Grotesk | Brødtekst, navigation, labels | 400–700 | Coaching platform |
| DM Mono | Kode, tal, tekniske data | 400, 500 | api.php · JWT |
| Størrelse | Brug |
|---|---|
| 26–36px · Outfit 800 | Sideoverskrifter og store tal (stat-num) |
| 18–20px · Outfit 700 | Kortoverskrifter og modaltitler |
| 15–16px · Space Grotesk 600–700 | Primær tekst, kortnavne |
| 13px · Space Grotesk 400–500 | Brødtekst, tabelindhold |
| 10–11px · Space Grotesk 600 | Labels, badges, uppercase metadata |
| 11–12px · DM Mono | Tekniske værdier, diskforbrug, datoer |
Knapper
Badges og tags
Alerts
| Element | Specifikation |
|---|---|
| Sidebar bredde | 260px fast (alle moduler) |
| Main padding | 36px 32px (desktop) · 20px 16px (mobil <700px) |
| Kortradius | 14–16px (cards) · 10px (knapper/inputs) · 20px (modals) |
| Kortpadding | 18–28px afhængig af kontekst |
| Gitter | CSS Grid med auto-fill og minmax() |
| Responsiv breakpoint | 700px – sidebar skjules, layout skifter til single-column |
| Transitions | background/border/color: .2s ease · transform: .15s |
| Baggrundsgradient | Subtil radial gradient øverst og nederst – accent og blue toner |
Ikonerne er linje-baserede SVG'er tegnet på et 24×24-grid med ensartet streg. De arver farve fra teksten (stroke: currentColor) og skalerer frit. De defineres som <symbol>-sprites og bruges via <use href="#icon-…">; stregattributterne sættes af container-klassen (fx .nav-icon i design.css), ikke på selve symbolet.
| Egenskab | Værdi |
|---|---|
| Grid | 24 × 24 |
| Stregtykkelse | 1.8 |
| Linecap / linejoin | round |
| Farve | currentColor – arver fra tekst/kontekst |
| Fyld | ingen (fill: none) |
| Brug | <svg><use href="#icon-navn"></svg> |
Admin-modulets ikonsæt (eksempel på husstilen)
homelogoutusertheme-suntheme-moonoverblikbrugeredatabaseflytskematestprojektvejledningtekniskdesignclaudearkitekturmodulerroentgenIkonerne defineres i dag pr. side som inline-sprites (ca. 122 distinkte på tværs af appen; genbrugte ikoner deler bevidst identisk path-data for pixel-perfekt konsistens). En genereret reference med style-spec ligger under docs/icon-sets/. En samlet, central ikon-fil er et muligt næste skridt.
Claude-værktøjer
Projektet har en .claude/-mappe, der udvider Claude Code (og Cowork) med projekt-specifikke værktøjer til udvikling af TeamApp. Der er tre slags — de bruges på hver sin måde:
| Type | Hvad det er | Hvordan det startes |
|---|---|---|
| Skill | Viden / fremgangsmåde Claude trækker ind | Automatisk, når opgaven matcher |
| Subagent | En separat Claude, der løser en delopgave | Automatisk eller ved at nævne navnet |
| Kommando | Genvej til en arbejdsgang | Du skriver /navn |
En skill er en mappe med en SKILL.md, der giver Claude specialiseret viden eller en arbejdsgang. Claude læser den automatisk ind, når din besked matcher skillens triggere — du aktiverer den ikke selv.
Sådan bruger du dem: beskriv bare opgaven. Fx udløser "fejlsøg et PHP-endpoint" web-udvikler, og "prioritér backloggen" udløser projektleder.
En subagent er en selvstændig Claude, der kører en afgrænset opgave i sit eget vindue og kun sender resultatet tilbage. Det sparer kontekst og giver den en snæver rolle. Projektets agenter ligger i .claude/agents/:
| Agent | Formål |
|---|---|
frontend-review | Gennemgår og optimerer frontend-design på en side |
backend-review | Reviewer api.php / admin2.php — sikkerhed først |
pwa-deploy | Tjekker service worker, manifest, cache og deploy |
web-tester | Statisk sundhedstjek (brudte links, syntaks, PWA) |
e2e-tester | Skriver og vedligeholder tværgående testcases på tværs af moduler (docs/testcases.md) |
ide-generator | Brainstormer nye features + håndboldindhold |
design-system | Vedligeholder det fælles designsystem (tokens) |
docs-sync | Synkroniserer dokumentationen i admin.html/CLAUDE.md med koden |
Sådan bruger du dem: beskriv opgaven ("reviewer kampnoter.html"), eller nævn agenten direkte ("brug web-tester på hele repoet"). Vil du kun have forslag, så sig "foreslå kun, lav ikke ændringer".
En slash-kommando er en genvej, du selv starter ved at skrive /navn. Den kører en forudskrevet arbejdsgang — ofte ved at kalde en eller flere agenter. De ligger i .claude/commands/:
| Kommando | Gør |
|---|---|
/pre-deploy | Fuldt review af ændringer + GO/NO-GO før deploy |
/test | Teknisk sundhedstjek af repoet (kalder web-tester) |
/design | Vedligehold designsystemet (audit / migrér en side til tokens) |
/ny-side | Stil en ny rod-HTML-side op efter projektets mønster |
/ny-pwa | Stil en ny undermappe-PWA op (manifest, sw, ikoner, design.css) |
/docs-sync | Sammenlign og synkroniser dokumentationen med koden (kalder docs-sync) |
Sådan bruger du dem: skriv kommandoen, evt. med et argument — fx /test kampnoter.html eller /ny-side statistik.html. Uden argument kører de deres standard.
.claude/agents/ | Subagenter (én .md pr. agent) |
.claude/commands/ | Slash-kommandoer |
.claude/skills/ | Projekt-skills (SKILL.md) |
Sådan hænger det sammen: en skill er passiv viden, en subagent er en aktiv proces (kan bruge en skill undervejs), og en kommando er knappen du selv trykker på for at sætte det i gang. Alle tre er værktøjer til at udvikle TeamApp — ikke funktioner i selve appen for trænere og spillere.
Projektoverblik
En samling statiske HTML-sider (vanilla JS, ingen build-step) med én fælles PHP-backend mod MySQL. Flere sider er installerbare PWA'er.
Dokumentation
Kampnoter — Brugervejledning v3
Kampnoter — Teknisk spec v3
TeamApp Designmanual
docs/design-system.md
docs/linkbibliotek-spec.md
Infrastruktur
GitHub Actions → FTP deploy
.htaccess (Apache/UnoEuro)
MySQL 8.0 · UnoEuro hosting
JWT (HS256) auth
design.css designsystem
Claude skills · 11
Arkitektur
Sådan hænger TeamApp sammen — fra bruger til database. Statiske sider taler med én PHP-backend, beskyttet af JWT, og deployes via FTP. Diagrammet følger appens tema.
Ingen staging — main er produktion. config.local.php ligger kun på serveren og overskrives ikke ved deploy. HTML serveres med no-cache, så nye versioner hentes straks.
Moduloversigt
TeamApp består af 14 HTML-moduler der tilsammen dækker hele løsningen – fra spillerens mobil-app til administratorens systempanel. Alle moduler deler samme design-system og API-backend.
| Fra modul | → Til modul | Datatype |
|---|---|---|
| spiller-admin.html | spiller.html | Åbninger, kampanalyser og udviklingsopslag deles med spillerne |
| tegning.html | dashboard.html / spiller-admin.html | Tegninger gemmes og vedhæftes åbninger |
| traening.html | dashboard.html | Træningssessioner ses i coaching-overblikket |
| admin.html | Alle moduler | Brugere og hold administreres centralt – påvirker adgang overalt |
| login.html | dashboard.html / spiller.html | JWT-token bruges på tværs af alle moduler til auth |
| Modul | API | PWA | Canvas | Tema |
|---|---|---|---|---|
| admin.html | admin2.php | — | — | Mørkt + Lyst |
| dashboard.html | api.php | — | ✓ | Mørkt + Lyst |
| spiller-admin.html | api.php | — | — | Mørkt |
| spiller.html | api.php | ✓ | — | Mørkt + Lyst |
| tegning.html | api.php | — | — | Mørkt |
| traening.html | api.php | — | — | Mørkt + Lyst |
| kampnoter.html | api.php | — | — | Mørkt + Lyst |
| oevelsesark.html | api.php | — | — | Mørkt + Lyst |
| modstandere.html | api.php | — | — | Mørkt + Lyst |
| styrke-skade.html | api.php | — | — | Mørkt + Lyst |
| links.html | api.php | ✓ (manifest-links.json) | — | Mørkt + Lyst |
| links-admin.html | api.php | — | — | Mørkt + Lyst |
| test.html | admin2.php + api.php | — | — | Mørkt |
| login.html | api.php (login) | — | — | Mørkt |