All checks were successful
Build, test and publish / verify (push) Successful in 7m31s
157 lines
10 KiB
Markdown
157 lines
10 KiB
Markdown
# 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.
|