specs
All checks were successful
Build, test and publish / verify (push) Successful in 1m21s

This commit is contained in:
2026-10-29 19:35:10 +01:00
parent aea792307c
commit b0c2f28e13
11 changed files with 839 additions and 51 deletions

View File

@@ -0,0 +1,160 @@
# S1 — School JSON import and export
Status: implemented
## User story
**As** a school maintainer,
**I want** to export and import my dance school as a JSON file,
**so that** I can store my school configuration locally while the application does
not offer persistent storage,
**and so that** I retain ownership of my data.
## Intent
Export downloads a complete snapshot of one dance school to a local JSON file.
Import restores that snapshot as a new school or replaces the corresponding
existing school after explicit confirmation.
## Scope
### In scope
- Exporting an existing school to a readable JSON file.
- Importing a school that does not exist or no longer exists.
- Replacing an existing school with the complete imported snapshot.
- Preserving all configured school data and relationships, including:
- School details and its persistent unique key.
- Dancers and their details.
- Dance groups, types, age ranges and styles.
- Dancer memberships, including dancers belonging to multiple groups.
- Shows, dates, day parts and any existing group assignments to day parts.
- Coaches and any existing links between coaches and groups.
- Full validation, an import preview, confirmation and clear error messages.
Preserving existing data does not add management screens for coaches or the
ability to assign groups to show day parts.
### Out of scope
- Merging an imported snapshot with an existing school.
- Persistent server-side storage.
The existing-school prompt includes a merge option, but selecting it only displays
that merging is not yet supported. It must not change any data. Implementing merge
behavior requires a separate specification.
## Identity and file format
- Every school has a persistent unique key that is included in exports and
preserved through imports and subsequent exports.
- Import identifies an existing school by that key, not by its name or a
runtime-generated numeric ID. The key remains meaningful after a server restart.
- A school with the same name but a different unique key is a separate school.
- A file contains one school and all data needed to restore it without accessing
another school or the original server state.
- The readable, documented JSON format includes a `formatVersion` field.
- Users may edit the JSON manually. Edited files undergo the same validation as
files produced by the application.
- Unknown fields and unsupported format versions are rejected explicitly; data
must not be silently ignored.
- Relationships in the file must be unambiguous and restored correctly. Internal
numeric IDs need not remain identical, provided school identity and all
relationships are preserved without collisions with other schools.
## Export flow
1. The maintainer opens an existing school's management screen.
2. The maintainer selects the JSON export option.
3. The application downloads a JSON file containing a consistent, complete
snapshot of that school.
4. Export does not change the school or any other application data.
## Import flow
1. The maintainer selects the JSON import option and chooses a local file.
2. The application validates the entire file before changing any stored data.
3. For a valid file, the application shows a preview containing the school name
and the numbers of dancers, dance groups and shows.
4. If the unique school key is unknown, the maintainer confirms adding the school
or cancels the import.
5. If the key already exists, the application identifies the school that would be
replaced and offers replace, merge or cancel:
- **Replace:** explicitly warn that the existing school is replaced completely.
After confirmation, replace all its configured data with the snapshot.
- **Merge:** show a message that this functionality is not yet supported and
leave all data unchanged.
- **Cancel:** leave all data unchanged.
6. A confirmed import is committed as one operation. The application must not
expose a partially imported or partially replaced school.
7. If validation or importing fails, show **"Import niet gelukt"** together with
the concrete cause. The user can correct the file and try again.
## Validation and failure behavior
- Validate JSON syntax, the supported file structure and format version, required
data, field values and all relationships before applying the import.
- Reject unknown fields and references to missing objects, including a group's
reference to a dancer absent from the snapshot.
- A failure must not create a partial school, partially replace an existing
school, or modify another school.
- A replacement must not remove the original school until the complete
replacement can succeed. If it fails, the original school remains intact.
- Error messages explain the cause specifically enough to correct the file.
For example: **"Import niet gelukt: groep Hiphop verwijst naar een onbekende
danser."**
## Acceptance criteria
### Export
1. Each existing school offers a JSON-file export that can be downloaded and
stored locally.
2. The export includes its persistent unique key, `formatVersion`, all configured
data listed in scope and all relationships between those objects.
3. Exporting leaves the application data unchanged.
4. A school with no dancers, groups or shows can be exported and imported.
### Adding a school
5. A valid file with an unknown school key shows the preview before any data is
added. Confirming creates the complete school; cancelling changes nothing.
6. An exported school can be restored after the original school is deleted or
the in-memory server state is lost.
7. An existing school with the same name but a different key is neither replaced
nor treated as the same school.
### Replacing a school
8. A valid file with an existing school key prompts the user to replace, merge or
cancel and clearly identifies the existing school.
9. Confirming replacement replaces the complete configuration. Objects and
relationships present only in the previous configuration are not retained as
part of the replaced school.
10. Other schools remain unchanged by replacement.
11. Selecting merge displays that merging is not yet supported and changes
nothing. Cancelling also changes nothing.
### Validation and errors
12. Malformed JSON, unsupported format versions, unknown fields, missing required
data, invalid field values and unresolved relationships cause the entire
import to fail.
13. Each failed import displays **"Import niet gelukt"** and a concrete cause.
14. A failed new-school import adds nothing. A failed replacement preserves the
entire existing school. Other schools are unaffected in either case.
15. After a failure, the user can select a corrected file and retry.
### Round-trip integrity
16. Exporting and importing a school preserves every configured field and
relationship, including a dancer's membership in multiple groups, shows and
their day parts, and any existing coaches or day-part group assignments.
17. Exporting the restored school again preserves its unique school key and
equivalent configuration, even if internal numeric IDs changed.
## Implementation handoff
This specification records agreed behavior. Backend endpoints, the detailed JSON
schema and frontend implementation remain implementation work; this review does
not implement the feature.

