Acceptance Criteria

Conventions

Acceptance criteria are written in Gherkin format (Given-When-Then). They are grouped by feature area and reference the corresponding use cases from 01_use_cases.adoc.

Model Initialization (UC-1)

AC-1.1: Default model creation

Feature: Initialize architecture model

  Scenario: Create new model in empty directory
    Given an empty project directory
    When the user runs "bausteinsicht init"
    Then a model file is created with a default specification
    And the specification contains element kinds "actor", "system", "container", "component"
    And a sample model with example elements exists
    And a default draw.io template file is created
    And the model file references a JSON Schema

  Scenario: Refuse to overwrite existing model
    Given a project directory with an existing Bausteinsicht model
    When the user runs "bausteinsicht init"
    Then the command exits with a non-zero exit code
    And a warning message indicates that model files already exist
    And no existing files are modified

Element Definition (UC-2)

AC-2.1: Element creation with unique IDs

Feature: Define architecture elements

  Scenario: Add element with unique ID
    Given a valid architecture model
    When the user adds an element with ID "payment_service", kind "container", and title "Payment Service"
    Then the model contains an element "payment_service" of kind "container"
    And the element has the title "Payment Service"

  Scenario: Reject duplicate element ID
    Given a valid architecture model containing element "api_gateway"
    When the user adds another element with ID "api_gateway"
    Then the JSON Schema validation reports an error
    And the model is not modified

  Scenario: Nested elements
    Given a valid architecture model with element "backend" of kind "container"
    When the user adds element "auth_module" of kind "component" as a child of "backend"
    Then the model contains "backend.auth_module"
    And "auth_module" is nested inside "backend"

  Scenario: Deeply nested elements (flexible hierarchy)
    Given a valid architecture model
    When the user creates elements nested 5 levels deep
    Then the model validates successfully
    And all 5 levels are represented correctly

AC-2.2: Relationship definition

Feature: Define relationships

  Scenario: Add relationship between elements
    Given a model with elements "frontend" and "api"
    When the user adds a relationship from "frontend" to "api" with label "calls"
    Then the model contains a relationship from "frontend" to "api"
    And the relationship has label "calls"

  Scenario: Relationship with nested element reference
    Given a model with element "backend.api" (nested)
    When the user adds a relationship from "frontend" to "backend.api"
    Then the relationship correctly references the nested element using dot notation

Forward Sync — Model to draw.io (UC-3)

AC-3.1: Initial diagram generation

Feature: Generate draw.io diagrams from model

  Scenario: Generate new diagram
    Given a valid architecture model with 3 elements and 2 relationships
    And a draw.io template with styled reference elements
    And no draw.io output file exists
    When the user runs "bausteinsicht sync"
    Then a draw.io file is created
    And all 3 elements appear as styled mxCell elements
    And all 2 relationships appear as connectors
    And each element carries its Bausteinsicht ID as a custom property
    And elements are placed side-by-side (no overlapping)
    And connectors are attached to element centers

  Scenario: Template styling is applied
    Given a template with a blue rounded rectangle for kind "system"
    And the model contains element "webshop" of kind "system"
    When the user runs "bausteinsicht sync"
    Then "webshop" appears as a blue rounded rectangle in the draw.io output

AC-3.2: Incremental sync preserving layout

Feature: Incremental forward sync

  Scenario: Add new element to existing diagram
    Given an existing draw.io diagram with elements "A" and "B" at specific positions
    And the model now contains a new element "C"
    When the user runs "bausteinsicht sync"
    Then element "C" appears in the draw.io file
    And element "C" has a visual marker indicating it needs manual positioning
    And elements "A" and "B" retain their original positions

  Scenario: Update element description
    Given a model where element "api" has description changed to "REST API v2"
    And an existing draw.io diagram containing "api"
    When the user runs "bausteinsicht sync"
    Then the draw.io element for "api" shows the updated description
    And the position of "api" is unchanged

  Scenario: Remove deleted element
    Given a model where element "legacy_db" has been removed
    And an existing draw.io diagram containing "legacy_db"
    When the user runs "bausteinsicht sync"
    Then "legacy_db" no longer appears in the draw.io file
    And connectors that referenced "legacy_db" are removed

Reverse Sync — draw.io to Model (UC-4)

AC-4.1: Detect changes from draw.io

Feature: Reverse sync from draw.io to model

  Scenario: Renamed element in draw.io
    Given a draw.io diagram where element with ID "api" has been renamed to "REST API v2"
    When the user runs "bausteinsicht sync"
    Then the model element "api" has its title updated to "REST API v2"
    And the element ID "api" remains unchanged

  Scenario: New element added in draw.io
    Given a draw.io diagram where the user has added a new rectangle labeled "Cache"
    And the new element has no Bausteinsicht ID
    When the user runs "bausteinsicht sync"
    Then a new element is added to the model with ID "cache" (sanitized from label: lowercase, hyphen-separated)
    And the element is assigned the first alphabetically-sorted kind from the specification
    And the element appears in other views on the next forward sync

  Scenario: New element with colliding ID is skipped
    Given a draw.io diagram where the user has added a new rectangle labeled "API"
    And the model already contains an element with ID "api"
    When the user runs "bausteinsicht sync"
    Then the new element is NOT imported
    And a warning is displayed indicating the ID "api" already exists

  Scenario: Navigation buttons are excluded from reverse sync
    Given a draw.io diagram containing navigation buttons with IDs prefixed "nav-back-"
    When the user runs "bausteinsicht sync"
    Then the navigation buttons are not detected as new elements
    And no model changes are made for navigation buttons

  Scenario: New relationship drawn in draw.io
    Given a draw.io diagram where the user has drawn an arrow from "api" to "cache" with label "reads"
    When the user runs "bausteinsicht sync"
    Then a new relationship is added to the model from "api" to "cache" with label "reads"

  Scenario: Layout-only change does not modify model
    Given a draw.io diagram where element "api" has been moved to a different position
    And no other changes were made
    When the user runs "bausteinsicht sync"
    Then the model file is not modified

