S16 postgresql opslag added
All checks were successful
Build, test and publish / verify (push) Successful in 7m31s
All checks were successful
Build, test and publish / verify (push) Successful in 7m31s
This commit is contained in:
135
docs/persistent-storage.md
Normal file
135
docs/persistent-storage.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# PostgreSQL storage (S16)
|
||||
|
||||
The backend requires PostgreSQL 17. Flyway applies the versioned SQL under
|
||||
`agiledancers-be/src/main/resources/db/migration` before startup recovery and
|
||||
readiness. Never edit an already deployed migration; add the next version instead.
|
||||
The database owns domain identifiers and a monotonically increasing school
|
||||
revision. Application persistence uses JPA/Hibernate ORM: mapped entities and
|
||||
collections live in `repository.entity`, and repositories use `EntityManager`.
|
||||
The existing domain objects remain independent of JPA. Database constraints enforce
|
||||
school ownership of every relationship.
|
||||
|
||||
Production uses `deploy/compose.yaml`: PostgreSQL has no published port and keeps
|
||||
its data in the named volume `agiledancers-production-database`. Set a long random
|
||||
`DATABASE_PASSWORD` in the mode-600 `production.env` on the NAS before the first
|
||||
S16 deployment. The release helper exports it for Compose without writing it to
|
||||
release metadata. The backend receives:
|
||||
|
||||
- `DATABASE_URL=jdbc:postgresql://database:5432/agiledancers`
|
||||
- `DATABASE_USER=agiledancers`
|
||||
- `DATABASE_PASSWORD` from `production.env`
|
||||
|
||||
Database health gates backend startup, and the backend readiness check includes
|
||||
the datasource. Acquisition failures reject requests with `503` and a message that
|
||||
the mutation was not stored. There is no volatile fallback. PostgreSQL's normal
|
||||
WAL, fsync and synchronous-commit defaults must remain enabled. Application writes
|
||||
are acknowledged only after commit. A network loss during acknowledgement can
|
||||
leave the client uncertain; reload current data before deciding to retry.
|
||||
|
||||
## Transition from the previous release
|
||||
|
||||
1. Export **every school** through JSON while the old backend is still running.
|
||||
Its data exists only in memory and cannot be recovered after it stops.
|
||||
2. Keep those exports, configure the database password, then deploy S16. The
|
||||
first startup creates an empty relational database through Flyway.
|
||||
3. Import the JSON files through the existing preview and confirmation workflow.
|
||||
School keys and file-local relationship semantics remain unchanged; runtime
|
||||
IDs are assigned by PostgreSQL. A replacement retains the target school ID.
|
||||
4. Verify schools and saved assignments after a restart before removing exports.
|
||||
Import retains the existing behavior of importing schedules as drafts.
|
||||
|
||||
Deployments recreate only the application containers. Never run `compose down -v`
|
||||
or delete the named database volume. Rollback replaces application images, not
|
||||
schema migrations; only roll back to a database-compatible release. An image from
|
||||
before S16 cannot read the new database. Database/volume loss recovery and backup
|
||||
operations are deferred to S17.
|
||||
|
||||
## Local development and verification
|
||||
|
||||
Quarkus Dev Services starts disposable PostgreSQL for development and tests when
|
||||
no datasource URL is configured; Docker must be accessible. For a durable local
|
||||
instance, create a PostgreSQL service with a persistent volume and pass
|
||||
`QUARKUS_DATASOURCE_JDBC_URL`, `QUARKUS_DATASOURCE_USERNAME`, and
|
||||
`QUARKUS_DATASOURCE_PASSWORD` to dev/test execution. Production uses the three
|
||||
`DATABASE_*` variables above. Never reuse a production database for tests.
|
||||
|
||||
```sh
|
||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64 mvn -Dformat.mode=check clean verify
|
||||
cd agiledancers-fe
|
||||
npm test
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
Standalone Docker builds run the complete backend tests against a reachable test
|
||||
database. Supply its configuration through BuildKit secrets (not image build
|
||||
arguments), for example with shell variables `TEST_DATABASE_URL`,
|
||||
`TEST_DATABASE_USER` and `TEST_DATABASE_PASSWORD` already set:
|
||||
|
||||
```sh
|
||||
docker build --network=host \
|
||||
--secret id=database_url,env=TEST_DATABASE_URL \
|
||||
--secret id=database_user,env=TEST_DATABASE_USER \
|
||||
--secret id=database_password,env=TEST_DATABASE_PASSWORD \
|
||||
-t agiledancers .
|
||||
```
|
||||
|
||||
CI runs verification against disposable PostgreSQL, packages the exact verified
|
||||
output using the `prebuilt` Docker target, and starts a separate database on its
|
||||
isolated browser-test network. Cleanup removes those test containers only.
|
||||
|
||||
The packaged-process regression test below checks graceful and abrupt backend
|
||||
termination, stable recovered run IDs through HTTP and SSE, committed results,
|
||||
interrupted calculations, database outages, and failed startup/migrations. It
|
||||
requires a built backend and an **isolated disposable database container**: the
|
||||
test deliberately stops and restarts the named container. It does not remove its
|
||||
volume. Pass matching connection options if they differ from the defaults.
|
||||
|
||||
```sh
|
||||
python3 tooling/persistence/restart_test.py --database-container agiledancers-s16-test
|
||||
```
|
||||
|
||||
S16 targets one active backend. The existing domain monitor serializes short
|
||||
snapshot/mutation/commit units of work; solver work runs outside that monitor and
|
||||
outside database transactions. Results use the school revision captured at start.
|
||||
Changes elsewhere in the same school may invalidate a run. Latest progress and
|
||||
outcome are durable; calculations left Running at startup become Interrupted and
|
||||
retain earlier saved assignments. There is no automatic resumption or run history.
|
||||
|
||||
|
||||
## JPA mapping and schema upgrades
|
||||
|
||||
Hibernate manages relationships, element collections, ordered assignments and
|
||||
orphan removal through mapped entities. Its `@Version` on the school entity
|
||||
implements optimistic concurrency. A child-only change marks the aggregate dirty,
|
||||
so the school version advances exactly once without manual version-update SQL.
|
||||
JTA owns the transaction boundary; run acceptance and completion are published only
|
||||
after commit. Detached domain snapshots do not expose Hibernate proxies through the
|
||||
API or to solver threads.
|
||||
|
||||
Flyway remains the only schema writer. Hibernate runs in `validate` mode and never
|
||||
creates or alters application tables. V1 is retained unchanged. V2 adds the aggregate
|
||||
change stamp, a JPA-managed identifier counter seeded above the existing sequence,
|
||||
and a deferred date/type uniqueness check for reordering dayparts. Existing school
|
||||
keys, entity IDs, assignments and scheduling status are preserved. The counter is
|
||||
locked while allocating IDs within a transaction. Rollback requires a release that
|
||||
understands V2's identifier allocation; the earlier JDBC implementation is not a
|
||||
compatible rollback target.
|
||||
|
||||
|
||||
## API projections
|
||||
|
||||
MapStruct 1.6.3 generates the REST-layer `DomainViewMapper` for domain objects to
|
||||
view records. REST resources inject the generated CDI bean. Relationship collections
|
||||
map to ID lists through one shared helper; validation remains a use-case result
|
||||
passed explicitly to the mapper. Preferred-daypart defaults call the existing
|
||||
application rule. View constructors preserve immutable snapshots.
|
||||
|
||||
The mapper sets `unmappedTargetPolicy = ERROR`: every target component must have a
|
||||
mapping, whether inferred from a matching property or declared explicitly. A newly
|
||||
added unmatched component therefore fails compilation. The backend compiler runs
|
||||
MapStruct together with Lombok and its pinned MapStruct binding. Generated classes
|
||||
stay under `target/generated-sources/annotations`; they are not maintained source.
|
||||
|
||||
Persistence entities and shared domain graph identity continue to use PeopleMapping,
|
||||
GroupMapping and ShowMapping. MapStruct does not construct or update that graph.
|
||||
@@ -4,10 +4,11 @@ De buildworkflow bouwt, test en publiceert automatisch. Productie verandert
|
||||
alleen via **Actions → Deploy production → Run workflow** of **Rollback
|
||||
production**. Start beide vanaf `main`; de workflows verschijnen na de merge.
|
||||
|
||||
**Tot S16 is geïmplementeerd kan iedere deployment, retry, rollback of automatisch
|
||||
herstel alle applicatiegegevens wissen.** Informeer de launching partner vooraf.
|
||||
Een onderbroken berekening moet opnieuw worden gestart. Een herstelde
|
||||
applicatieversie herstelt geen verloren gegevens.
|
||||
**Voor de eerste S16-deployment: exporteer alle scholen voordat de oude backend
|
||||
stopt.** De oude release bewaart gegevens alleen in geheugen. Configureer ook
|
||||
`DATABASE_PASSWORD` in `production.env`. Zie [database-inrichting en overgang](persistent-storage.md).
|
||||
Nieuwe releases gebruiken een apart PostgreSQL-volume; verwijder dit volume niet.
|
||||
Onderbroken berekeningen worden als Interrupted hersteld en starten niet vanzelf.
|
||||
|
||||
## Eenmalige DSM-inrichting
|
||||
|
||||
@@ -285,11 +286,12 @@ nieuwe release door te drukken.
|
||||
|
||||
## Na S16 en lokale verificatie
|
||||
|
||||
S16 blokkeert S6 niet. Zodra S16 is ingevoerd, moeten database/volumes buiten de
|
||||
vervangbare containers blijven en saved data zowel deployment als rollback
|
||||
overleven. De gewone procedure vereist dan databasecompatibiliteit met de vorige
|
||||
applicatieversie. Plan incompatibele migraties apart: imageherstel maakt geen
|
||||
migratie ongedaan. Backup/restore blijven S17-werk.
|
||||
De databaseservice en het volume `agiledancers-production-database` blijven buiten
|
||||
de vervanging van backend en frontend. `production.env` levert het databasewachtwoord
|
||||
ook bij retry en rollback; het staat niet in releasebestanden. De procedure vereist
|
||||
databasecompatibiliteit met de vorige applicatieversie. Plan incompatibele migraties
|
||||
apart: imageherstel maakt geen migratie ongedaan. Rollback naar een oude release
|
||||
van vóór S16 kan de database niet lezen. Backup/restore blijven S17-werk.
|
||||
|
||||
```sh
|
||||
java ci/Ci.java test
|
||||
|
||||
Reference in New Issue
Block a user