View File

@@ -0,0 +1,200 @@
# S4 — Build and publish pipelines in Gitea
Status: IMPLEMENTED
Agreed after the grill-me review; shared understanding confirmed.
## User story
As a maintainer, I want every branch push to build and test the application,
so that broken changes are detected and successful main-branch builds provide
identifiable Docker images in our own registry.
## Agreed environment and feasibility
- Gitea and its container registry run on the existing Synology.
- The existing development mini-PC runs the Gitea Actions runner, separately from
Gitea. No additional hardware is available or required.
- Gitea supports push-triggered Actions workflows and a runner on a separate
machine. Codex can implement the repository configuration and assist with the
installation and configuration required on the existing machines.
- Gitea was inspected as version 1.25.4. Match the runner and workflow setup to
the installed version rather than assuming newer documentation applies.
- The mini-PC was inspected as Linux x86_64 with a Docker client installed, but
without a reachable Docker daemon. Configuring a working daemon is part of S4.
- The current internal Gitea/registry endpoint is `http://192.168.2.28:3000`.
Use that endpoint over the trusted internal network and explicitly configure
Docker clients that need registry access to trust this particular HTTP registry.
Introducing HTTPS is outside S4.
- The runner and job containers need access to Gitea, the registry and dependency
download sources. The runner connects to Gitea; it needs no public incoming port.
- The mini-PC must be on, awake and running the runner. Jobs wait while it is
unavailable; S4 does not promise unattended availability when the PC is off.
References:
- [Gitea 1.25 Actions quickstart](https://docs.gitea.com/1.25/usage/actions/quickstart/)
- [Gitea 1.25 Actions design](https://docs.gitea.com/1.25/usage/actions/design/)
- [Gitea container registry](https://docs.gitea.com/usage/packages/container/)
## Scope
### In scope
- Version-controlled Gitea Actions workflows and supporting build configuration.
- Enable Actions as needed at instance and repository level, configure Docker on
the mini-PC, and install, register and configure its runner.
- Build and test both backend and frontend for every push to every branch,
including newly created branches, except when the author intentionally uses a
supported skip marker such as `[skip ci]`. Separate tag and pull-request event workflows
are not required; branch pushes also check changes used in pull requests.
- Build two runnable Docker images: backend and frontend.
- Run end-to-end tests against those built containers before publication.
- Publish both images only from successful builds of the `main` branch to the
container registry on the Synology.
- Configure registry authentication and the necessary secrets outside Git.
- Preserve failure diagnostics and document operation and recovery.
- Demonstrate a real successful pipeline and images that can be pulled back.
### Out of scope
- Automatic deployment, starting application containers on the Synology, and OTAP.
Starting temporary containers for pipeline tests is in scope.
- New linting or static-analysis gates, such as ESLint or Sonar. Existing tests,
including architecture tests, remain mandatory.
- Merge or release policies, separate tag/release workflows, and automatic image
deletion or retention cleanup. Published images remain available for now.
- Multi-architecture images, HTTPS setup, new hardware or provisioning additional
infrastructure.
## Build and verification behavior
1. Every ordinary branch push runs backend and frontend builds and their existing
tests. Explicit Gitea-supported skip markers are an accepted maintainer-approved
opt-out.
2. Backend verification includes the existing unit, integration/system and
architecture tests. Current entry point: `mvn clean verify` using Java 25.
3. Frontend verification uses the lockfile (`npm ci`), unit tests (`npm test`) and
production build (`npm run build`) with a supported Node version.
4. Build both Docker images on every branch, including branches that cannot
publish. The current Dockerfile only covers the backend; frontend packaging
must be added as part of implementation.
5. The frontend image serves the production Angular build, supports direct SPA
route navigation, and forwards `/api` requests to the backend container.
Container addressing/configuration is an implementation choice.
6. Run the existing Playwright end-to-end suite with Chromium against the built
frontend/backend containers, through the frontend's API forwarding. Adapt the
existing development-server test configuration as necessary: the acceptance
run must exercise the actual images, not development servers.
7. Determine the intended server's CPU architecture during implementation. Build
for that single target architecture and run the end-to-end tests on that same
architecture. Do not infer the Synology's architecture from the mini-PC.
Any architecture mismatch must be resolved and tested on the existing hardware
before claiming acceptance.
8. A failed build or test fails the pipeline and prevents publication. Test
containers are temporary and are cleaned up after the run, including failure.
## Publication and image identity
- Publish separate backend and frontend images under the repository owner's
namespace in the existing Gitea container registry. Document the exact names.
- Feature branches must not publish application images.
- Both images from a main-branch commit use the full Git commit SHA as their tag.
This identifies the matching pair independently of moving tags.
- Once both commit images have been successfully published, reruns verify/reuse
them without overwriting either commit tag.
- Publication succeeds only when both images are published and can be pulled
back from the registry. A partial publication fails the pipeline; one image may
already exist. A rerun preserves that image and may publish the missing image.
- After both commit images are available, update the moving `main` tags only if
the commit is still the current main-branch head. Serialize/coordinate that
operation so an older, slower pipeline cannot move `main` backwards.
- The two moving tags are not an atomic pair. Use the same commit SHA on both
images when an exact matching pair is needed. A failure updating a moving tag
must be visible as a pipeline failure and recoverable through a rerun.
- No automatic deletion of published images is introduced in S4.
## Failure diagnostics and operation
- Failed pipelines retain available test reports, container logs, and Playwright
traces and screenshots for fourteen days. Collect available diagnostics even
when a preceding step fails; do not hide the original failure.
- Provide a short management guide covering:
- Docker/runner installation, registration, startup and required access.
- Gitea instance/repository Actions settings and registry configuration.
- Required credentials, permissions and secret names, without secret values.
- Which settings exist outside Git and how to reproduce them.
- Trigger behavior, mini-PC availability and queued jobs.
- Image names, tags and commands to pull a matching image pair.
- Finding diagnostics, rerunning failed jobs and completing partial publication.
- The target architecture and how it was established.
- Keep registry credentials and registration tokens out of repository files and
logs; use the relevant secret settings.
## Acceptance criteria
- [x] A push to any branch, including a new branch, starts a pipeline, except for
an explicit supported skip marker chosen by the author.
- [x] Backend and frontend build and all existing tests, including architecture
and Playwright end-to-end tests, pass before publication is permitted.
- [x] Every branch builds both Docker images; end-to-end tests exercise those
images through the frontend and its `/api` forwarding.
- [x] A failing build or test fails the pipeline without publishing images.
- [x] A successful feature-branch pipeline publishes no application images.
- [x] A successful `main` pipeline publishes both images to the Synology registry
with the full commit SHA; both images can be pulled back.
- [x] Published commit images are preserved on rerun; partial publication can be
completed without overwriting an existing commit image.
- [x] Moving `main` tags are updated only after both commit images are available,
and an older pipeline cannot move them backwards.
- [x] Publication or pull-verification failure makes the pipeline fail, even if
some images have already been uploaded.
- [x] Available failure diagnostics are retained for fourteen days, and temporary
test containers are cleaned up on success and failure.
- [x] The runner operates on the existing mini-PC, with Gitea and the registry on
the existing Synology; no additional hardware is needed.
- [x] The single target architecture is established and the images are tested on
that architecture using the existing hardware.
- [x] A management guide records setup, external settings, secrets, image usage
and recovery, including the need to keep the mini-PC/runner available.
- [x] Actual pipeline runs demonstrate successful main-branch publication,
feature-branch checks without publication, and failure blocking publication.
## Implementation handoff
This specification captures the agreed design. It does not install the runner,
change server settings or implement the pipeline. S4 is complete only when the
configuration, documentation and operational acceptance evidence are delivered;
workflow files alone are insufficient.
## Implementation progress
Repository implementation and local Docker verification are available. See
[management instructions](../../docs/gitea-ci.md) and
[validation evidence](../../docs/s4-validation.md).
Backend verification (20 tests), frontend verification (14 tests), both runtime
image builds and both Playwright tests against the containers passed. Fifteen
Java CI publication/configuration tests pass. The runner binary and user-service
configuration are installed on the mini-PC.
The maintainer confirmed the Synology as `x86_64` / `linux/amd64`. Gitea secrets
and the target-platform variable are configured; the runner is registered and
online. Registry login succeeded. Real feature runs #1 and #3 passed, including
container E2E; deliberate failure run #2 blocked the build/publication path and
provided downloadable diagnostics.
PR #1 was subsequently merged by the maintainer. Main run #7 succeeded for
commit `2356a31aa612c8b0ce4b386a0a65da6589e23285`, publishing and pulling both
full-SHA images and both main aliases. Registry digests are recorded in the
validation evidence.
The final real-registry probes confirmed partial-publication recovery, immutable
commit-tag preservation on rerun and stale-main protection in isolated validation
repositories. Application manifests remained unchanged. The maintainer confirmed
that the Synology app.ini has no actions section, so Gitea 1.25.4's documented
90-day artifact and 365-day log defaults apply; the workflow requests fourteen
days for diagnostic artifacts. Explicit skip markers are accepted by the
maintainer. All acceptance criteria are met; see the validation evidence for
probe details, digests and the distinction from full Gitea workflow reruns.