diff --git a/README.md b/README.md index b384e83..c9b00dd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,82 @@ Repository for team IT2810-H26-T29 in IT2810-H26. +We are building a web application that helps gymnastics coaches plan their gymnasts' routines. It contains a searchable catalog of all elements and vaults in the FIG Women's Artistic Gymnastics Code of Points 2025–2028. Coaches can put together routines for their gymnasts and see the D-value (difficulty value) of each routine. + +## Status + +The first delivery is a specification. There is no working application yet. + +The code in `src/` is the Vite starter project with one example test. The tooling is set up: TypeScript, ESLint, Prettier and Vitest. + +## What to review + +| Document | Describes | +| ---------------------------------------- | ---------------------------------------------------------------------------------------- | +| [docs/UI_PLANS.md](docs/UI_PLANS.md) | The user groups, user stories and pages of the application | +| [docs/DATA_MODEL.md](docs/DATA_MODEL.md) | The entities, how they relate, the constraints and the reasoning behind the main choices | +| [docs/examples/](docs/examples/) | Invented example data that shows how each entity in the data model is structured | +| [docs/AI_USAGE.md](docs/AI_USAGE.md) | How AI was used in the project | + +## The dataset + +The catalog data comes from the FIG Women's Artistic Gymnastics Code of Points 2025–2028, which is published as a PDF. We will extract the apparatus, element groups, elements and vaults from the PDF with a script, and load them into the database with a seed script. Neither script is written yet. + +The data is used for educational purposes. All rights to the Code of Points belong to FIG (Fédération Internationale de Gymnastique). + +## Planned functionality + +For everyone, without logging in: + +- Search, filter and sort all elements and vaults +- See the details of one element or vault: code, value, description, image and variants +- Put together a routine in the calculator and see its D-value + +For coaches, who log in with Google: + +- Create gymnast profiles +- Build and save routines for each gymnast, with several routines per apparatus +- Keep a list of the elements each gymnast can do or is practicing + +The D-value of a routine is calculated from its elements and is not stored. Composition requirements and connection values are not included in this version. + +## Technology + +In the repository now: + +- React, TypeScript and Vite for the frontend +- ESLint and Prettier for linting and formatting +- Vitest for testing + +Planned: + +- A GraphQL backend in Node and TypeScript +- A database installed directly on the VM. + +## Getting started + +> **Not relevant yet.** The first delivery is a specification, so you do not need to run anything to review it. These commands only start the starter project. + +You need Node 24 (see `.nvmrc`) and pnpm. If you have npm but not pnpm, install it with `npm install -g pnpm`. + +```bash +nvm use +pnpm install +pnpm dev +``` + +`pnpm dev` starts the starter project at http://localhost:5173. + +Other commands: + +| Command | What it does | +| -------------- | ----------------------------------------------- | +| `pnpm build` | Type-checks and builds the project into `dist/` | +| `pnpm preview` | Serves the built project locally | +| `pnpm lint` | Runs ESLint | +| `pnpm format` | Formats all files with Prettier | +| `pnpm test` | Runs the tests with Vitest | + ## Working in this repository `main` is protected — you cannot push to it directly. Work on a branch and diff --git a/docs/AI_USAGE.md b/docs/AI_USAGE.md index 7078729..9541e73 100644 --- a/docs/AI_USAGE.md +++ b/docs/AI_USAGE.md @@ -6,3 +6,39 @@ - **What Claude did:** Wrote the Mermaid code for the ER diagram and drafted the descriptions, based on our conversation. - **Review:** The team reviewed the result and edited it. + +## Example data (`docs/examples/`) + +- **Tool:** Claude Code +- **What the team did:** Wrote the task description: which files to create, + what each should contain, and that the data must follow the constraints in + the data model. +- **What Claude did:** Generated all the data in the JSON files and wrote the + README. The elements, vaults, descriptions, names, coach, gymnasts and + routines are invented by Claude. The apparatus and element group names were + written by Claude from its knowledge of the Code of Points, not copied from + the document. Claude also checked with a script that all referenced ids + exist and that the data follows the constraints. +- **Prompt:** + + ```text + Add example JSON files in docs/examples/ that show how the data in docs/DATA_MODEL.md is + structured. They are documentation only, and the catalog entries are invented. + + Files (JSON arrays): + - apparatus.json and elementGroups.json: all 4 apparatus and all 22 groups, with real names + from the Code of Points table of contents. + - elements.json: 2–3 per UB, BB and FX. At least one named element and one element with + two variants. + - vaults.json: two vaults from different groups. + - variantGroups.json: one group for the element with variants. + - coaches.json, gymnasts.json, routines.json: one coach, two gymnasts, and routines that include + two routines on the same apparatus and one vault routine. + + Invented entries must look plausible: codes and values follow the Code of Points pattern + ("3.304" = group 3, C, 0.3), but don't copy real descriptions. + + Check that all referenced ids exist and that the data follows the constraints in DATA_MODEL.md. + Add a short README in docs/examples/ saying the data is invented, and link to the folder from + DATA_MODEL.md. + ``` diff --git a/docs/DATA_MODEL.md b/docs/DATA_MODEL.md index 9a5e0c6..252cb66 100644 --- a/docs/DATA_MODEL.md +++ b/docs/DATA_MODEL.md @@ -4,6 +4,8 @@ This document describes the data model for the Code of Points catalog: what each The catalog data (apparatus, element groups, elements, vaults and variant groups) is extracted from the FIG Women's Artistic Gymnastics Code of Points 2025–2028 and is read-only in the app. The user data (coaches, gymnasts and routines) is created by users through the website. +Example data that shows how each entity is structured is in [examples/](examples/). The entries are invented and are for documentation only. + ## Diagram ```mermaid diff --git a/docs/examples/README.md b/docs/examples/README.md new file mode 100644 index 0000000..048725f --- /dev/null +++ b/docs/examples/README.md @@ -0,0 +1,20 @@ +# Example data + +These JSON files show how the data described in [DATA_MODEL.md](../DATA_MODEL.md) is structured. They are documentation only and are not used by the app. + +**The data is invented.** The apparatus and element group names are taken from the table of contents of the FIG Women's Artistic Gymnastics Code of Points 2025–2028. Everything else is made up: the elements, vaults, descriptions, names, coach and gymnasts. The codes and values follow the pattern of the Code of Points (`3.304` is an element in group 3 with value 0.3), but they do not match real elements. The image files named in the data do not exist. + +**The data is generated by AI.** All the JSON files were generated by Claude Code from a task description written by the team. See [AI_USAGE.md](../AI_USAGE.md). + +The ids of coaches, gymnasts and routines (`coach-1`, `gymnast-1`, `routine-1`) are placeholders for the internal ids the database will generate. + +| File | Entity | Contents | +| -------------------- | ------------ | --------------------------------------------------------------------- | +| `apparatus.json` | Apparatus | All 4 apparatus | +| `elementGroups.json` | ElementGroup | All 22 element groups | +| `elements.json` | Element | 9 elements on uneven bars, beam and floor, including two variants | +| `vaults.json` | Vault | 2 vaults from different groups | +| `variantGroups.json` | VariantGroup | 1 variant group, linking the two variants of `UB-1.101` | +| `coaches.json` | Coach | 1 coach | +| `gymnasts.json` | Gymnast | 2 gymnasts with their lists of elements | +| `routines.json` | Routine | 5 routines, including two on the same apparatus and one vault routine | diff --git a/docs/examples/apparatus.json b/docs/examples/apparatus.json new file mode 100644 index 0000000..391287d --- /dev/null +++ b/docs/examples/apparatus.json @@ -0,0 +1,6 @@ +[ + { "id": "VT", "name": "Vault" }, + { "id": "UB", "name": "Uneven bars" }, + { "id": "BB", "name": "Balance beam" }, + { "id": "FX", "name": "Floor exercise" } +] diff --git a/docs/examples/coaches.json b/docs/examples/coaches.json new file mode 100644 index 0000000..bbddaac --- /dev/null +++ b/docs/examples/coaches.json @@ -0,0 +1,9 @@ +[ + { + "id": "coach-1", + "googleId": "109876543210987654321", + "email": "kari.nilsen@example.com", + "name": "Kari Nilsen", + "createdAt": "2026-10-01T12:00:00Z" + } +] diff --git a/docs/examples/elementGroups.json b/docs/examples/elementGroups.json new file mode 100644 index 0000000..be0d045 --- /dev/null +++ b/docs/examples/elementGroups.json @@ -0,0 +1,84 @@ +[ + { + "id": "VT-1", + "apparatusId": "VT", + "number": 1, + "name": "Vaults without salto (handspring, Yamashita, round-off) with or without LA turn in 1st and/or 2nd flight phase" + }, + { + "id": "VT-2", + "apparatusId": "VT", + "number": 2, + "name": "Handspring fwd with or without 1/1 turn (360°) in 1st flight phase – salto fwd or bwd with or without LA turn in 2nd flight phase" + }, + { + "id": "VT-3", + "apparatusId": "VT", + "number": 3, + "name": "Handspring with ¼–½ turn (90°–180°) in 1st flight phase (Tsukahara) – salto bwd with or without LA turn in 2nd flight phase" + }, + { + "id": "VT-4", + "apparatusId": "VT", + "number": 4, + "name": "Round-off (Yurchenko) with or without ¾ turn (270°) in 1st flight phase – salto bwd with or without LA turn in 2nd flight phase" + }, + { + "id": "VT-5", + "apparatusId": "VT", + "number": 5, + "name": "Round-off with ½ turn (180°) in 1st flight phase – salto fwd or bwd with or without LA turn in 2nd flight phase" + }, + { "id": "UB-1", "apparatusId": "UB", "number": 1, "name": "Mounts" }, + { + "id": "UB-2", + "apparatusId": "UB", + "number": 2, + "name": "Casts and clear hip circles" + }, + { "id": "UB-3", "apparatusId": "UB", "number": 3, "name": "Giant circles" }, + { "id": "UB-4", "apparatusId": "UB", "number": 4, "name": "Stalder circles" }, + { "id": "UB-5", "apparatusId": "UB", "number": 5, "name": "Pike circles" }, + { "id": "UB-6", "apparatusId": "UB", "number": 6, "name": "Dismounts" }, + { "id": "BB-1", "apparatusId": "BB", "number": 1, "name": "Mounts" }, + { + "id": "BB-2", + "apparatusId": "BB", + "number": 2, + "name": "Gymnastic leaps, jumps and hops" + }, + { "id": "BB-3", "apparatusId": "BB", "number": 3, "name": "Gymnastic turns" }, + { + "id": "BB-4", + "apparatusId": "BB", + "number": 4, + "name": "Holds and acrobatic non-flight" + }, + { + "id": "BB-5", + "apparatusId": "BB", + "number": 5, + "name": "Acrobatic flight" + }, + { "id": "BB-6", "apparatusId": "BB", "number": 6, "name": "Dismounts" }, + { + "id": "FX-1", + "apparatusId": "FX", + "number": 1, + "name": "Gymnastic leaps, jumps and hops" + }, + { "id": "FX-2", "apparatusId": "FX", "number": 2, "name": "Gymnastic turns" }, + { + "id": "FX-3", + "apparatusId": "FX", + "number": 3, + "name": "Hand support elements" + }, + { + "id": "FX-4", + "apparatusId": "FX", + "number": 4, + "name": "Saltos forward and sideward" + }, + { "id": "FX-5", "apparatusId": "FX", "number": 5, "name": "Saltos backward" } +] diff --git a/docs/examples/elements.json b/docs/examples/elements.json new file mode 100644 index 0000000..71a36c9 --- /dev/null +++ b/docs/examples/elements.json @@ -0,0 +1,83 @@ +[ + { + "id": "UB-1.101-a", + "elementGroupId": "UB-1", + "code": "1.101", + "value": 0.1, + "description": "Jump with straight body to hang on HB – swing fwd with ½ turn (180°)", + "name": null, + "image": "UB-1.101-a.webp" + }, + { + "id": "UB-1.101-b", + "elementGroupId": "UB-1", + "code": "1.101", + "value": 0.1, + "description": "Jump with legs straddled to hang on HB – swing fwd with ½ turn (180°)", + "name": null, + "image": "UB-1.101-b.webp" + }, + { + "id": "UB-3.304-a", + "elementGroupId": "UB-3", + "code": "3.304", + "value": 0.3, + "description": "Giant circle bwd in mixed grip with ½ turn (180°) through handstand", + "name": null, + "image": "UB-3.304-a.webp" + }, + { + "id": "BB-2.201-a", + "elementGroupId": "BB-2", + "code": "2.201", + "value": 0.2, + "description": "Leap fwd with ½ turn (180°), landing on one leg in cross position", + "name": null, + "image": "BB-2.201-a.webp" + }, + { + "id": "BB-5.403-a", + "elementGroupId": "BB-5", + "code": "5.403", + "value": 0.4, + "description": "Salto swd tucked from a two-step approach, landing in side position", + "name": "Lindqvist", + "image": "BB-5.403-a.webp" + }, + { + "id": "BB-6.305-a", + "elementGroupId": "BB-6", + "code": "6.305", + "value": 0.3, + "description": "Round-off at end of beam – salto bwd piked with ½ turn (180°)", + "name": null, + "image": "BB-6.305-a.webp" + }, + { + "id": "FX-1.203-a", + "elementGroupId": "FX-1", + "code": "1.203", + "value": 0.2, + "description": "Hop with free leg at horizontal and 1/1 turn (360°)", + "name": null, + "image": "FX-1.203-a.webp" + }, + { + "id": "FX-2.302-a", + "elementGroupId": "FX-2", + "code": "2.302", + "value": 0.3, + "description": "2/1 turn (720°) on one leg with free leg held bent in front", + "name": null, + "image": "FX-2.302-a.webp" + }, + { + "id": "FX-5.506-a", + "elementGroupId": "FX-5", + "code": "5.506", + "value": 0.5, + "description": "Double salto bwd with first salto tucked and second salto piked, with 1/1 turn (360°)", + "name": "Aasen", + "image": "FX-5.506-a.webp" + } +] diff --git a/docs/examples/gymnasts.json b/docs/examples/gymnasts.json new file mode 100644 index 0000000..81c2cd4 --- /dev/null +++ b/docs/examples/gymnasts.json @@ -0,0 +1,21 @@ +[ + { + "id": "gymnast-1", + "coachId": "coach-1", + "name": "Ingrid Haugen", + "elementIds": [ + "UB-1.101-a", + "UB-1.101-b", + "UB-3.304-a", + "BB-2.201-a", + "VT-1.12-a", + "VT-4.23-a" + ] + }, + { + "id": "gymnast-2", + "coachId": "coach-1", + "name": "Emma Berg", + "elementIds": ["BB-2.201-a", "BB-5.403-a", "FX-1.203-a", "FX-2.302-a"] + } +] diff --git a/docs/examples/routines.json b/docs/examples/routines.json new file mode 100644 index 0000000..4531d46 --- /dev/null +++ b/docs/examples/routines.json @@ -0,0 +1,37 @@ +[ + { + "id": "routine-1", + "gymnastId": "gymnast-1", + "name": "Competition routine", + "apparatusId": "UB", + "elementIds": ["UB-1.101-a", "UB-3.304-a"] + }, + { + "id": "routine-2", + "gymnastId": "gymnast-1", + "name": "With straddled mount", + "apparatusId": "UB", + "elementIds": ["UB-1.101-b", "UB-3.304-a"] + }, + { + "id": "routine-3", + "gymnastId": "gymnast-1", + "name": "Competition vault", + "apparatusId": "VT", + "elementIds": ["VT-1.12-a"] + }, + { + "id": "routine-4", + "gymnastId": "gymnast-2", + "name": "Competition routine", + "apparatusId": "BB", + "elementIds": ["BB-2.201-a", "BB-5.403-a", "BB-6.305-a"] + }, + { + "id": "routine-5", + "gymnastId": "gymnast-2", + "name": "Competition routine", + "apparatusId": "FX", + "elementIds": ["FX-1.203-a", "FX-2.302-a", "FX-5.506-a"] + } +] diff --git a/docs/examples/variantGroups.json b/docs/examples/variantGroups.json new file mode 100644 index 0000000..1f5e194 --- /dev/null +++ b/docs/examples/variantGroups.json @@ -0,0 +1,6 @@ +[ + { + "id": "UB-1.101", + "variantIds": ["UB-1.101-a", "UB-1.101-b"] + } +] diff --git a/docs/examples/vaults.json b/docs/examples/vaults.json new file mode 100644 index 0000000..65108de --- /dev/null +++ b/docs/examples/vaults.json @@ -0,0 +1,20 @@ +[ + { + "id": "VT-1.12-a", + "elementGroupId": "VT-1", + "code": "1.12", + "dValue": 2.4, + "description": "Handspring fwd on – ¾ turn (270°) off", + "name": null, + "image": "VT-1.12-a.webp" + }, + { + "id": "VT-4.23-a", + "elementGroupId": "VT-4", + "code": "4.23", + "dValue": 4.4, + "description": "Round-off, flic-flac on – salto bwd piked with 1¼ turn (450°) off", + "name": "Dahl", + "image": "VT-4.23-a.webp" + } +]