feat: add container config to apps and default config to environments

- V5 migration: container_config JSONB + updated_at on apps,
  default_container_config JSONB on environments
- App/Environment records updated with new fields
- PUT /apps/{id}/container-config endpoint for per-app config
- PUT /admin/environments/{id}/default-container-config for env defaults
- GET /apps now supports optional environmentId (lists all when omitted)
- AppRepository.findAll() for cross-environment app listing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-08 16:18:08 +02:00
parent e04dca55aa
commit 875062e59a
12 changed files with 133 additions and 16 deletions

View File

@@ -1,6 +1,8 @@
package com.cameleer3.server.core.runtime;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
public record App(UUID id, UUID environmentId, String slug, String displayName, Instant createdAt) {}
public record App(UUID id, UUID environmentId, String slug, String displayName,
Map<String, Object> containerConfig, Instant createdAt, Instant updatedAt) {}

View File

@@ -1,13 +1,16 @@
package com.cameleer3.server.core.runtime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public interface AppRepository {
List<App> findByEnvironmentId(UUID environmentId);
List<App> findAll();
Optional<App> findById(UUID id);
Optional<App> findByEnvironmentIdAndSlug(UUID environmentId, String slug);
UUID create(UUID environmentId, String slug, String displayName);
void updateContainerConfig(UUID id, Map<String, Object> containerConfig);
void delete(UUID id);
}

View File

@@ -10,6 +10,7 @@ import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class AppService {
@@ -25,10 +26,16 @@ public class AppService {
this.jarStoragePath = jarStoragePath;
}
public List<App> listAll() { return appRepo.findAll(); }
public List<App> listByEnvironment(UUID environmentId) { return appRepo.findByEnvironmentId(environmentId); }
public App getById(UUID id) { return appRepo.findById(id).orElseThrow(() -> new IllegalArgumentException("App not found: " + id)); }
public List<AppVersion> listVersions(UUID appId) { return versionRepo.findByAppId(appId); }
public void updateContainerConfig(UUID id, Map<String, Object> containerConfig) {
getById(id); // verify exists
appRepo.updateContainerConfig(id, containerConfig);
}
public UUID createApp(UUID environmentId, String slug, String displayName) {
if (appRepo.findByEnvironmentIdAndSlug(environmentId, slug).isPresent()) {
throw new IllegalArgumentException("App with slug '" + slug + "' already exists in this environment");

View File

@@ -1,6 +1,7 @@
package com.cameleer3.server.core.runtime;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
public record Environment(
@@ -9,5 +10,6 @@ public record Environment(
String displayName,
boolean production,
boolean enabled,
Map<String, Object> defaultContainerConfig,
Instant createdAt
) {}

View File

@@ -1,6 +1,7 @@
package com.cameleer3.server.core.runtime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@@ -10,5 +11,6 @@ public interface EnvironmentRepository {
Optional<Environment> findBySlug(String slug);
UUID create(String slug, String displayName, boolean production);
void update(UUID id, String displayName, boolean production, boolean enabled);
void updateDefaultContainerConfig(UUID id, Map<String, Object> defaultContainerConfig);
void delete(UUID id);
}

View File

@@ -1,6 +1,7 @@
package com.cameleer3.server.core.runtime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class EnvironmentService {
@@ -32,6 +33,11 @@ public class EnvironmentService {
repo.update(id, displayName, production, enabled);
}
public void updateDefaultContainerConfig(UUID id, Map<String, Object> defaultContainerConfig) {
getById(id); // verify exists
repo.updateDefaultContainerConfig(id, defaultContainerConfig);
}
public void delete(UUID id) {
Environment env = getById(id);
if ("default".equals(env.slug())) {