Seed default availability, and stop reused Dev Services containers breaking the suite - #145
Merged
Conversation
Covers calit-szew (Dev Services container drift), calit-sjwh (new users get no default availability) and calit-wvtl (already fixed in merged PR #142). Also files calit-a4yj for the SignupResource owner_settings gap found while planning. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
…n't drift A parked Testcontainers Postgres is matched by a hash that knows nothing about the branch or worktree that last used it, so a container carrying V27 made a V26 branch die at boot with 'Detected applied migration not resolved locally'. Clean-at-start in %test drops and re-migrates the schema each boot: the container is reused, its schema never is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
DefaultAvailabilitySeeder was dead code — a no-op startup observer and a weekdayDefaults() with no production caller — so every new user started with zero global availability rules: their meeting types offered no slots and the working-hours grid rendered empty under help text promising defaults. The first-login wizard is the one place every user must pass through, so it seeds Mon-Fri 09:00-18:00 globals stamped with the owner id. Seeding no-ops when the owner already has a global rule, so a repeated submit can't double them. The seeder loses its CDI wiring and becomes a static helper. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
Wizard seeding landed in e407d69; the bean stays open until the backfill for already-onboarded accounts lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
The wizard now seeds Mon-Fri 09:00-18:00, but settingsComplete is written once and never again, so an account that onboarded before that change would keep its zero global rules forever. V28 gives default hours to every owner that has none, skipping any owner who already set global hours, so nothing hand-configured is overwritten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
…beans calit-sjwh: wizard seeding (e407d69) plus the V28 backfill (de5f9fe) close it. calit-wvtl: PR #142 merged with the null guard, so the Sonar gate cleared. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
… first onboarding V28 gave Mon-Fri bookable hours to every owner without them, including accounts an admin had disabled -- whose public booking page is still served and still bookable, so the migration would have invited real bookings for someone who has left. It now skips disabled owners, which also matches the Java path: a disabled user cannot log in, so the wizard could never seed one. The wizard's seed guard was "this owner has no global rules", which an owner can also reach deliberately by clearing their weekly grid; re-posting the wizard then re-seeded them. It now guards on !settingsComplete -- the actual "first completion" condition -- with the row-count check kept inside the seeder as belt-and-braces. Also: pin the NOT EXISTS correlation and the null-owner guard in tests, and correct the clean-disabled comment (false is already the Quarkus 3.38 default, so the line is a pin, not a requirement). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
Surfaced by the final review of this branch: V28 would have handed bookable hours to disabled accounts, which is only dangerous because PublicResource serves and accepts bookings on a disabled owner's page at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH
|
This was referenced Aug 21, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Clears the three open high-priority beans:
calit-szew,calit-sjwh,calit-wvtl.New users started with no availability at all (
calit-sjwh)DefaultAvailabilitySeederwas dead code — a no-op@Observes StartupEventand aweekdayDefaults()with no production caller. Every new user therefore began with zero global availability rules: their meeting types offered no bookable slots, and the working-hours grid rendered empty under help text promising "your global default hours".Seeding now happens in the first-login wizard.
MeOwnerFilterbounces anyone withsettingsComplete == falseto/me/setup, andMeSetupResource#submitis the only writer ofsettingsComplete = true, so one call there covers all five creation paths —/setup,/signup, admin invite, Google sign-in, OIDC sign-in — without touching any of them. The seeder loses its CDI wiring and becomes a static helper withseedGlobalDefaults(ownerId), which stampsowner_idand no-ops when the owner already has any global rule.The seed is guarded on
!settingsComplete— the owner's first completion — not on "has no rules". An owner can legitimately hold zero global rules by clearing their weekly grid (saveWeeklyRulesis replace-all), and/me/setupstays POST-able afterwards; guarding on the row count would have re-seeded them against their wishes.V28__seed_default_availability.sqlbackfills accounts that onboarded before this change and so would never re-enter the wizard. Same hours, same skip-if-any-global-rule guard, plusu.enabled— a disabled account's public booking page is still served and still bookable, so seeding one would have invited real bookings for someone an admin switched off. That also matches the Java path, which can never run for a disabled user.Reused Dev Services container broke the suite across worktrees (
calit-szew)quarkus.datasource.devservices.reuse=truematches a parked Postgres by a Testcontainers hash that knows nothing about the branch or worktree that last used it, so a container carryingV27made aV26branch die at boot withFlywayValidateException: Detected applied migration not resolved locally.Reuse stays on;
quarkus.flyway.clean-at-start=truein%testdrops and re-migrates the schema on every boot. The container is reused, its schema never is — which also covers branch-switching inside a single worktree, where per-worktree label scoping would not have helped. Verified by stamping a bogusV99row into the live reused container'sflyway_schema_history, re-running, and confirming the row was gone afterwards.The properties are in
src/test/resources/, so they cannot reach production: the packagedtarget/quarkus-appcarries onlyquarkus.flyway.migrate-at-start=true, and the Dockerfile copies nothing else.Sonar NPE gate (
calit-wvtl)Already fixed in merged PR #142 —
WriteTargetResolver.writeOverrideguards its null owner. Bookkeeping only here.Testing
898 tests, 0 failures, 0 errors.
spotless:checkclean.DefaultAvailabilityBackfillTestruns the migration's own SQL text read from the classpath rather than a retyped copy, so the migration and its test cannot drift apart.Follow-ups filed
calit-a4yj—SignupResourcecreates a user with noowner_settingsrow, unlike the other four creation paths.calit-h8mb—PublicResourceserves and accepts bookings on a disabled owner's page. Predates this branch;V28is only what made us look.Upgrade note
V28runs at boot and gives Monday–Friday 09:00–18:00 global hours to any enabled account that has none. Accounts with hours already set are untouched. An owner who deliberately kept zero global hours will find meeting types with no per-type hours bookable again on those defaults. No configuration changes.Changelog entry for
docs-sitefollows in a separate PR.🤖 Generated with Claude Code
https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH