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:
@@ -1,144 +0,0 @@
|
||||
# S12 — Asynchronous feedback for scheduling
|
||||
|
||||
Status: IN_REVIEW
|
||||
|
||||
Agreed after the grill-me interview; shared understanding confirmed.
|
||||
|
||||
## User story
|
||||
|
||||
As a dance-school maintainer, I want feedback after starting Schedule Groups,
|
||||
so that I can see whether the backend is still calculating, when it finishes
|
||||
and what the outcome is, including when I leave and return to the show page.
|
||||
|
||||
## Background execution and concurrency
|
||||
|
||||
- Start scheduling in the backend without keeping the initiating HTTP request
|
||||
open until the calculation finishes. Navigation, page reloads and disconnected
|
||||
clients must not stop the calculation.
|
||||
- The backend owns the current scheduling status for each show. All open
|
||||
screens see the same status, including screens that did not start the run.
|
||||
- Allow at most one active calculation per show. Disable Schedule Groups while
|
||||
it is running and reject duplicate starts in the backend as well.
|
||||
- Different shows may calculate concurrently. A global capacity limit and a
|
||||
waiting queue are outside S12.
|
||||
- Retain the existing 30-minute solver limit and scheduling rules.
|
||||
|
||||
## Progress and outcomes
|
||||
|
||||
- While running, show elapsed time, the current optimization phase (attendance,
|
||||
spread or variety), and whether a valid solution has been found.
|
||||
- Report a valid solution as soon as the solver discovers one, including during
|
||||
a phase. Extend solver progress reporting rather than waiting for the phase
|
||||
to finish. Do not apply intermediate solutions.
|
||||
- Do not present a completion percentage or estimated finish time: the phases
|
||||
do not represent proportional parts of the calculation time.
|
||||
- Keep the latest status and outcome per show until a new calculation starts.
|
||||
Show the finish time and distinguish an optimal solution from a valid solution
|
||||
whose optimality was not proven within the time limit.
|
||||
- For a successful result, show a concise summary with concrete results for
|
||||
attendance, spread and variety, using understandable labels.
|
||||
- Clearly distinguish invalid input, infeasibility, solver failure, time limit
|
||||
without a valid solution and rejection because inputs changed. Explain why
|
||||
no result was applied and that existing assignments were preserved.
|
||||
Backend-restart interruption recovery belongs to S16.
|
||||
|
||||
## Applying results
|
||||
|
||||
- Retain the confirmation before starting that explains replacement of existing
|
||||
assignments. A successful completed calculation automatically replaces them;
|
||||
no preview/apply step is introduced.
|
||||
- A valid solution may be applied when the time limit expires even if optimality
|
||||
has not been proven.
|
||||
- Preserve the existing scheduling input revision check. A result based on
|
||||
outdated inputs must not replace the current assignments.
|
||||
- Failed, infeasible, interrupted, stale and no-solution calculations preserve
|
||||
existing assignments.
|
||||
- Report success only after the resulting assignments have been saved. Keep
|
||||
status and saved results consistent.
|
||||
|
||||
## Server-sent events and connection recovery
|
||||
|
||||
- Use server-sent events (SSE) for backend-to-frontend status updates.
|
||||
- On initial connection and reconnection, provide the current backend status.
|
||||
Correctness must not depend on receiving every previous event.
|
||||
- Maintain updates across navigation within the application so completion
|
||||
notifications can appear outside the show page.
|
||||
- If the connection is lost, indicate that displayed status may be outdated
|
||||
while the backend calculation continues. Reconnect and reconcile with the
|
||||
current status when connectivity returns.
|
||||
- Configure the application's proxy for streaming so updates reach the client
|
||||
promptly rather than being buffered until completion.
|
||||
|
||||
## Completion notifications
|
||||
|
||||
- Show an application-wide snackbar when a calculation completes or fails,
|
||||
including when the user has navigated to another application page.
|
||||
- Include the show name, a short outcome and a View show action.
|
||||
- Phase changes update progress without generating snackbars.
|
||||
- After temporary connection loss, show a missed completion notification once
|
||||
when the connection recovers. Reconnection must not repeatedly notify for
|
||||
the same completion.
|
||||
- Do not replay old snackbars on page reload or reopening the application;
|
||||
show the retained status on the show page instead.
|
||||
- Email, browser notifications and notifications outside the application are
|
||||
outside S12.
|
||||
|
||||
## 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)
|
||||
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.
|
||||
|
||||
S16 owns PostgreSQL storage of the latest run, atomic persistence of saved
|
||||
assignments and completed status, and startup recovery of previously running
|
||||
calculations as Interrupted without automatic resumption. Previously saved
|
||||
results must survive restart under S16. These are not completion criteria for S12.
|
||||
Distributed execution and scheduling on another PC remain in S13.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Cancelling a calculation or applying an intermediate solution.
|
||||
- History of earlier calculations beyond the latest status and outcome.
|
||||
- Global capacity limits, queues and remote workers.
|
||||
- Changes to scheduling objectives or constraints.
|
||||
- This specification grants no coding-standards waiver.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] Starting Schedule Groups returns without waiting for solver completion;
|
||||
leaving or reloading the page does not interrupt the calculation.
|
||||
- [x] Opening a show in another screen recovers its current backend status;
|
||||
duplicate runs for the same show are prevented in frontend and backend,
|
||||
while different shows can run concurrently.
|
||||
- [x] Running status shows elapsed time, phase and discovery of a valid solution
|
||||
during a phase, without a fabricated completion percentage or ETA.
|
||||
- [x] SSE delivers status changes promptly through the deployed proxy. Initial
|
||||
connection and reconnection reconcile the current state, and loss of
|
||||
connectivity visibly marks status as potentially outdated.
|
||||
- [x] Successful runs automatically apply their result after the existing start
|
||||
confirmation, retain stale-input protection and distinguish proven optimal
|
||||
results from valid results at the time limit.
|
||||
- [x] The final display includes finish time and concrete attendance, spread and
|
||||
variety results when successful; unsuccessful outcomes are distinguishable
|
||||
and explain that previous assignments were preserved.
|
||||
- [x] An application-wide snackbar reports completion or failure with the show
|
||||
name and View show action, including after navigation to another page.
|
||||
- [x] Connection recovery notifies once for a missed completion; phase changes,
|
||||
repeated reconnection and reopening do not replay old snackbars.
|
||||
- [x] The latest status and outcome survive navigation, page reload and SSE
|
||||
reconnection within the lifetime of the running backend. Durable storage
|
||||
and recovery after backend restart are explicitly transferred to S16.
|
||||
|
||||
## Review handoff
|
||||
|
||||
Background execution, solver progress callbacks, SSE, frontend status recovery,
|
||||
result summaries, proxy streaming configuration and application-wide completion
|
||||
notifications are implemented and verified. S12 replaces S9's synchronous request
|
||||
behavior while retaining scheduling and result-application protections.
|
||||
|
||||
See [S12 validation](../S12-validation.md) for verification and retained standards
|
||||
signals. Durable storage and backend-restart recovery are tracked in S16 and do
|
||||
not block review of this specification under the agreed scope adjustment.
|
||||
Implementation is ready for review; final acceptance is pending.
|
||||
155
specs/in_review/S16_store-state-in-persistent-storage
Normal file
155
specs/in_review/S16_store-state-in-persistent-storage
Normal file
@@ -0,0 +1,155 @@
|
||||
# S16 — Store state in persistent storage
|
||||
|
||||
Status: IN_REVIEW
|
||||
|
||||
Agreed after the grill-me interview; shared understanding confirmed.
|
||||
|
||||
## User story
|
||||
|
||||
As a dance school maintainer, I want application data to be stored persistently,
|
||||
so that confirmed changes and saved scheduling results survive server restarts
|
||||
and application crashes.
|
||||
|
||||
## Storage decision
|
||||
|
||||
Use PostgreSQL with relational tables for schools, dancers, coaches, groups,
|
||||
shows and their relationships. Use Flyway to version and apply database schema
|
||||
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
|
||||
to work without silently overwriting each other's changes. These requirements
|
||||
favor relational storage with transactions and referential constraints.
|
||||
|
||||
A document database was considered: a whole-school document would align with
|
||||
JSON import/export. However, the agreed requirements provide no concrete benefit
|
||||
for that approach over relational storage. The application owns a fixed domain
|
||||
model; school-defined arbitrary fields and structures are not required.
|
||||
|
||||
JSON remains the import/export format, rather than the primary storage model.
|
||||
|
||||
## Scope and deployment
|
||||
|
||||
- Support multiple schools and concurrent maintainers.
|
||||
- Target one production environment with one active backend instance.
|
||||
- A separate database service and its operational management are acceptable.
|
||||
- Multiple active backend instances, distribution across servers or regions, and
|
||||
automatic resumption of calculations are outside S16.
|
||||
- Keep the implementation within existing project architecture and coding
|
||||
standards; this specification grants no standards waiver.
|
||||
|
||||
## Durability and consistency
|
||||
|
||||
- Confirm a mutation as successful only after its database transaction commits
|
||||
durably. All confirmed domain changes and saved scheduling results survive an
|
||||
application restart or crash.
|
||||
- Persist schools and all their maintained domain data, relationships and saved
|
||||
planning state, rather than only a subset of the existing in-memory state.
|
||||
- Related mutations either succeed completely or leave the previous state intact.
|
||||
This includes deleting a dancer and cleaning up memberships, deleting a group
|
||||
and cleaning up show references, deleting a school and its children, and
|
||||
replacing a school through import.
|
||||
- Validate imports before publishing the replacement. Preserve the current
|
||||
import/export behavior and identity semantics.
|
||||
- Enforce valid relationships through database constraints alongside application
|
||||
validation.
|
||||
|
||||
## Concurrent changes and scheduling
|
||||
|
||||
- Use one persistent revision per school for optimistic concurrency control.
|
||||
- Mutations must identify the school revision on which they are based. Check
|
||||
that revision and commit the change and new revision atomically.
|
||||
- Reject stale mutations with a clear conflict message; do not silently overwrite
|
||||
newer changes. The user can reload current data and decide again.
|
||||
- Changes to different components of the same school may therefore conflict.
|
||||
Finer-grained conflict detection is outside S16.
|
||||
- Retain the scheduling input revision check: a result computed from an outdated
|
||||
input revision must not replace current planning state.
|
||||
- After restart, calculations interrupted by the restart must be recognizably
|
||||
interrupted, rather than remain indefinitely marked as running. They do not
|
||||
resume automatically. Previously saved results remain available.
|
||||
|
||||
## Persistent scheduling status (transferred from S12)
|
||||
|
||||
The maintainer explicitly moved durable scheduling status and backend-restart
|
||||
recovery from S12 to S16 when completing S12. S12 supplies background execution,
|
||||
status snapshots, SSE and notifications within the lifetime of the backend.
|
||||
|
||||
- Persist the latest calculation per show in PostgreSQL, including its run
|
||||
identifier, school/show identity, start and finish timestamps, state, latest
|
||||
phase, whether a valid solution was found, outcome explanation and final
|
||||
attendance/spread/variety summary when available. A run history is not required.
|
||||
- Persist acceptance of a run before acknowledging its start. After restart or
|
||||
crash, an accepted calculation must remain identifiable even if it never
|
||||
produced a result.
|
||||
- Commit successful assignment replacement and its completed run status
|
||||
atomically. Publish success through the status API and SSE only after the
|
||||
transaction commits. A failed commit must not leave a successful status with
|
||||
missing assignments, or replaced assignments with an outdated running status.
|
||||
- On startup, mark calculations left Running by the previous backend instance
|
||||
as Interrupted before serving their recovered status. Explain that no new
|
||||
result was applied, retain previously saved assignments and allow a new run.
|
||||
Do not resume calculations automatically or retain their old run-slot guards.
|
||||
- Recover the latest status and outcome through S12's existing status endpoint
|
||||
and initial/reconnection SSE snapshots. Preserve stable run identifiers so
|
||||
reconnecting clients can deduplicate notifications; reopening the application
|
||||
must not replay old completion snackbars.
|
||||
- Verify recovery after both graceful restart and abrupt process termination,
|
||||
including a calculation running at termination and a completed saved result.
|
||||
|
||||
## Database failures and schema changes
|
||||
|
||||
- Refuse mutations while the database is unavailable and provide a clear failure
|
||||
message. Do not acknowledge successful storage or fall back to volatile writes.
|
||||
- Connection and Flyway migration failures at startup must be clearly visible;
|
||||
the application must not present itself as ready for normal use when required
|
||||
database initialization has failed.
|
||||
- Maintain the database schema through versioned Flyway migrations.
|
||||
|
||||
## Transition from in-memory storage
|
||||
|
||||
Start with an empty database. Existing data is transferred through the current
|
||||
JSON export/import path; no separate in-memory migration mechanism is required.
|
||||
Document that existing data must be exported before stopping the old application
|
||||
for the transition, because its current state exists only in memory.
|
||||
|
||||
## Deferred work
|
||||
|
||||
Database backup and restore are outside S16 and will be specified separately in
|
||||
`specs/S17_database-backup-and-restore`. That specification is intentionally empty
|
||||
for now. S16 does not promise recovery after loss of the database or its volume.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] PostgreSQL stores the complete maintained domain state and saved scheduling
|
||||
results, with Flyway managing the relational schema.
|
||||
- [x] Confirmed changes remain available after both a normal restart and an
|
||||
application crash, using the same persistent database.
|
||||
- [x] Failed related mutations and failed school replacement imports leave no
|
||||
partial changes or dangling references.
|
||||
- [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.
|
||||
- [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.
|
||||
- [x] Successful assignment replacement and completed run status commit
|
||||
atomically; success is published only after durable commit.
|
||||
- [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.
|
||||
- [x] Database unavailability prevents successful mutation acknowledgements;
|
||||
startup connection and migration failures are clearly reported.
|
||||
- [x] An empty database can be initialized through Flyway and populated through
|
||||
existing JSON import, preserving import/export behavior and identities.
|
||||
- [x] Setup and transition instructions cover the database service, persistent
|
||||
storage, connection configuration, migrations and export-before-transition.
|
||||
|
||||
## Implementation handoff
|
||||
|
||||
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