Commit Graph

138 Commits

Author SHA1 Message Date
hsiegeln
45b60a0aee feat: add cameleer3-server-ui container to Docker Compose
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 38s
The cameleer3-server deploys backend and UI as separate containers.
Add the cameleer3-server-ui image (nginx SPA + API reverse proxy)
to the Compose stack, exposed on port 8082 in dev. Update sidebar
"View Dashboard" link to point to the UI container.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:23:48 +02:00
hsiegeln
9b77f810c1 fix: use correct health endpoint and HTTP method for server integration
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 31s
ConnectivityHealthCheck: /actuator/health → /api/v1/health (actuator
now requires auth on cameleer3-server after OIDC was added).

Bootstrap: POST → PUT for /api/v1/admin/oidc (server expects PUT,
POST returned 405 causing OIDC config to silently fail).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:59:24 +02:00
hsiegeln
1ef8c9dceb refactor: merge tenant isolation into single HandlerInterceptor
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 37s
Replace TenantResolutionFilter + TenantOwnershipValidator (15 manual
calls across 5 controllers) with a single TenantIsolationInterceptor
that uses Spring HandlerMapping path variables for fail-closed tenant
isolation. New endpoints with {tenantId}, {environmentId}, or {appId}
path variables are automatically isolated without manual code.

Simplify OrgResolver from dual-token fetch to single token — Logto
merges all scopes into either token type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:48:04 +02:00
hsiegeln
051f7fdae9 feat: auth hardening — scope enforcement, tenant isolation, and docs
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 39s
Add @PreAuthorize annotations to all API controllers (14 endpoints
across 6 controllers) enforcing OAuth2 scopes: apps:manage, apps:deploy,
billing:manage, observe:read, platform:admin.

