Skip to content

Latest commit

 

History

History
409 lines (365 loc) · 23.3 KB

File metadata and controls

409 lines (365 loc) · 23.3 KB

CLAUDE.md

This file provides guidance to Claude Code and other coding agents when working in this repository.

Project Overview

artemis-feature-model is a standalone MVP for an interactive Artemis feature model. It turns a functional feature catalog into a constraint-aware exploration and configuration tool.

Tech Stack

  • Server: Spring Boot 4.0.x, Java 25
  • Client: Angular 21, TypeScript 5.9, SCSS
  • Build: Gradle wrapper, npm/Node 24
  • Testing: JUnit via Spring Boot test support, Vitest for Angular tests
  • Current styling baseline: Bootstrap-compatible SCSS
  • Runtime model: classpath JSON resource

This MVP does not use a database, Liquibase, authentication, authorization, Helm, or the Artemis runtime.

Current Project State

  • The backend exposes GET /api/feature-model, POST /api/feature-model/validate, GET /api/feature-model/guided-workflow, safe read-only runtime provenance at GET /api/feature-model/provenance, deployment profile endpoints (GET /api/deployment-profiles, GET /api/deployment-profiles/{id}), profile-aware availability (GET /api/feature-model/profile-availability), Level 1 configuration artifact download (POST /api/feature-model/artifacts/download), and local runtime deployment package endpoints (POST /api/feature-model/deployment-package/preview and /download).
  • 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, guided decision cards, immediate validation, detailed violation and warning feedback, review summaries, a first-run tutorial, and an in-configurator tree view.
  • 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 directly update the selection.
  • Artifact and deployment-package generation are implemented. A valid selection yields a downloadable ZIP: a Spring configuration overlay (application-feature-model.yml), an .env.example, selected-feature and deployment-profile metadata, and a generation report (Phase 5 Level 1); the deployment package adds local-checkout and self-contained remote-image Docker Compose stacks, helper scripts, a package manifest, and runtime checks for local validation. The review page generates and downloads directly; there is no preview step. Generation is DEMO-mode only and never writes plaintext secrets — secret values appear solely as ${VARIABLE} placeholders.
  • The deployment package supports an export-time deployment-mode axis (D1+D2): ArtifactGenerationRequest takes an optional deploymentMode (stable string ids in DeploymentModes: local-docker, dev-ide, remote-ansible); an omitted mode selects local Docker without recording a deployment mode in the package manifest, while an explicitly chosen mode is recorded. Package generation is deterministic for the same active model, catalog, profile, and request. Profiles may declare supportedDeploymentModes (absent = all; unknown entries warn, never fail loading), and an unsupported or unknown mode yields a controlled 400. DeploymentPackageService composes packages per mode from shared artifacts; the dev-ide mode emits the Level 1 overlay files plus a deterministic IntelliJ run configuration whose ACTIVE_PROFILES are derived from technical mapping tokens when present, with the original programming/hyperion rule retained only as the curated-model fallback, and a developer README. The profile order mirrors the run configurations Artemis ships and is semantic (buildagent must precede core, or the buildagent config excludes the JPA/DataSource auto-configuration and startup fails); an extra feature-model profile makes Spring load the overlay directly once it is copied under its original name into the checkout's config directory, with the developer's application-local.yml keeping final precedence. A feature-model-demo profile loads generated demo defaults for the overlay's ${VARIABLE} placeholders — the dev-ide counterpart of env/.env.demo — so a DEMO run starts without manual environment setup; real environment variables override the dummies. The review page offers a deployment-target picker; the guided workflow itself has no deployment decisions. Artifact mappings only reach the overlay when they target application-feature-model.yml.
  • The classpath model and generated snapshots now share the technical subtree and drive both package modes. dev-ide applies the selected CI profile family while recording its developer-managed database choice and generating actionable MySQL or PostgreSQL instructions. local-docker generates an extends-based Compose stack for the selected database and CI provider plus a self-contained stack using the configured ghcr.io/ls1intum/artemis image. start-demo.sh uses the local checkout when given a path and the remote image without an argument. Runtime provenance is resolved strictly from active snapshot metadata or the classpath runtime properties; latest is rendered as a mutable tag and other values as digest references. Both stacks retain selection-consistency runtime checks. Its integrated-code-lifecycle stack points LocalVC at the containerized Artemis server and supplies the host Docker socket group through a platform-aware FM_DOCKER_GID. Jenkins configuration keys are mapping-driven and secret-safe. Its local Docker package also points LocalVC at the containerized Artemis server and declares the build-agent Git credentials that the production image does not supply through application-localvc.yml. A local-docker Jenkins package deliberately has no Jenkins service yet, so it carries a prominent warning and a failing jenkins-stack-available check. The classpath defaults are MySQL, integrated code lifecycle, and LocalVC.
  • The remote-ansible mode generates an admin-consumable Ansible deployment package: a self-contained mini values repository (pinned collection requirements.yml, minimal ansible.cfg with hash_behaviour = merge, playbook, inventory membership wiring and group values, preflight script) plus remote metadata (remote-readiness.json, vault-references.json). Values come from the curated Ansible binding catalog (src/main/resources/deployment-bindings/artemis-ansible-binding-catalog.json), an application resource in both source modes, versioned by its collection pin — never part of a model snapshot. Every selectable feature must be classified bound/no-op/unsupported; unclassified or inexpressible selections (module reduction, Jenkins) fail closed with a controlled 400 naming the catalog identity or missing variable. Secrets appear only as lookup('hashi_vault', …) expressions. The optional null-tolerant remoteEnvironment request component supplies admin identity values; absent values yield a structurally identical placeholder package (environmentProvided: pending), and supplying the component on a non-remote mode is a controlled 400. Golden fixtures derived from the deploy-lab inventory pin the generated values byte-for-byte. The review page offers "Remote server (Ansible)" as a third deployment target sending only deploymentMode: "remote-ansible".
  • The generated overlay is statically validated against a curated Artemis config key catalog (src/main/resources/feature-model/artemis-config-key-catalog.json): unknown keys and value-type mismatches are reported without booting Artemis. The verdict ships as metadata/static-config-validation.json, a static-config-keys runtime check, and a validate-package.sh gate, and runs as a branch-scoped CI workflow. A drift-guard test fails when a model mapping path is missing from the catalog, so the catalog must be refreshed when Artemis config keys change.
  • Extraction runs as four composable commands plus one aggregate: extractFeatureCandidates (the only one that reads Artemis sources), assembleFeatureModel, prepareGuidedWorkflow, packageFeatureModelSnapshot, and buildFeatureModelSnapshot; featureModelManifestPreflight prints the derived source revision and manifest digest, and extractFeatureModel is a deprecated alias of the aggregate. Every command resolves the Artemis checkout, requires a clean git work tree, derives the run identity from checkout HEAD, and optionally verifies it against -PexpectedArtemisSha (the CI validation pin or a dispatch input). Each command owns one directory of build/feature-extraction/<derived-revision>/{scan,model,workflow,report,snapshot} and consumes upstream artifacts only through digest-verified envelopes, so a stale or foreign intermediate artifact is rejected instead of composed. The model envelope covers both the generated feature model and generated config-key catalog; packaging never reads either as an unverified side file. Configuration enters through FeatureExtractionInputs. Each command reads the manifest once — through the two-mode featureManifestSource strategy (repository committed default; checkout reads supportingFiles/feature-model/artemis-feature-manifest.yml inside the checkout, and repository mode fails on a diverging co-located copy) — and binds its parsed content, byte digest, derived revision, and revision-scoped layout in ExtractionRunContext; the local checkout resolves from -PartemisPath (or user-level gradle.properties), then ARTEMIS_PATH, and no developer path is committed. Override the relocatable repository-mode manifest input with -PfeatureManifestPath=<manifest.yml>. Outputs are deterministic apart from scan-metadata timestamps; the drift report replaces the discovery step of the manual weekly consistency audit.
  • The scope manifest is schema version 3 and carries curation content only: the source revision is derived from the verified checkout HEAD (a file cannot pin the commit that contains it), the runtime image reference lives in delivery/artemis-runtime-image.json, and the retired artemisCommitSha/artemisImageDigest fields are rejected with migration messages. The scan verifies before reading any file that the checkout is a clean git work tree and matches the expected revision when one is supplied. Curation is fail-closed — an undeclared candidate, a relation between included features without a declared constraint or an ignoredRelations entry, an orphan or ambiguous anchor, a colliding decision, or a failed extractor blocks the run, which writes diagnostics and exits non-zero without assembling a model. Manifest-authored semantics win over @ArtemisFeature annotations, which only fill attributes the manifest leaves open and never grant membership. Exclusion reasons are optional: an omitted reason is normalized to unspecified and reported as a non-blocking warning. Missing rationale on an excluded runtime toggle also warns, while an included runtime toggle without rationale remains a blocking curation conflict.
  • The extraction run additionally assembles a complete generated feature model from the manifest's include entries and conceptual nodes — including the first technical subtree (database mysql/postgresql and ci-provider integrated-code-lifecycle/jenkins as maintainer-only xor groups plus the mandatory localvc baseline, enforced through alternative group relations and excludes constraints) — regenerates the Artemis config-key catalog from the scanned YAML defaults, validates model and bundled workflow through the shared loader/integrity/diagnostics code paths, and independently compares the emitted model with the resolved manifest contract, including membership, names/descriptions, kind/category/defaults, hierarchy and group semantics, required capabilities, artifact mappings, constraints, and relation ordering. Any mismatch is a blocking conformance finding in JSON and HTML. It also emits a complete deterministic snapshot/ folder. The manifest-driven generated model is canonical for delivery and is independent of the curated classpath development fixture. Runtime selects the complete classpath or snapshot bundle explicitly, and StaticConfigValidationService always consumes the catalog from that same validated bundle.
  • Enabled configuration keys are not standalone feature candidates and therefore need no manifest membership entries. Their constants, YAML defaults, and usage remain evidence on the owning module candidate and inputs to artifact mappings and the generated config-key catalog; new enabled-property anchors still surface through their module candidates and remain fail-closed.
  • The authored guided-workflow.json is lean: decision structure and teacher prose only. Model-owned wiring — option requiresCapabilities and artifactImpacts, the workflow's feature model pin, and review group members (now referenced by groupNodeId) — is derived at serve time by GuidedWorkflowAssembler, so the served DTO shape is unchanged and capabilities are single-source on model features. GuidedWorkflowDiagnosticsService surfaces coverage, capability-validity, template-consistency, and stub-prose findings as logged warnings in the app and as guided-workflow-validation.json (with an automation status) in the extraction output; hard reference errors still fail hard. ./gradlew syncGuidedWorkflowScaffold is a deliberate maintainer task that stubs newly included features with TODO prose, flags orphans without deleting, and leaves an already-covered workflow byte-identical.
  • Successful and controlled failed extraction runs write a dependency-free report/index.html plus raw conformance, extraction, workflow, and release-delta JSON. Successful runs publish seven checksummed snapshot files: model, workflow, generated config-key catalog, generation report, deterministic provenance, metadata, and checksums.txt. ./gradlew validateFeatureModelSnapshot -PsnapshotPath=<snapshot> validates the complete snapshot read-only; generation invokes the same validator before exposing a snapshot. Metadata validation is fail-closed for generated lifecycle status, extractor identity, and immutable image identity as well as payload names and cross-artifact provenance.
  • GitHub delivery reuses one read-only validation workflow for pull requests, development-branch pushes, and publication. PR CI checks out Artemis at the committed delivery/artemis-validation-pin and validates deterministically; publication runs supply an explicitly resolved immutable SHA. Publication (publish-snapshot-image.yml, image-publish Environment) tags the content-addressed snapshot id, short-circuits on an already-published identity, attests build provenance, and records the registry digest. Promotion (promote-image.yml, image-promote Environment) retags a published digest as verified without rebuilding and appends to the delivery/verified-images.json ledger via an automated PR; rollback is promotion of a prior ledger entry. The scheduled poller (poll-artemis-delivery.yml) resolves the Artemis tracking ref, publishes, and opens the delivery auto-PR (fixture refresh, validation-pin bump, coverage summary). No workflow publishes latest or deploys the image; deployment remains deferred. The cutover to the Artemis-hosted manifest is documented in docs/extraction/automated-model-delivery.md and not executed.
  • Runtime source mode is explicit under artemis.feature-model.source-mode. Local development defaults to classpath, which loads and validates the hand-maintained model, workflow, and config-key catalog as one bundle and rejects an active snapshot id. Production-like execution uses snapshot, requires data-root plus active-snapshot-id, validates the complete v2 snapshot during startup, and never falls back to classpath artifacts. The legacy /api/feature-model/snapshots/** administration resource is absent by default and can only be enabled explicitly in classpath mode. A controlled Docker named-context task stages one revalidated snapshot; the production image embeds it read-only, selects snapshot mode explicitly, runs as uid 10001 without a model volume, and records snapshot/source OCI labels.

Build and Development Commands

Run commands from the repository root:

./gradlew test                    # server tests
./gradlew bootRun                 # server on http://localhost:8090

npm install                       # install client dependencies
npm run start                     # Angular dev server on http://localhost:9090
npm run build                     # Angular build into build/webapp
npm run test                      # Angular unit tests with Vitest

The Angular dev server proxies /api/** to http://localhost:8090. The local ports deliberately avoid the Artemis dev defaults (8080/9000) so both applications can run side by side.

Project Structure

build.gradle
settings.gradle
gradle.properties
gradlew
gradlew.bat
package.json
package-lock.json
angular.json
tsconfig.json
tsconfig.app.json
tsconfig.spec.json
proxy.conf.json
src/main/java/de/tum/cit/aet/artemis/featuremodel/
src/main/resources/
src/main/webapp/
src/test/java/de/tum/cit/aet/artemis/featuremodel/

Server package areas:

  • catalog owns the feature model catalog, source model records, storage boundary, JSON-backed store, and model metadata.
  • validation owns model and selection validation.
  • visualization owns derived tree/read-model structures.
  • selection owns user selection concepts and future selection sessions.
  • snapshot owns the legacy, explicit-development-only local snapshot listing, import, and export surface.
  • deployment owns deployment profiles, profile loading, and capability resolution.
  • export owns Level 1 configuration artifact generation, the Level 2 local runtime deployment package, and static overlay validation against the Artemis config key catalog.
  • extraction owns the manifest-driven staged pipeline. extraction.source owns upstream source conventions, verified location, and shared parse/scan results; extraction.domain owns persisted scan, envelope, and snapshot-bundle contracts; extraction.pipeline owns shared stage infrastructure — run context, verified input loading, manifest loading and preflight, the digest-verified artifact store, and controlled-failure reporting; extraction.scan owns the source scanners and candidate assembly behind the scan stage; extraction.model owns curation, conformance, and model/catalog generation behind the model stage; extraction.workflow owns extraction-time workflow validation and scaffold authoring; extraction.report owns report assembly and HTML rendering and depends only on extraction.domain; extraction.snapshot owns snapshot publication, validation, and Docker context staging behind the package stage; extraction.artifact owns deterministic JSON bytes, SHA-256 calculation, and artifact-directory lifecycle operations.
  • shared is only for truly shared exceptions, constants, and small utilities.

Client areas:

  • src/main/webapp/app/app.* contains the application shell and routes.
  • src/main/webapp/app/feature-model/core is for shared feature-model interfaces and pure helpers.
  • src/main/webapp/app/feature-model/api is for Angular API services.
  • src/main/webapp/app/feature-model/explorer is for the read-only explorer route.
  • src/main/webapp/app/feature-model/configurator is for the interactive configurator route.
    • guided/ contains the guided workflow UI.
    • guided/tutorial/ contains the tutorial panel UI.
    • tree/ contains the in-configurator tree view.
    • shared/ contains configurator-local types and selection helpers.
  • src/main/webapp/app/feature-model/validation is for validation status and violation UI.

Source Model Rules

  • Runtime resource: src/main/resources/feature-model/functional-feature-model.json

Do not duplicate the feature model in client code. The server loads the runtime classpath copy and exposes it through APIs.

Behavioral Guidelines

Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.

1. Think Before Coding

Don't assume. Don't hide confusion. Surface tradeoffs.

Before implementing:

  • State your assumptions explicitly. If uncertain, ask.
  • If multiple interpretations exist, present them - don't pick silently.
  • If a simpler approach exists, say so. Push back when warranted.
  • If something is unclear, stop. Name what's confusing. Ask.

2. Simplicity First

Minimum code that solves the problem. Nothing speculative.

  • No features beyond what was asked.
  • No abstractions for single-use code.
  • No "flexibility" or "configurability" that wasn't requested.
  • No error handling for impossible scenarios.
  • If you write 200 lines and it could be 50, rewrite it.

Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.

3. Surgical Changes

Touch only what you must. Clean up only your own mess.

When editing existing code:

  • Don't "improve" adjacent code, comments, or formatting.
  • Don't refactor things that aren't broken.
  • Match existing style, even if you'd do it differently.
  • If you notice unrelated dead code, mention it - don't delete it.

When your changes create orphans:

  • Remove imports/variables/functions that YOUR changes made unused.
  • Don't remove pre-existing dead code unless asked.

The test: Every changed line should trace directly to the user's request.

4. Goal-Driven Execution

Define success criteria. Loop until verified.

Transform tasks into verifiable goals:

  • "Add validation" → "Write tests for invalid inputs, then make them pass"
  • "Fix the bug" → "Write a test that reproduces it, then make it pass"
  • "Refactor X" → "Ensure tests pass before and after"

For multi-step tasks, state a brief plan:

1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]

Guidelines and Conventions

Detailed project guidelines are maintained in docs/guidelines/. Treat those files as the source of truth and avoid duplicating their contents here.

When a change touches one of these areas, read the corresponding guideline before editing code. Update the guideline document itself when a convention changes; keep CLAUDE.md as the project overview and navigation entry point.