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:
156
specs/S16-validation.md
Normal file
156
specs/S16-validation.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# S16 implementation validation
|
||||
|
||||
## Delivered behavior
|
||||
|
||||
PostgreSQL owns normalized school, dancer, coach, group, membership, style, show,
|
||||
daypart, appearance and ordered-assignment tables, plus the latest scheduling run.
|
||||
Flyway V1 creates the schema, persistent identifier sequence, cross-school-safe
|
||||
foreign keys and row constraints. School keys, runtime identifiers, relationship
|
||||
identity, coach links, draft assignments and finalized state survive reload.
|
||||
|
||||
Application persistence uses JPA/Hibernate ORM with mapped entities in
|
||||
`repository.entity` and `EntityManager` repositories. Relationships, element
|
||||
collections, daypart order and orphan removal are managed by Hibernate; domain
|
||||
objects and API responses remain framework independent. The hand-written JDBC
|
||||
query/update layer and row readers have been removed.
|
||||
|
||||
The HTTP interceptor runs each school operation in a short repeatable-read JTA
|
||||
transaction under the existing domain monitor. Reads convert managed entities into
|
||||
detached domain snapshots. Hibernate's school `@Version` checks optimistic changes;
|
||||
a change stamp marks child-only edits so the school revision advances exactly once.
|
||||
Missing or stale caller revisions conflict before applying edits, and stale detached
|
||||
JPA entities also fail. Successful graph merges flush before commit, and status
|
||||
publication remains after durable commit. A single school-data endpoint gives the
|
||||
editor a consistent data/revision snapshot. Open editors retain their original
|
||||
revision across background refreshes; conflict responses preserve their input and
|
||||
require reload before retry. Replacement imports retain the target school ID and
|
||||
check the revision returned by preview. Existing JSON import/export semantics remain.
|
||||
|
||||
Domain-to-view projection now uses MapStruct 1.6.3 in the REST layer. The generated
|
||||
CDI `DomainViewMapper` covers schools, dancers, groups, coaches, dayparts and shows.
|
||||
A shared ID conversion projects relationships to ordered ID lists; validation results
|
||||
remain an explicit argument and preferred-daypart defaults delegate to the existing
|
||||
application rule. View record constructors retain their defensive copies. Entity to
|
||||
domain graph construction remains explicit in the persistence adapter.
|
||||
`unmappedTargetPolicy = ERROR` rejects missing target fields at compilation. A compiler
|
||||
probe with the actual mapper and an added unmapped SchoolView component confirms this
|
||||
failure, without modifying maintained sources. MapStruct's generated implementation
|
||||
is marked `lombok.Generated`, preserving the existing generated-code scope of coverage
|
||||
and architecture checks; handwritten mapper helpers remain covered and checked.
|
||||
|
||||
Flyway remains the schema authority; Hibernate validates rather than generates DDL.
|
||||
V1 is unchanged. V2 preserves existing rows, adds the aggregate change stamp and a
|
||||
JPA-managed identifier counter seeded above previously allocated IDs, and defers
|
||||
date/type uniqueness until commit so Hibernate can reorder retained dayparts safely.
|
||||
Identifier allocation takes a pessimistic lock on the counter row. Coach/dancer and
|
||||
group/coach associations use Hibernate composite join mappings to share the owning
|
||||
school key while letting Hibernate update the linked member column directly.
|
||||
|
||||
Run acceptance checks the school revision and persists the run before launch or
|
||||
acknowledgement. Acceptance itself does not change scheduling inputs. Background
|
||||
computation holds neither a database transaction nor the domain monitor. Progress
|
||||
commits before publication. Successful assignment replacement, school revision and
|
||||
terminal run status commit together; publication callbacks run only after commit.
|
||||
Deferred constraint failures roll back both assignments and status without
|
||||
publishing success. Database failure never falls back to acknowledged memory-only
|
||||
writes. Disconnected status subscribers cannot turn a committed result into a
|
||||
solver failure.
|
||||
|
||||
Startup recovery marks persisted Running runs Interrupted before serving status,
|
||||
retains their IDs, progress and previous saved assignments, and creates no old run
|
||||
guards. The frontend recognizes Interrupted and retains S12's reconnect/reload
|
||||
notification behavior. Timestamps use PostgreSQL microsecond precision consistently
|
||||
in live and recovered snapshots.
|
||||
|
||||
## Verification
|
||||
|
||||
- Maven clean verify: all 72 backend tests and 19 standards-checker regression tests
|
||||
pass. The JPA integration run also verified Flyway V1 and V2 and Hibernate schema
|
||||
validation against an empty database, as well as an upgrade of the populated V1
|
||||
test database.
|
||||
- Backend line coverage: 1763/1827 (96.50%), above the 80% gate.
|
||||
- Frontend: 32 unit tests, production build and ESLint pass (unchanged by the
|
||||
MapStruct-only backend change).
|
||||
- Generated-mapper CDI tests cover ordered relationship IDs, an unlinked coach,
|
||||
nested assignment order, defensive copies, explicit validation messages and the
|
||||
configured/default preferred-daypart rule. The compile-time unmapped-field probe
|
||||
passes with the expected compiler error.
|
||||
- Playwright: the three existing real REST/browser scenarios pass with PostgreSQL;
|
||||
a fourth scenario verifies two screens editing the same revision, conflict
|
||||
handling with retained form input, and successful reload/retry.
|
||||
- PostgreSQL tests cover simultaneous edits (one succeeds, one conflicts), missing
|
||||
revisions, relational graph recovery, IDs and ordered assignments, finalized
|
||||
state, deferred commit failure without success publication, failed replacement
|
||||
import rollback, stale scheduling inputs and interrupted-run recovery. JPA-specific
|
||||
tests verify stale detached entities, exactly one aggregate version increment for
|
||||
child-only edits, and reordered dayparts retaining their assignments.
|
||||
- `tooling/persistence/restart_test.py` runs the packaged production backend against
|
||||
an isolated persistent PostgreSQL container. It passes graceful restart and
|
||||
SIGKILL interruption checks, verifies a completed saved result after every
|
||||
restart, checks stable recovered IDs through HTTP and SSE, starts a new run after
|
||||
interruption, rejects mutations during a database outage, and verifies startup
|
||||
failure for an unreachable database and a deliberately failing Flyway migration.
|
||||
- CI helper tests: 17 pass. Release and actual deployment-shell behavior tests:
|
||||
32 pass. Shell syntax and Java/frontend formatting checks pass.
|
||||
|
||||
The packaged-process checks deliberately stop/restart only the named disposable
|
||||
test database. Production deployment was not performed. Database provisioning and
|
||||
transition instructions are in `docs/persistent-storage.md`; export every school
|
||||
before stopping the old in-memory release. Production Compose retains its database
|
||||
volume outside application replacement. CI supplies a separate disposable browser
|
||||
database and removes its anonymous volume during cleanup.
|
||||
|
||||
## Manual standards assessment
|
||||
|
||||
No waivers or weaker gates were added. Architecture tests pass. Persistence entities
|
||||
and their embeddable keys belong to the repository layer, while the scheduling
|
||||
records remain in `model.scheduling`. Mutable classes, no-argument construction,
|
||||
setters and replaceable collections are deliberate JPA lifecycle requirements;
|
||||
Hibernate installs managed collection wrappers and hydrates fields. Composite key
|
||||
values are assigned before persistence and are not mutated afterward. None of these
|
||||
entities or lazy collections escapes into the solver or the API. Existing immutable
|
||||
snapshot records still defensively copy mutable collections.
|
||||
|
||||
Retained review signals in changed code:
|
||||
|
||||
- Database fan-out 27 and transaction cyclomatic complexity 8: JPA/JTA lifecycle,
|
||||
rollback and heuristic failures, optimistic-conflict classification, and committed
|
||||
publication are handled in one transaction owner. Its two injected dependencies
|
||||
remain below the review signal.
|
||||
- SchoolWriter fan-out 17: one adapter builds and merges the school graph, removes
|
||||
deleted-show statuses, checks JPA revisions and flushes changes. PeopleMapping,
|
||||
GroupMapping and ShowMapping separate domain conversion from ORM lifecycle.
|
||||
- Entity fan-out reflects explicit relationship and collection annotations:
|
||||
DayPartEntity 22, GroupEntity 24, RunEntity 17, SchoolEntity 18 and ShowEntity 23.
|
||||
Each maps one existing table/aggregate boundary; splitting fields merely to lower
|
||||
annotation-driven fan-out would obscure the relational mappings. Entity collections
|
||||
are mutable only within the persistence adapter and Hibernate session.
|
||||
- SchoolTransactions fan-out 19 and request cyclomatic complexity 9: four collaborators
|
||||
cover the detached domain monitor, transaction owner, loader and writer. The branch
|
||||
structure distinguishes reads, run acceptance and domain mutations and maps storage
|
||||
failures separately from optimistic conflicts. SchoolChange's four components
|
||||
keep the revision and operation classification together.
|
||||
- SchedulingRuns fan-out 31: it coordinates immutable input/progress/run/result
|
||||
records, the solver port, durable lifecycle operations and subscriber callbacks;
|
||||
its three injected collaborators remain below the dependency review signal.
|
||||
- SchoolManagementService fan-out 38, 30 public methods, beginScheduling
|
||||
cyclomatic complexity 8 and the existing five-parameter updateShow are retained:
|
||||
aggregate use cases and validations remain together. Load installs detached state
|
||||
and resets transient input counters under the existing monitor.
|
||||
- REST resource fan-out is 18–28 (DanceSchoolResource 25): resources combine HTTP
|
||||
annotations, use cases, request/view contracts and the injected projection mapper.
|
||||
The consistent data endpoint assembles views inside the transaction. DomainViewMapper
|
||||
fan-out 25 represents six explicit source/target projections plus the MapStruct
|
||||
annotations and two small shared helpers. DomainViewMapperTest fan-out 22 exercises
|
||||
the generated CDI mapper's API edge cases. SchoolView's six components include the revision;
|
||||
SchoolDataView's five components represent one editor snapshot. ImportPreview's
|
||||
seventh component identifies the target revision for replacement.
|
||||
- PersistenceTest fan-out 47, seven injected fixtures, 335 code lines and methods of
|
||||
41/33/42 lines: these cross real ORM, graph and transaction boundaries, including
|
||||
detached-entity conflicts, commit-time failure, failed import, child versioning and
|
||||
reordered assignments. The fixtures remain below all blocking limits. Existing
|
||||
changed REST/SSE/background fixture metrics retain their S12/S7 rationale.
|
||||
|
||||
One active backend remains the supported deployment model. Global execution
|
||||
capacity, distributed workers, database backup/restore and recovery after database
|
||||
volume loss remain outside S16. S17 owns backup/restore.
|
||||
@@ -1,6 +1,6 @@
|
||||
# S12 — Asynchronous feedback for scheduling
|
||||
|
||||
Status: IN_REVIEW
|
||||
Status: IMPLEMENTED
|
||||
|
||||
Agreed after the grill-me interview; shared understanding confirmed.
|
||||
|
||||
@@ -86,7 +86,7 @@ and what the outcome is, including when I leave and return to the show page.
|
||||
## Persistence and backend restarts
|
||||
|
||||
The maintainer explicitly transferred durable scheduling status and recovery
|
||||
following backend restarts to [S16](../refined/S16_store-state-in-persistent-storage)
|
||||
following backend restarts to [S16](../in_review/S16_store-state-in-persistent-storage)
|
||||
when completing S12. The latest status and outcome in S12 survive navigation,
|
||||
page reloads and SSE reconnection while the same backend process remains active.
|
||||
Schools, assignments and scheduling status currently remain in memory.
|
||||
@@ -1,6 +1,6 @@
|
||||
# S16 — Store state in persistent storage
|
||||
|
||||
Status: REFINED
|
||||
Status: IN_REVIEW
|
||||
|
||||
Agreed after the grill-me interview; shared understanding confirmed.
|
||||
|
||||
@@ -14,7 +14,8 @@ and application crashes.
|
||||
|
||||
Use PostgreSQL with relational tables for schools, dancers, coaches, groups,
|
||||
shows and their relationships. Use Flyway to version and apply database schema
|
||||
changes.
|
||||
changes. Use JPA with Hibernate ORM for application persistence; keep the mappings
|
||||
inside the repository layer so the existing domain model remains framework independent.
|
||||
|
||||
The existing domain has shared relationships and operations on individual school
|
||||
components. Related changes must be atomic, and multiple maintainers must be able
|
||||
@@ -121,32 +122,34 @@ for now. S16 does not promise recovery after loss of the database or its volume.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] PostgreSQL stores the complete maintained domain state and saved scheduling
|
||||
- [x] PostgreSQL stores the complete maintained domain state and saved scheduling
|
||||
results, with Flyway managing the relational schema.
|
||||
- [ ] Confirmed changes remain available after both a normal restart and an
|
||||
- [x] Confirmed changes remain available after both a normal restart and an
|
||||
application crash, using the same persistent database.
|
||||
- [ ] Failed related mutations and failed school replacement imports leave no
|
||||
- [x] Failed related mutations and failed school replacement imports leave no
|
||||
partial changes or dangling references.
|
||||
- [ ] Two edits based on the same school revision cannot silently overwrite one
|
||||
- [x] Two edits based on the same school revision cannot silently overwrite one
|
||||
another: the stale edit receives a clear conflict response, and the user
|
||||
can reload and retry.
|
||||
- [ ] Scheduling results based on outdated input revisions are rejected.
|
||||
- [ ] The latest accepted scheduling run, its stable identifier, timestamps,
|
||||
- [x] Scheduling results based on outdated input revisions are rejected.
|
||||
- [x] The latest accepted scheduling run, its stable identifier, timestamps,
|
||||
progress, outcome and objective summary survive normal restart and crash
|
||||
and are returned through the status API and SSE snapshots.
|
||||
- [ ] Successful assignment replacement and completed run status commit
|
||||
- [x] Successful assignment replacement and completed run status commit
|
||||
atomically; success is published only after durable commit.
|
||||
- [ ] Calculations left Running become Interrupted before recovered status is
|
||||
- [x] Calculations left Running become Interrupted before recovered status is
|
||||
served; previous assignments remain, no automatic resumption occurs and a
|
||||
new run can start. Reopening does not replay old completion snackbars.
|
||||
- [ ] Database unavailability prevents successful mutation acknowledgements;
|
||||
- [x] Database unavailability prevents successful mutation acknowledgements;
|
||||
startup connection and migration failures are clearly reported.
|
||||
- [ ] An empty database can be initialized through Flyway and populated through
|
||||
- [x] An empty database can be initialized through Flyway and populated through
|
||||
existing JSON import, preserving import/export behavior and identities.
|
||||
- [ ] Setup and transition instructions cover the database service, persistent
|
||||
- [x] Setup and transition instructions cover the database service, persistent
|
||||
storage, connection configuration, migrations and export-before-transition.
|
||||
|
||||
## Implementation handoff
|
||||
|
||||
This specification records the agreed design and behavior. Database provisioning,
|
||||
application changes and validation are subsequent implementation work.
|
||||
PostgreSQL/JPA/Hibernate storage, Flyway migrations, school revision checks, durable scheduling status and
|
||||
restart recovery are implemented and verified. See [S16 validation](../S16-validation.md)
|
||||
and [setup and transition instructions](../../docs/persistent-storage.md).
|
||||
Implementation is ready for review; final acceptance is pending.
|
||||
Reference in New Issue
Block a user