Enforce tenant isolation: TenantResolutionFilter now rejects cross-tenant
access on /api/tenants/{id}/* paths. New TenantOwnershipValidator checks
environment/app ownership for paths without tenantId. Platform admins
bypass both layers.

Fix frontend: OrgResolver split into two useEffect hooks so scopes
refresh on org switch. Scopes now served from /api/config (single source
of truth). Bootstrap cleaned — standalone org permissions removed.

Update docs/architecture.md, docs/user-manual.md, and CLAUDE.md to
reflect all auth hardening changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:32:53 +02:00
hsiegeln
b459a69083 docs: add architecture document
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 7s
Comprehensive technical reference covering system topology, auth model
(Logto OIDC, scopes, token types, Spring Security pipeline), data model
(7 tables from Flyway migrations), deployment flow, agent-server protocol,
API endpoints, security boundaries, frontend architecture, and full
configuration reference. All class names, paths, and properties verified
against the codebase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:19:05 +02:00
hsiegeln
c5596d8ea4 docs: add user manual
Task-oriented guide for SaaS customers and self-hosted operators
covering login, environments, applications, deployments, observability,
licenses, platform admin, roles, self-hosted setup, and troubleshooting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:15:40 +02:00
hsiegeln
e3baaeee84 fix: replace stale permission prop with scope in EnvironmentDetailPage
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 38s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:13:37 +02:00
hsiegeln
298f6e3e71 feat: scope-based authorization — read standard scope claim, remove custom roles extraction
Some checks failed
CI / build (push) Failing after 18s
CI / docker (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:04:16 +02:00
hsiegeln
9c2a1d27b7 feat: replace hardcoded permission map with direct OAuth2 scope checks
Remove role-to-permission mapping (usePermissions, RequirePermission) and replace
with direct scope reads from the Logto access token JWT. OrgResolver decodes the
scope claim after /api/me resolves and stores scopes in Zustand. RequireScope and
useScopes replace the old hooks/components across all pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:04:06 +02:00
hsiegeln
277d5ea638 feat: define OAuth2 scopes on API resource and assign to Logto roles
Creates 10 API resource scopes (platform:admin + 9 tenant-level) on the
Cameleer SaaS API resource, assigns all to platform-admin role, creates
matching organization scopes, and wires them declaratively to org roles
(admin gets all, member gets deploy/observe). All operations are idempotent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:01:43 +02:00
hsiegeln
6ccf7f3fcb fix: ProtectedRoute spinner fix, TokenSync cleanup, dev hot-reload
All checks were successful
CI / build (push) Successful in 37s
CI / docker (push) Successful in 38s
- ProtectedRoute: only gate on initial auth load, not every async op
- TokenSync: OrgResolver is sole source of org data, remove fetchUserInfo
- docker-compose.dev: mount ui/dist for hot-reload

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 13:11:44 +02:00
hsiegeln
cfa989bd5e fix: allow JwtDecoder bean override in test context
- Add @Primary + @ConditionalOnMissingBean so TestSecurityConfig.jwtDecoder()
  wins over SecurityConfig.jwtDecoder() without needing a real OIDC endpoint
- Add spring.main.allow-bean-definition-overriding=true and
  cameleer.clickhouse.enabled=false to src/test/resources/application-test.yml
  so Testcontainers @ServiceConnection can supply the datasource
- Disable ClickHouse in test profile (src/main/resources/application-test.yml)
  so the explicit ClickHouseConfig DataSource bean is not created, allowing
  @ServiceConnection to wire the Testcontainers Postgres datasource
- Fix TenantControllerTest and LicenseControllerTest to explicitly grant
  ROLE_platform-admin authority via .authorities() on the test JWT, since
  spring-security-test does not run the custom JwtAuthenticationConverter
- Fix EnvironmentService.createDefaultForTenant() to use an internal
  bootstrap path that skips license enforcement (chicken-and-egg: no license
  exists at tenant creation time yet)
- Remove now-unnecessary license stub from EnvironmentServiceTest

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:06:31 +02:00
hsiegeln
4da9cf23cb infra: add OIDC config to bootstrap output, stop reading Logto DB for secrets
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:44:27 +02:00
hsiegeln
9e6440d97c infra: remove ForwardAuth, keys mount, add OIDC env vars for server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:44:04 +02:00
hsiegeln
5326102443 feat: remove bootstrap_token from EnvironmentEntity — API keys managed separately
Remove bootstrapToken field/getter/setter from EnvironmentEntity and drop
the RuntimeConfig dependency from EnvironmentService. DeploymentService and
AgentStatusService now use a TODO-api-key placeholder until the ApiKeyService
wiring is complete. All test references to setBootstrapToken removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:42:47 +02:00
hsiegeln
ec1ec2e65f feat: rewrite frontend auth — roles from org store, Logto org role names
Replace ID-token claim reads with org store lookups in useAuth and
usePermissions; add currentOrgRoles to useOrgStore; update role names
to Logto org role conventions (admin/member); remove username from
Layout (no longer derived from token claims).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:42:26 +02:00
hsiegeln
5f43394b00 refactor: remove getUserRoles from LogtoManagementClient — roles come from JWT 2026-04-05 12:40:58 +02:00
hsiegeln
bd2a6a601b test: update TestSecurityConfig with org and role claims for Logto tokens 2026-04-05 12:40:49 +02:00
hsiegeln
4b5a1cf2a2 feat: add API key entity, repository, and service with SHA-256 hashing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:39:50 +02:00
hsiegeln
b8b0c686e8 feat: replace manual Logto role check with @PreAuthorize in TenantController
Remove LogtoManagementClient dependency from TenantController; gate
listAll and create with @PreAuthorize("hasRole('platform-admin')"),
relying on the JWT roles claim already mapped by JwtAuthenticationConverter.
Update TenantControllerTest to supply the platform-admin role via jwt()
on all POST requests that expect 201/409.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:39:40 +02:00
hsiegeln
d4408634a6 feat: rewrite MeController — read from JWT claims, Management API only for cold start
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:38:39 +02:00
hsiegeln
48a5035a2c fix: remove Ed25519 license signing — replace with UUID token placeholder
Drop JwtConfig dependency from LicenseService; generate license tokens as
random UUIDs instead. Add findByToken to LicenseRepository and update
verifyLicenseToken to do a DB lookup. Update LicenseServiceTest to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:37:32 +02:00
hsiegeln
396c00749e feat: rewrite SecurityConfig — single filter chain, Logto OAuth2 Resource Server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 12:35:45 +02:00
hsiegeln
f89be09e04 chore: greenfield migrations — remove user/role tables, add api_keys, drop bootstrap_token
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:33:52 +02:00
hsiegeln
3929bbb95e chore: delete dead auth code — users/roles/JWTs/ForwardAuth live in Logto now
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:32:18 +02:00
hsiegeln
1397267be5 docs: add auth overhaul implementation plan
16 tasks across 3 phases: server OIDC support, SaaS auth rewrite,
infrastructure updates. TDD, complete code, greenfield migrations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 12:26:47 +02:00
hsiegeln
c61c59a441 docs: update auth spec for greenfield approach
Remove migration/backward-compat hedging. Delete legacy user/role/permission
tables entirely, remove bootstrap_token column in favor of api_keys table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 12:19:09 +02:00
hsiegeln
fc4c1f94cd docs: add auth overhaul design spec
Comprehensive design for replacing the incoherent three-system auth
with Logto-centric architecture: OAuth2 Resource Server for humans,
API keys for agents, zero trust (no header identity), server-per-tenant.
Covers cameleer-saas (large), cameleer3-server (small), agent (none).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 12:13:19 +02:00
hsiegeln
1b42bd585d fix: re-resolve tenantId when org list is enriched by OrgResolver
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 37s
TokenSync sets currentOrgId from fetchUserInfo (no tenantId).
OrgResolver later calls setOrganizations with enriched data including
tenantId. Now setOrganizations auto-resolves currentTenantId when
the org is already selected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:29:03 +02:00
hsiegeln
51c73d64a4 fix: read M2M credentials from bootstrap JSON when env vars empty
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 31s
The bootstrap dynamically creates the M2M app and writes credentials
to the JSON file. LogtoConfig now falls back to the bootstrap file
when LOGTO_M2M_CLIENT_ID/SECRET env vars are not set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:23:02 +02:00
hsiegeln
34aadd1e25 fix: accept Logto at+jwt token type in Spring Security
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 30s
Logto issues access tokens with typ "at+jwt" (RFC 9068) but Spring
Security's default NimbusJwtDecoder only allows "JWT". Custom decoder
accepts any type. Also removed hard 401 redirect from API client.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:17:25 +02:00
hsiegeln
1abf0f827b fix: remove 401 hard redirect, let React Query retry
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 41s
The /api/me call races with TokenSync — fires before the token
provider is set. Removed the hard window.location redirect on 401
from the API client. React Query retries with backoff instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 03:02:32 +02:00
hsiegeln
00ee8876c1 fix: move DB seeding from bootstrap script to Java ApplicationRunner
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 33s
SonarQube Analysis / sonarqube (push) Successful in 1m21s
The bootstrap script runs before cameleer-saas (Flyway), so tenant
tables don't exist yet. Moved DB seeding to BootstrapDataSeeder
ApplicationRunner which runs after Flyway migrations complete.
Reads bootstrap JSON and creates tenant/environment/license if missing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 02:55:43 +02:00
hsiegeln
827e388349 feat: bootstrap 2 users, tenant, org-scoped tokens, platform admin UI
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 39s
Bootstrap script now creates:
- SaaS Owner (admin/admin) with platform-admin role
- Tenant Admin (camel/camel) in Example Tenant org
- Traditional Web App for cameleer3-server OIDC
- DB records: tenant, default environment, license
- Configures cameleer3-server OIDC via its admin API
All credentials configurable via env vars.

Backend:
- Fix LogtoManagementClient resource URL (https://default.logto.app/api)
- Add getUserRoles/getUserOrganizations to LogtoManagementClient
- Add GET /api/me endpoint (user info, platform admin status, tenants)
- Add GET /api/tenants list-all for platform admins
- Remove insecure X-header forwarding from Traefik

Frontend:
- Org-scoped tokens: getAccessToken(resource, orgId) for tenant context
- OrgResolver component populates org store from /api/me
- useOrganization Zustand store (currentOrgId + currentTenantId)
- Platform admin sidebar section + AdminTenantsPage
- View Dashboard link points to cameleer3-server on port 8081

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 02:50:51 +02:00
hsiegeln
b83cfdcd49 fix: add all design-system providers (GlobalFilter + CommandPalette)
All checks were successful
CI / build (push) Successful in 41s
CI / docker (push) Successful in 38s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:30:18 +02:00
hsiegeln
a7dd026225 fix: add GlobalFilterProvider required by design-system DataTable
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 41s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:23:36 +02:00
hsiegeln
0843a33383 refactor: replace hand-rolled OIDC with @logto/react SDK
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 48s
The hand-rolled OIDC flow (manual PKCE, token exchange, URL
construction) was fragile and accumulated multiple bugs. Replaced
with the official @logto/react SDK which handles PKCE, token
exchange, storage, and refresh automatically.

- Add @logto/react SDK dependency
- Add LogtoProvider with runtime config in main.tsx
- Add TokenSync component bridging SDK tokens to API client
- Add useAuth hook replacing Zustand auth store
- Simplify LoginPage to signIn(), CallbackPage to useHandleSignInCallback()
- Delete pkce.ts and auth-store.ts (replaced by SDK)
- Fix react-router-dom → react-router imports in page files
- All 17 React Query hooks unchanged (token provider pattern)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:17:47 +02:00
hsiegeln
84667170f1 fix: register API resource in Logto for JWT access tokens
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 39s
Logto returns opaque access tokens when no resource is specified.
Added API resource creation to bootstrap, included resource indicator
in /api/config, and SPA now passes resource parameter in auth request.
Also fixed issuer-uri to match Logto's public endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:01:32 +02:00
hsiegeln
6764f981d2 fix: add PKCE support for Logto auth and fix Traefik routing
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 39s
Logto requires PKCE (Proof Key for Code Exchange) for SPA auth.
Added code_challenge/code_verifier to login and callback flow.

Also fixed Traefik router-service linking — when a container defines
multiple routers, each needs an explicit service binding or Traefik
v3 refuses to auto-link them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:48:21 +02:00
hsiegeln
537c2bbaf2 fix: use LOGTO_PUBLIC_ENDPOINT for Logto ENDPOINT config
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 6s
Logto's ENDPOINT must be the browser-accessible URL (not Docker
internal). When .env sets LOGTO_ENDPOINT=http://logto:3001, it was
overriding the default and causing Logto to redirect browsers to
an unreachable hostname.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:44:24 +02:00
hsiegeln
beb3442c07 fix: return browser-accessible Logto URL from /api/config
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 31s
Separate LOGTO_PUBLIC_ENDPOINT (browser-facing, defaults to
http://localhost:3001) from LOGTO_ENDPOINT (Docker-internal).
Also fix bootstrap M2M verification by using correct Host header
for default tenant token endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:33:43 +02:00
hsiegeln
a20d36df38 fix: bootstrap script use curl with Host header for Logto tenant routing
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 6s
Logto routes requests by Host header to determine tenant. Inside Docker,
requests to logto:3001/3002 need Host: localhost:3001/3002 to match the
configured ENDPOINT/ADMIN_ENDPOINT.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:28:23 +02:00
hsiegeln
021b056bce feat: zero-config first-run experience with Logto bootstrap
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 37s
- logto-bootstrap.sh: API-driven init script that creates SPA app,
  M2M app, and default user (camel/camel) via Logto Management API.
  Reads m-default secret from DB, then removes seeded apps with
  known secrets (security hardening). Idempotent.
- PublicConfigController: /api/config public endpoint serves Logto
  client ID from bootstrap output file (runtime, not build-time)
- Frontend: LoginPage + CallbackPage fetch config from /api/config
  instead of import.meta.env (fixes Vite build-time baking issue)
- Docker Compose: logto-bootstrap init service with health-gated
  dependency chain, shared volume for bootstrap config
- SecurityConfig: permit /api/config without auth

Flow: docker compose up → bootstrap creates apps/user → SPA fetches
config → login page shows → sign in with Logto → camel/camel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:22:22 +02:00
hsiegeln
cda7dfbaa7 fix: permit SPA routes and static assets in Spring Security
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 32s
The SPA (index.html, /login, /callback, /assets/*) must be accessible
without authentication. API routes remain protected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:49:43 +02:00
hsiegeln
ad6805e447 fix: use standard dist/ output for Vite, copy to static/ explicitly
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 37s
The relative outDir '../src/main/resources/static' resolved
unpredictably in Docker. Use standard 'dist/' output, then:
- Dockerfile: COPY --from=frontend /ui/dist/ to static/
- CI: cp -r dist/ to src/main/resources/static/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:44:50 +02:00
hsiegeln
e5e14fbe32 fix: add CAMELEER_JWT_SECRET for cameleer3-server
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 7s
The server needs this to derive its Ed25519 signing key. Without it,
startup fails with 'Empty key'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:42:37 +02:00
hsiegeln
e10f80c298 fix: allow ClickHouse connections from Docker network
All checks were successful
CI / build (push) Successful in 39s
CI / docker (push) Successful in 6s
The default ClickHouse image restricts the 'default' user to localhost
only. Override with clickhouse-users.xml to allow connections from any
IP (needed for inter-container communication on the Docker network).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:41:14 +02:00
hsiegeln
16acd145a3 fix: pg_isready healthcheck must specify database name
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 5s
Without -d, pg_isready connects to database matching the username
('cameleer'), which doesn't exist. Specify $POSTGRES_DB explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:38:02 +02:00
hsiegeln
d0fd2c49be fix: Docker Compose database initialization
Some checks failed
CI / build (push) Successful in 38s
CI / docker (push) Has been cancelled
- init-databases.sh: create cameleer3 DB for cameleer3-server, connect
  to $POSTGRES_DB explicitly (avoids 'database cameleer does not exist')
- clickhouse-init.sql: auto-create cameleer database on first start
- docker-compose.yml: fix cameleer3-server datasource to cameleer3 DB,
  add ClickHouse init script volume mount, pass credentials

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:37:19 +02:00
hsiegeln
567d92ca34 fix: let Flyway inherit datasource connection instead of separate URL
All checks were successful
CI / build (push) Successful in 38s
CI / docker (push) Successful in 31s
Explicit spring.flyway.url/user/password used SPRING_DATASOURCE_URL env
var but Flyway resolves its own defaults independently, falling back to
localhost when the env var mapping doesn't match. Removing the explicit
Flyway connection config lets it inherit from the datasource, which is
correctly configured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:20:04 +02:00