AC-4.2: Conflict handling

Feature: Sync conflict handling

  Scenario: Same element changed in both model and draw.io
    Given element "api" has title "API" in the model
    And element "api" has title "REST API" in draw.io
    And both changes happened since the last sync
    When the user runs "bausteinsicht sync"
    Then a warning is displayed showing both values
    And no silent overwrite occurs

Watch Mode (UC-5)

AC-5.1: Continuous synchronization

Feature: Watch mode

  Scenario: Auto-sync on model change
    Given "bausteinsicht watch" is running
    When the user saves a change to the model file
    Then the draw.io diagram is updated within 2 seconds
    And a sync summary is displayed

  Scenario: Auto-sync on draw.io change
    Given "bausteinsicht watch" is running
    When the user saves a change to the draw.io file
    Then the model is updated within 2 seconds
    And a sync summary is displayed

  Scenario: Debounce rapid changes
    Given "bausteinsicht watch" is running
    When the user saves the model file 5 times within 1 second
    Then only 1 sync operation is performed

CLI Interface (UC-6)

AC-6.1: Validation

Feature: Model validation

  Scenario: Valid model
    Given a valid architecture model
    When the user runs "bausteinsicht validate"
    Then the command exits with exit code 0
    And a success message is displayed

  Scenario: Invalid model
    Given a model with a relationship referencing non-existent element "ghost"
    When the user runs "bausteinsicht validate"
    Then the command exits with a non-zero exit code
    And an error message identifies the invalid reference

  Scenario: Version display
    When the user runs "bausteinsicht --version"
    Then the current version number is displayed

AC-6.2: LLM-friendly CLI

Feature: LLM-driven model manipulation

  Scenario: Add element via CLI
    Given a valid architecture model
    When an LLM runs "bausteinsicht add element --id cache --kind container --title Cache"
    Then the model contains a new element "cache" of kind "container" with title "Cache"

  Scenario: Add relationship via CLI
    Given a model with elements "api" and "cache"
    When an LLM runs "bausteinsicht add relationship --from api --to cache --label reads"
    Then the model contains a new relationship from "api" to "cache" with label "reads"

  Scenario: Machine-readable output
    Given a valid architecture model
    When the user runs "bausteinsicht validate --format json"
    Then the output is valid JSON with structured validation results

Navigation and Drill-Down (UC-7)

AC-7.1: Zoom-based navigation

Feature: Drill-down navigation in draw.io

  Scenario: Link from context to container view
    Given a model with system "webshop" containing containers "api" and "db"
    And views exist for both context and container level
    When "bausteinsicht sync" generates the draw.io file
    Then the "webshop" element in the context view contains a link
    And clicking the link navigates to the container view area

  Scenario: Parent view visible after drill-down
    Given views at context and container level on a single draw.io page
    When the user navigates from context to container level
    Then the context view remains visible (smaller) above the container view
    And clicking the context view navigates back

Export Command (UC-8)

AC-8.1: Diagram export

Feature: Export diagram views as images

  Scenario: Export all views as PNG
    Given a synced architecture model with 3 views
    When the user runs "bausteinsicht export"
    Then PNG files are generated for each view in the output directory
    And the exit code is 0

  Scenario: Export specific view
    Given a synced architecture model
    When the user runs "bausteinsicht export --view context"
    Then only the "context" view is exported

  Scenario: Export non-existent view
    Given a synced architecture model
    When the user runs "bausteinsicht export --view nonexistent"
    Then the exit code is 2
    And the error message mentions "view not found"

  Scenario: Export as SVG
    Given a synced architecture model
    When the user runs "bausteinsicht export --image-format svg"
    Then SVG files are generated for each view

  Scenario: Export to custom directory
    Given a synced architecture model
    When the user runs "bausteinsicht export --output ./docs/images"
    Then image files are written to the "./docs/images" directory

Bugfix Acceptance Criteria

AC-9.1: Self-referencing relationship rendering (#111)

Feature: Self-referencing relationships

  Scenario: Element with relationship to itself
    Given a model with element "api" that has a relationship from "api" to "api" with label "recurse"
    When the user runs "bausteinsicht sync"
    Then a loopback connector is rendered on the "api" element in draw.io
    And the connector label shows "recurse"
    And the connector does not overlap the element text

AC-9.2: View include cleanup on element deletion (#114)

Feature: View cleanup on element deletion

  Scenario: Deleted element is removed from view includes
    Given a model with element "legacy" included in views "context" and "container"
    When the user deletes element "legacy" from the model
    And the user runs "bausteinsicht sync"
    Then "legacy" is removed from the include lists of all views
    And no dangling references remain in the view definitions

AC-9.3: Lifted connector deduplication (#197)

Feature: Lifted connector deduplication

  Scenario: Multiple child relationships produce single lifted connector
    Given a model where "a.child1" and "a.child2" both relate to "b"
    And a view that shows "a" and "b" but not their children
    When the user runs "bausteinsicht sync"
    Then only one lifted connector is drawn from "a" to "b"
    And the connector is not duplicated

AC-9.4: Connector to scope element (#217)

Feature: Connector to scope element

  Scenario: Relationship targets the scope element of a view
    Given a model where element "api" has a relationship to the scope element "system"
    And a view with scope "system" that includes "api"
    When the user runs "bausteinsicht sync"
    Then a connector is drawn from "api" to the scope boundary of the view
    And the connector is correctly attached