Implements EnvironmentService with full CRUD, duplicate slug rejection,
tier-based environment count limits, and audit logging for create/update/delete.
Adds ENVIRONMENT_CREATE, ENVIRONMENT_UPDATE, ENVIRONMENT_DELETE to AuditAction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add docker-java and ClickHouse JDBC dependencies, RuntimeConfig and
ClickHouseConfig Spring components, AsyncConfig with deployment thread
pool, and runtime/clickhouse config sections in application.yml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
16-task plan covering environments, apps, deployments, Docker
runtime orchestrator, ClickHouse log ingestion, and CI updates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Build container has no Docker-in-Docker, so TestContainers can't
create PostgreSQL containers. Exclude integration tests in CI;
they run locally with Docker Desktop. Matches cameleer3-server
pattern of separating unit and integration tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use cameleer-build:1 (Maven 3.9 + Temurin 21) container instead of
setup-java. Use cameleer-docker-builder:1 for Docker image builds
with registry push. Aligns with cameleer3-server CI pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Docker Desktop 4.54 (Engine 29.1.2) raised minimum API from 1.24 to
1.44. TestContainers 1.20.5 defaults to 1.32 which gets rejected.
TC 1.21.4 handles API version negotiation natively.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auth is now handled by Logto. Removed AuthController, AuthService,
and related DTOs. Integration tests use Spring Security JWT mocks.
Ed25519 JwtService retained for machine token signing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates Logto organizations when tenants are created. Authenticates
via M2M client credentials. Gracefully skips when Logto is not
configured (dev/test mode).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /auth/verify validates JWT and returns X-User-Id, X-User-Email
headers for downstream service routing via Traefik middleware.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TenantResolutionFilter extracts organization_id from Logto JWT and
resolves to local tenant via TenantService. ThreadLocal TenantContext
available throughout request lifecycle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dual auth: machine endpoints use Ed25519 JWT filter, all other API
endpoints use Spring Security OAuth2 Resource Server with Logto OIDC.
Mock JwtDecoder provided for test isolation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POST /api/tenants/{id}/license generates Ed25519-signed license JWT.
GET /api/tenants/{id}/license returns active license.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Generates tier-aware license tokens with features/limits per tier.
Verifies signature and expiry. Audit logged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Licenses table linked to tenants with JSONB features/limits, Ed25519
signed token storage, and revocation support.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keys are loaded from PEM files when CAMELEER_JWT_PRIVATE_KEY_PATH and
CAMELEER_JWT_PUBLIC_KEY_PATH are set. Falls back to ephemeral key
generation for development.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Architecture spec covers Docker+K8s dual deployment with build-vs-buy
decisions (Logto, Traefik, Stripe, deferred Lago/Vault). Phase 2 plan
has 12 implementation tasks for tenants, identity, and licensing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set up the foundational Spring Boot project structure:
- Root POM with web, security, JPA, Flyway, validation, AOP, actuator
- PostgreSQL + Testcontainers for test infrastructure
- Application YAML configs for default, dev, and test profiles
- Maven wrapper (3.9.9) for reproducible builds
- .gitignore for Maven/IDE/OS artifacts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>