Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ This MVP does not use a database, Liquibase, authentication, authorization, Dock
## Current Project State

- The backend exposes `GET /api/feature-model`,
`POST /api/feature-model/validate`, and
`GET /api/feature-model/guided-workflow`.
`POST /api/feature-model/validate`, `GET /api/feature-model/guided-workflow`,
local snapshot endpoints under `/api/feature-model/snapshots`, deployment
profile endpoints (`GET /api/deployment-profiles`,
`GET /api/deployment-profiles/{id}`), and profile-aware availability
(`GET /api/feature-model/profile-availability`).
- The Explorer route is read-only and supports tree/list inspection,
filtering, expansion controls, and feature details.
- The Configurator route is a guided workflow. It supports use-case templates,
Expand All @@ -33,6 +36,11 @@ This MVP does not use a database, Liquibase, authentication, authorization, Dock
- The regular guided workflow should use user-facing outcome, recommendation,
availability, and things-to-know text. Keep technical capability ids and
artifact mappings in the advanced tree view.
- Deployment Profiles are JSON files; one bundled `default-artemis-profile`
provides all capabilities and drives feature/option availability. The regular
Configurator does not expose a profile selector; capability gating is a latent
safety net for maintainer local overrides. Keep raw capability ids and
missing-capability details in advanced tree/debug views.
- Custom configuration starts from backend-derived `defaultSelectedFeatureIds`;
default-on guided options should be reflected as selected in the UI.
- The in-configurator tree reflects guided selections in real time and can
Expand Down Expand Up @@ -83,6 +91,8 @@ Server package areas:
- `validation` owns model and selection validation.
- `visualization` owns derived tree/read-model structures.
- `selection` owns user selection concepts and future selection sessions.
- `snapshot` owns local feature model snapshot listing, import, and export.
- `deployment` owns deployment profiles, profile loading, and capability resolution.
- `export` is reserved for later deployment/configuration artifact generation.
- `shared` is only for truly shared exceptions, constants, and small utilities.

Expand Down Expand Up @@ -253,16 +263,21 @@ This MVP scaffold currently uses Bootstrap-compatible SCSS. Use Bootstrap utilit

## API and Server Design Conventions

- Public MVP API routes live under `/api/feature-model`.
- Public MVP API routes live under `/api/feature-model` and `/api/deployment-profiles`.
- `GET /api/feature-model` returns the loaded model, derived tree, default selected feature ids, and warnings.
- `POST /api/feature-model/validate` validates a submitted selection.
- `GET /api/feature-model/guided-workflow` returns the guided workflow
metadata, templates, steps, decision options, and review groups.
- `GET /api/feature-model/snapshots...` lists, details, imports, and exports local snapshots.
- `GET /api/deployment-profiles` and `GET /api/deployment-profiles/{id}` return deployment profile summaries and detail.
- `GET /api/feature-model/profile-availability` returns profile-aware option and feature availability; an optional `profileId` is for tests/maintainers, not the regular UI.
- Bootstrap profiles live in `src/main/resources/deployment-profiles`; local overrides under `<data-root>/deployment-profiles`.
- Store abstraction belongs in `catalog.repository`.
- JSON-backed loading belongs in `catalog.repository`.
- API DTOs belong in the owning module's `dto` package.
- Tree DTOs belong in `visualization.dto`.
- Validation request and result DTOs belong in `validation.dto`.
- Deployment profile and availability DTOs belong in `deployment.dto`.
- Do not expose internal domain records directly from web resources if a REST DTO is more stable.

## Testing Guidelines
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package de.tum.cit.aet.artemis.featuremodel.deployment.domain;

