Skip to content

Seed default availability, and stop reused Dev Services containers breaking the suite - #145

Merged
asm0dey merged 9 commits into
mainfrom
fix/high-priority-issues
Aug 21, 2026
Merged

Seed default availability, and stop reused Dev Services containers breaking the suite#145
asm0dey merged 9 commits into
mainfrom
fix/high-priority-issues

Conversation

@asm0dey

@asm0dey asm0dey commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Clears the three open high-priority beans: calit-szew, calit-sjwh, calit-wvtl.

New users started with no availability at all (calit-sjwh)

DefaultAvailabilitySeeder was dead code — a no-op @Observes StartupEvent and a weekdayDefaults() 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. MeOwnerFilter bounces anyone with settingsComplete == false to /me/setup, and MeSetupResource#submit is the only writer of settingsComplete = 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 with seedGlobalDefaults(ownerId), which stamps owner_id and 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 (saveWeeklyRules is replace-all), and /me/setup stays POST-able afterwards; guarding on the row count would have re-seeded them against their wishes.

V28__seed_default_availability.sql backfills accounts that onboarded before this change and so would never re-enter the wizard. Same hours, same skip-if-any-global-rule guard, plus u.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=true matches a parked Postgres by a Testcontainers 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 FlywayValidateException: Detected applied migration not resolved locally.

Reuse stays on; quarkus.flyway.clean-at-start=true in %test drops 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 bogus V99 row into the live reused container's flyway_schema_history, re-running, and confirming the row was gone afterwards.

The properties are in src/test/resources/, so they cannot reach production: the packaged target/quarkus-app carries only quarkus.flyway.migrate-at-start=true, and the Dockerfile copies nothing else.

Sonar NPE gate (calit-wvtl)

Already fixed in merged PR #142WriteTargetResolver.writeOverride guards its null owner. Bookkeeping only here.

Testing

898 tests, 0 failures, 0 errors. spotless:check clean. DefaultAvailabilityBackfillTest runs 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-a4yjSignupResource creates a user with no owner_settings row, unlike the other four creation paths.
  • calit-h8mbPublicResource serves and accepts bookings on a disabled owner's page. Predates this branch; V28 is only what made us look.

Upgrade note

V28 runs 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-site follows in a separate PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QF9JXW4V2AFDBicwBfV5zH

asm0dey and others added 9 commits August 21, 2026 23:47
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
@sonarqubecloud

Copy link
Copy Markdown

@asm0dey
asm0dey merged commit 655c370 into main Aug 21, 2026
11 checks passed
@asm0dey
asm0dey deleted the fix/high-priority-issues branch August 21, 2026 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant