All checks were successful
Build, test and publish / verify (push) Successful in 1m40s
226 lines
8.9 KiB
Markdown
226 lines
8.9 KiB
Markdown
# agiledancers
|
|
|
|
To map dance groups to performance days. The backend runs on Quarkus with Java 25.
|
|
|
|
Requires JDK 25 and Maven 3.9.0 or newer. Set `JAVA_HOME` to your JDK 25 installation.
|
|
|
|
Build and run all tests (including `*Sit` tests) from the repository root:
|
|
|
|
```sh
|
|
mvn clean verify
|
|
```
|
|
|
|
Start development mode with live reload from the repository root:
|
|
|
|
```sh
|
|
mvn -pl agiledancers-be quarkus:dev
|
|
```
|
|
|
|
Run the packaged application after building:
|
|
|
|
```sh
|
|
java -jar agiledancers-be/target/quarkus-app/quarkus-run.jar
|
|
```
|
|
|
|
Build and run a Docker container from the repository root (only Docker is required):
|
|
|
|
```sh
|
|
docker build -t agiledancers .
|
|
docker run --rm --name agiledancers -p 8080:8080 agiledancers
|
|
```
|
|
|
|
The Docker build compiles the application and runs the tests in a Maven build stage,
|
|
then copies the Quarkus application into a Java 25 runtime image running as a non-root user.
|
|
|
|
Check readiness at <http://localhost:8080/q/health/ready> or overall health at
|
|
<http://localhost:8080/q/health>. For example:
|
|
|
|
```sh
|
|
curl --fail http://localhost:8080/q/health/ready
|
|
```
|
|
|
|
Quarkus configuration can be overridden with environment variables, for example
|
|
`docker run --rm -e QUARKUS_HTTP_PORT=9090 -p 9090:9090 agiledancers`.
|
|
|
|
The REST API uses shared in-memory storage; data is lost when the process stops.
|
|
|
|
Architecture checks run with the normal test suite, or separately with:
|
|
|
|
```sh
|
|
mvn -pl agiledancers-be -Dtest=ArchitectureTest test
|
|
```
|
|
|
|
`ArchitectureTest` guards the following packages below `nl.agilecc.agiledancers`:
|
|
|
|
| Package | Responsibility | Allowed dependencies within the application |
|
|
| --- | --- | --- |
|
|
| `model` | Domain entities and specifications | Model |
|
|
| `service` | Application use cases and future ports | Model, repositories |
|
|
| `repository` | Current in-memory persistence | Model |
|
|
| `rest` | Future REST services | Services, model |
|
|
| `solver` | Future OR-Tools calculations | Services (ports), model |
|
|
|
|
REST and solver packages are optional until implemented. OR-Tools dependencies
|
|
are allowed only in `solver`; JAX-RS and RESTEasy dependencies only in `rest`.
|
|
The model may depend only on itself, Java and Lombok. Package cycles and
|
|
production classes outside these packages fail the architecture tests.
|
|
|
|
API models live in `rest.apimodel`, each in its own Java file as a public top-level
|
|
class or record. Their names end in `Request`, `Response`, `View`, `Dto` or `DTO`.
|
|
Architecture tests enforce this naming and location convention and require all
|
|
records in the REST layer to reside in `rest.apimodel`.
|
|
|
|
The current services instantiate concrete repositories, so this is not yet strict
|
|
Onion architecture. That requires repository interfaces in the core and injected
|
|
implementations in an outer adapter. For future calculations, define a port in
|
|
`service.port` using domain types and implement it in `solver`; services must not
|
|
depend on solver implementations or expose OR-Tools types.
|
|
|
|
|
|
## School management REST API
|
|
|
|
All endpoints consume and produce JSON. Resources are scoped to their dance school.
|
|
A dancer can belong to multiple dance groups within the same school. Memberships
|
|
are managed separately from group details and survive updates to dancers and groups.
|
|
|
|
| Resource collection | Item URL |
|
|
| --- | --- |
|
|
| `/api/dance-schools` | `/api/dance-schools/{schoolId}` |
|
|
| `/api/dance-schools/{schoolId}/dancers` | `.../dancers/{dancerId}` |
|
|
| `/api/dance-schools/{schoolId}/dance-groups` | `.../dance-groups/{groupId}` |
|
|
| `/api/dance-schools/{schoolId}/shows` | `.../shows/{showId}` |
|
|
|
|
Each collection supports `GET` (list) and `POST` (create). Each item supports `GET`,
|
|
`PUT` (replace editable details), and `DELETE`. Creation returns `201` with a
|
|
`Location` header; updates return `200`; deletion returns `204`. Invalid input
|
|
returns `400`, and missing resources or resources belonging to another school
|
|
return `404`. Client-supplied IDs are not used.
|
|
|
|
Request bodies (dates use ISO `yyyy-MM-dd`):
|
|
|
|
```json
|
|
{"name": "24 Dance Studio"}
|
|
```
|
|
|
|
```json
|
|
{"name": "Sam", "birthDate": "2010-05-12"}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"category": "Teens",
|
|
"type": "REGULAR",
|
|
"startAge": 12,
|
|
"endAge": 18,
|
|
"styles": ["HIPHOP", "JAZZ"]
|
|
}
|
|
```
|
|
|
|
```json
|
|
{"name": "Annual show", "date": "2027-06-12"}
|
|
```
|
|
|
|
Names and categories must be nonblank. Birth dates cannot be in the future.
|
|
Both ages must be nonnegative and `startAge <= endAge`; `styles` is required
|
|
and may be empty. Group types are `SHOW_CASE`, `PRE_EDUCATION`, `SELECTION`,
|
|
`REGULAR`, `PRE_SCHOOLER`. Styles are `HIPHOP`, `JAZZ`, `MODERN`, `STREETDANCE`,
|
|
`CLASSIC`, `BREAKDANCE`.
|
|
|
|
School responses include `dancerIds`, `danceGroupIds`, and `showIds`; group
|
|
responses include `dancerIds`. To add or remove a dancer's group membership:
|
|
|
|
```sh
|
|
curl -X PUT http://localhost:8080/api/dance-schools/0/dance-groups/0/dancers/0
|
|
curl -X DELETE http://localhost:8080/api/dance-schools/0/dance-groups/0/dancers/0
|
|
```
|
|
|
|
Both operations return `204` and are idempotent for existing groups and dancers.
|
|
Deleting a dancer removes all their memberships; deleting a group retains the
|
|
dancers; deleting a school also deletes its dancers, groups and shows.
|
|
|
|
Shows have a name, a date and three automatically created day parts: `MORNING`,
|
|
`AFTERNOON`, `EVENING`. Each day part has an empty `danceGroupIds` list; assigning
|
|
groups is not exposed yet. Multiple shows per year are allowed.
|
|
|
|
Run the HTTP integration tests with:
|
|
|
|
```sh
|
|
mvn -pl agiledancers-be -Dtest=SchoolManagementResourceTest test
|
|
```
|
|
|
|
|
|
## Angular frontend
|
|
|
|
The Angular 22 frontend is in [`agiledancers-fe`](agiledancers-fe/README.md),
|
|
next to `agiledancers-be`. It provides Dutch-language screens to manage schools,
|
|
dancers, groups, memberships and shows through the REST API.
|
|
|
|
Use Node.js 22.22.3+ (22.x), 24.15.0+ (24.x), or 26+.
|
|
Start the backend as described above, then run in a second terminal:
|
|
|
|
```sh
|
|
cd agiledancers-fe
|
|
npm ci
|
|
npm start
|
|
```
|
|
|
|
Open <http://localhost:4200>. The development proxy forwards API requests to the
|
|
backend on port 8080. Frontend builds and tests run independently of Maven:
|
|
`npm run build` and `npm test`. See the frontend README for browser tests and
|
|
production hosting requirements.
|
|
|
|
## Frontend lint and formatting
|
|
|
|
Run these commands from `agiledancers-fe/`:
|
|
|
|
```sh
|
|
npm run lint
|
|
npm run lint:fix
|
|
```
|
|
|
|
`lint` checks maintained application code, inline and external Angular templates,
|
|
unit tests, Playwright tests and JavaScript/TypeScript configuration. It uses the
|
|
recommended JavaScript, Angular and type-aware TypeScript rules. It changes no
|
|
files; both errors and warnings cause failure. Dependencies, generated output
|
|
and `package-lock.json` are excluded. `lint:fix` applies ESLint's available fixes;
|
|
review the diff and resolve any remaining findings manually. Prettier retains
|
|
responsibility for formatting with the existing configuration.
|
|
|
|
Every branch pipeline runs `npm run lint` immediately after frontend `npm ci`,
|
|
before frontend tests/builds and container E2E. Failure prevents image publication;
|
|
findings are in the job log and retained `ci/artifacts/verify.log`. CI only checks
|
|
and never fixes or stages source files.
|
|
|
|
Local `npm ci` automatically installs Husky at the repository root. Its commit
|
|
hook runs **Prettier only**, through lint-staged with backup, rollback and hiding
|
|
of unstaged changes in partially staged files enabled. It formats applicable
|
|
staged frontend TypeScript, JavaScript, HTML, CSS and JSON files, then stages the
|
|
formatting. Unrelated unstaged edits and files remain outside the commit. A
|
|
formatter error or a conflict restoring unstaged edits aborts the commit and
|
|
restores the original staged and unstaged state. Generated files are excluded;
|
|
commits without applicable frontend changes skip these checks.
|
|
|
|
The complete Prettier-plus-ESLint hook exceeds the agreed three-second budget
|
|
when all maintained files are staged. The selected Prettier-only hook meets the
|
|
budget for single-file, mixed and all-file commits. ESLint is therefore run
|
|
explicitly during development and always by CI. See [S2 validation](docs/s2-validation.md)
|
|
for the measured environment, timings and preservation checks.
|
|
|
|
Hook installation is skipped when `CI` is set (including Docker builds) or
|
|
`HUSKY=0`. Use `HUSKY=0 npm ci` to skip local installation, `HUSKY=0 git commit`
|
|
to skip one hook execution, or `git config --local core.hooksPath /dev/null` to
|
|
disable hooks for this clone. A subsequent normal `npm ci` enables them again.
|
|
|
|
VS Code recommends the ESLint extension in both root and frontend workspaces.
|
|
With it installed, findings appear in the editor and Problems panel; the root
|
|
workspace selects `agiledancers-fe/` as ESLint's working directory. No automatic
|
|
fixing or formatting on save is required. `npm run lint` uses the same rules as CI.
|
|
|
|
## Gitea CI
|
|
|
|
Every branch push builds and tests both applications and their Docker images.
|
|
Only successful `main` runs publish images to the Synology registry. See
|
|
[the CI management guide](docs/gitea-ci.md) for runner setup, registry secrets,
|
|
image names, diagnostics and recovery, and [validation evidence](docs/s4-validation.md)
|
|
for the current operational status.
|