import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/**
* A Deployment Profile represents maintainer-approved technical assumptions and infrastructure capabilities for a
* deployment context. Teachers configure functional features through the guided workflow while the active profile
* decides which technical capabilities are available and supplies the parameters later phases use for artifact
* generation.
*
* <p>
* Profiles are loaded from JSON files. Secret values are stored only as references or placeholders (for example
* {@code env:PYRIS_SECRET} or {@code vault:artemis/pyris/shared-secret}), never as plaintext secrets.
*
* @param id stable profile id, also the file base name.
* @param name human-readable profile name.
* @param version profile version.
* @param status lifecycle status, for example {@code published}.
* @param editableBy roles allowed to edit this profile.
* @param providedCapabilities technical capabilities this profile makes available.
* @param parameters non-secret parameters and secret references keyed by parameter name.
* @param unresolvedNotes optional notes about entries that could not be confidently resolved.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public record DeploymentProfile(String id, String name, String version, String status, List<String> editableBy, List<String> providedCapabilities,
Map<String, String> parameters, List<String> unresolvedNotes) {

/**
* Creates a deployment profile and normalizes nullable collections to immutable empty collections.
*
* @param id stable profile id.
* @param name human-readable profile name.
* @param version profile version.
* @param status lifecycle status.
* @param editableBy roles allowed to edit this profile.
* @param providedCapabilities technical capabilities this profile provides.
* @param parameters non-secret parameters and secret references.
* @param unresolvedNotes optional notes about unresolved entries.
*/
public DeploymentProfile {
editableBy = editableBy == null ? List.of() : List.copyOf(editableBy);
providedCapabilities = providedCapabilities == null ? List.of() : List.copyOf(providedCapabilities);
parameters = parameters == null ? Map.of() : Map.copyOf(parameters);
unresolvedNotes = unresolvedNotes == null ? List.of() : List.copyOf(unresolvedNotes);
}

/**
* Checks whether this profile provides a given technical capability.
*
* @param capability capability id to check.
* @return true if the capability is in this profile's provided capabilities.
*/
public boolean providesCapability(String capability) {
return providedCapabilities.contains(capability);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Domain types for the deployment profile module.
*/
package de.tum.cit.aet.artemis.featuremodel.deployment.domain;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package de.tum.cit.aet.artemis.featuremodel.deployment.dto;

import java.util.List;
import java.util.Map;

import de.tum.cit.aet.artemis.featuremodel.deployment.domain.DeploymentProfile;

/**
* Full detail of a deployment profile, including provided capabilities and parameters. Parameters expose only non-secret
* values and secret references, matching how they are stored in the profile JSON.
*
* @param id stable profile id.
* @param name human-readable profile name.
* @param version profile version.
* @param status lifecycle status.
* @param editableBy roles allowed to edit this profile.
* @param providedCapabilities technical capabilities this profile provides.
* @param parameters non-secret parameters and secret references keyed by parameter name.
* @param unresolvedNotes notes about entries that could not be confidently resolved.
* @param defaultProfile whether this profile is the prototype default profile.
*/
public record DeploymentProfileDetailDTO(String id, String name, String version, String status, List<String> editableBy, List<String> providedCapabilities,
Map<String, String> parameters, List<String> unresolvedNotes, boolean defaultProfile) {

/**
* Builds a detail DTO from a deployment profile.
*
* @param profile deployment profile.
* @param defaultProfile whether this profile is the prototype default profile.
* @return deployment profile detail DTO.
*/
public static DeploymentProfileDetailDTO from(DeploymentProfile profile, boolean defaultProfile) {
return new DeploymentProfileDetailDTO(profile.id(), profile.name(), profile.version(), profile.status(), profile.editableBy(),
profile.providedCapabilities(), profile.parameters(), profile.unresolvedNotes(), defaultProfile);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package de.tum.cit.aet.artemis.featuremodel.deployment.dto;

import de.tum.cit.aet.artemis.featuremodel.deployment.domain.DeploymentProfile;

/**
* Summary of a deployment profile for listing and selection. Excludes capabilities and parameters so the listing stays
* small; the detail DTO carries the full content.
*
* @param id stable profile id.
* @param name human-readable profile name.
* @param version profile version.
* @param status lifecycle status.
* @param defaultProfile whether this profile is the prototype default profile.
*/
public record DeploymentProfileSummaryDTO(String id, String name, String version, String status, boolean defaultProfile) {

/**
* Builds a summary from a deployment profile.
*
* @param profile deployment profile.
* @param defaultProfile whether this profile is the prototype default profile.
* @return deployment profile summary DTO.
*/
public static DeploymentProfileSummaryDTO from(DeploymentProfile profile, boolean defaultProfile) {
return new DeploymentProfileSummaryDTO(profile.id(), profile.name(), profile.version(), profile.status(), defaultProfile);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package de.tum.cit.aet.artemis.featuremodel.deployment.dto;

import java.util.List;

/**
* Availability of a single feature under the active deployment profile.
*
* <p>
* A feature is profile-dependent when it requires any capability, either directly or through a guided option that
* selects it. {@code teacherReason} is a readable, non-technical message for the review page and never contains raw
* capability ids; {@code requiredCapabilities} and {@code missingCapabilities} carry the technical detail for advanced
* tree and debug views only.
*
* @param featureId feature id.
* @param featureName feature display name, used to build the teacher-facing reason.
* @param available whether the feature is available under the active profile.
* @param profileDependent whether the feature requires any technical capability.
* @param requiredCapabilities capabilities the feature requires, aggregated from the feature and guided options.
* @param missingCapabilities required capabilities the active profile does not provide.
* @param teacherReason teacher-facing reason when unavailable, otherwise {@code null}.
*/
public record FeatureAvailabilityDTO(String featureId, String featureName, boolean available, boolean profileDependent, List<String> requiredCapabilities,
List<String> missingCapabilities, String teacherReason) {

/**
* Creates a feature availability DTO and normalizes nullable capability lists to immutable empty lists.
*
* @param featureId feature id.
* @param featureName feature display name.
* @param available whether the feature is available.
* @param profileDependent whether the feature requires any capability.
* @param requiredCapabilities capabilities the feature requires.
* @param missingCapabilities required capabilities the active profile does not provide.
* @param teacherReason teacher-facing reason when unavailable.
*/
public FeatureAvailabilityDTO {
requiredCapabilities = requiredCapabilities == null ? List.of() : List.copyOf(requiredCapabilities);
missingCapabilities = missingCapabilities == null ? List.of() : List.copyOf(missingCapabilities);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package de.tum.cit.aet.artemis.featuremodel.deployment.dto;

import java.util.List;

/**
* Availability of a single guided decision option under the active deployment profile.
*
* <p>
* {@code teacherReason} is a readable, non-technical message suitable for guided decision cards and never contains raw
* capability ids. {@code requiredCapabilities} and {@code missingCapabilities} carry the technical detail for advanced
* tree and debug views only.
*
* @param optionId guided decision option id.
* @param available whether the option can be selected under the active profile.
* @param requiredCapabilities capabilities the option requires.
* @param missingCapabilities required capabilities the active profile does not provide.
* @param teacherReason teacher-facing reason when unavailable, otherwise {@code null}.
*/
public record OptionAvailabilityDTO(String optionId, boolean available, List<String> requiredCapabilities, List<String> missingCapabilities, String teacherReason) {

/**
* Creates an option availability DTO and normalizes nullable capability lists to immutable empty lists.
*
* @param optionId guided decision option id.
* @param available whether the option can be selected.
* @param requiredCapabilities capabilities the option requires.
* @param missingCapabilities required capabilities the active profile does not provide.
* @param teacherReason teacher-facing reason when unavailable.
*/
public OptionAvailabilityDTO {
requiredCapabilities = requiredCapabilities == null ? List.of() : List.copyOf(requiredCapabilities);
missingCapabilities = missingCapabilities == null ? List.of() : List.copyOf(missingCapabilities);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package de.tum.cit.aet.artemis.featuremodel.deployment.dto;

import java.util.List;

/**
* Profile-aware availability of the active guided workflow and feature model under one deployment profile.
*
* <p>
* The Configurator reads this in a single call: {@code activeProfile} drives the review header, {@code availableProfiles}
* populates the profile selector, and the option and feature availability lists drive disabled states and the
* profile-dependent feature summary.
*
* @param activeProfile the profile the availability was resolved against.
* @param availableProfiles all selectable profiles, for the profile selector.
* @param options availability of each guided decision option.
* @param features availability of each model feature.
*/
public record WorkflowAvailabilityDTO(DeploymentProfileSummaryDTO activeProfile, List<DeploymentProfileSummaryDTO> availableProfiles,
List<OptionAvailabilityDTO> options, List<FeatureAvailabilityDTO> features) {

/**
* Creates a workflow availability DTO and normalizes nullable lists to immutable empty lists.
*
* @param activeProfile the profile the availability was resolved against.
* @param availableProfiles all selectable profiles.
* @param options availability of each guided decision option.
* @param features availability of each model feature.
*/
public WorkflowAvailabilityDTO {
availableProfiles = availableProfiles == null ? List.of() : List.copyOf(availableProfiles);
options = options == null ? List.of() : List.copyOf(options);
features = features == null ? List.of() : List.copyOf(features);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* REST DTOs for the deployment profile API: profile summaries and details, and profile-aware option and feature
* availability.
*/
package de.tum.cit.aet.artemis.featuremodel.deployment.dto;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Deployment profile feature. Loads JSON Deployment Profiles, exposes them through the deployment profile API, and
* resolves profile-aware availability of guided decision options and features so teachers configure functional features
* while technical capabilities and parameters come from maintainer-approved profiles.
*/
package de.tum.cit.aet.artemis.featuremodel.deployment;
Loading
Loading