feat: enforce single tool type with port configuration
- Replace interfaces array with single interface_type string (web/terminal) - Add requires_port boolean to indicate port/tunnel needs - Create Alembic migration for database schema change - Update backend model, API validation, and seed data - Update frontend types and tool workshop UI with dropdown - Add conditional port field rendering based on interface type - Update all frontend and backend tests OpenSpec change: enforce-single-tool-type-with-port-config Quality gates: frontend typecheck PASS, lint PASS, tests 37/37 PASS
This commit is contained in:
@@ -111,6 +111,37 @@ The system SHALL provide a dashboard overview.
|
||||
- Recent activity
|
||||
- Quick action buttons
|
||||
|
||||
### Requirement: Tool Interface Type Dropdown
|
||||
The tool workshop SHALL provide a dropdown for selecting a single interface type.
|
||||
|
||||
#### Scenario: Interface type dropdown
|
||||
- GIVEN the tool workshop page
|
||||
- WHEN a user creates or edits a tool type
|
||||
- THEN the interface type field is a dropdown (not checkboxes)
|
||||
- AND the options are "web" and "terminal"
|
||||
- AND only one option can be selected
|
||||
|
||||
### Requirement: Conditional Port Fields
|
||||
The tool workshop SHALL conditionally show or hide port-related fields based on the selected interface type.
|
||||
|
||||
#### Scenario: Web tool shows port fields
|
||||
- GIVEN a tool type with interface type "web"
|
||||
- WHEN the user views the tool editor
|
||||
- THEN the Default Port field is visible and required
|
||||
- AND port-related config fields are shown
|
||||
|
||||
#### Scenario: Terminal tool hides port fields
|
||||
- GIVEN a tool type with interface type "terminal"
|
||||
- WHEN the user views the tool editor
|
||||
- THEN the Default Port field is hidden
|
||||
- AND port-related config fields are hidden or disabled
|
||||
|
||||
#### Scenario: Changing interface type updates visibility
|
||||
- GIVEN a user changes interface type from "web" to "terminal"
|
||||
- WHEN the change is applied
|
||||
- THEN port fields are immediately hidden
|
||||
- AND any port value is preserved but not validated
|
||||
|
||||
## Dependencies
|
||||
|
||||
- React 18+
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Port Configuration Visibility
|
||||
The system SHALL control whether port configuration is relevant for a tool type.
|
||||
|
||||
#### Scenario: Web tool requires port
|
||||
- GIVEN a tool type with `requires_port` = true
|
||||
- WHEN the tool type is displayed in the UI
|
||||
- THEN port configuration fields are shown
|
||||
- AND default_port is validated as required
|
||||
|
||||
#### Scenario: Terminal tool does not require port
|
||||
- GIVEN a tool type with `requires_port` = false
|
||||
- WHEN the tool type is displayed in the UI
|
||||
- THEN port configuration fields are hidden
|
||||
- AND default_port validation is skipped
|
||||
- AND port_override in tool configs is not shown
|
||||
|
||||
### Requirement: Port Validation Based on requires_port
|
||||
The API SHALL validate port fields conditionally based on requires_port.
|
||||
|
||||
#### Scenario: Validate port for web tools
|
||||
- GIVEN a tool type with `requires_port` = true
|
||||
- WHEN creating or updating without a default_port
|
||||
- THEN the system returns 400 Bad Request
|
||||
|
||||
#### Scenario: Skip port validation for terminal tools
|
||||
- GIVEN a tool type with `requires_port` = false
|
||||
- WHEN creating or updating without a default_port
|
||||
- THEN the request succeeds
|
||||
- AND default_port defaults to 0 or null
|
||||
|
||||
### Requirement: UI Conditional Rendering
|
||||
The frontend SHALL conditionally render port-related UI elements.
|
||||
|
||||
#### Scenario: Hide port in tool list
|
||||
- GIVEN a terminal tool type
|
||||
- WHEN displayed in the tool workshop list
|
||||
- THEN port information is not shown
|
||||
|
||||
#### Scenario: Hide port in editor
|
||||
- GIVEN a terminal tool type being edited
|
||||
- WHEN the editor form is rendered
|
||||
- THEN the Default Port field is hidden
|
||||
- AND the readiness probe fields are shown (still relevant)
|
||||
|
||||
#### Scenario: Show port for web tools
|
||||
- GIVEN a web tool type being edited
|
||||
- WHEN the editor form is rendered
|
||||
- THEN the Default Port field is visible and required
|
||||
@@ -0,0 +1,39 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Single Interface Type Enforcement
|
||||
The system SHALL enforce that each tool type has exactly one interface type.
|
||||
|
||||
#### Scenario: Create with single interface
|
||||
- GIVEN a tool type creation request with `interface_type` = "web"
|
||||
- WHEN the request is processed
|
||||
- THEN the tool type is created successfully
|
||||
- AND the interface type is stored as a single string
|
||||
|
||||
#### Scenario: Reject multiple interfaces
|
||||
- GIVEN a legacy request with `interfaces` array
|
||||
- WHEN the request is processed
|
||||
- THEN the system returns 400 Bad Request
|
||||
- AND the error message indicates that `interface_type` (string) should be used instead
|
||||
|
||||
### Requirement: Interface Type Validation
|
||||
The system SHALL validate that interface_type is one of the allowed values.
|
||||
|
||||
#### Scenario: Valid interface types
|
||||
- GIVEN interface_type values "web" or "terminal"
|
||||
- WHEN a tool type is created or updated
|
||||
- THEN the request is accepted
|
||||
|
||||
#### Scenario: Invalid interface type
|
||||
- GIVEN interface_type value "ssh"
|
||||
- WHEN a tool type is created or updated
|
||||
- THEN the system returns 400 Bad Request
|
||||
|
||||
### Requirement: Data Migration
|
||||
The system SHALL migrate existing tool types from interfaces array to single interface_type.
|
||||
|
||||
#### Scenario: Migrate existing records
|
||||
- GIVEN existing tool types with interfaces = ["web"] or ["terminal"]
|
||||
- WHEN the migration runs
|
||||
- THEN each record gets interface_type = interfaces[0]
|
||||
- AND requires_port is set based on the interface type
|
||||
- AND the old interfaces column is removed
|
||||
@@ -11,7 +11,12 @@ The system SHALL provide a `ToolType` model to store tool definitions.
|
||||
- `name`: unique string (e.g., "code-server")
|
||||
- `display_name`: human-readable string (e.g., "VS Code Server")
|
||||
- `description`: optional text
|
||||
- `category`: string (e.g., "editor", "notebook")
|
||||
- `interface_type`: single string — "web" or "terminal"
|
||||
- `requires_port`: boolean indicating if port/tunnel configuration is needed
|
||||
- `compose_template`: Docker Compose YAML string
|
||||
- `dockerfile_template`: Dockerfile string
|
||||
- `definition_type`: string — "compose" or "dockerfile"
|
||||
- `required_variables`: list of required template variables
|
||||
- `is_builtin`: boolean flag for system-defined types
|
||||
- `created_at`/`updated_at`: timestamps
|
||||
@@ -30,7 +35,9 @@ The system SHALL provide REST API endpoints for tool type management.
|
||||
- GIVEN an admin user
|
||||
- WHEN they POST /api/tool-types with valid data
|
||||
- THEN the system creates a new tool type
|
||||
- AND validates the compose template YAML
|
||||
- AND validates `interface_type` is "web" or "terminal"
|
||||
- AND validates `requires_port` is boolean
|
||||
- AND validates the compose template YAML (if definition_type is "compose")
|
||||
- AND validates all required variables are present in template
|
||||
- AND returns 201 Created with the new tool type
|
||||
|
||||
@@ -44,6 +51,7 @@ The system SHALL provide REST API endpoints for tool type management.
|
||||
- GIVEN an admin user
|
||||
- WHEN they PUT /api/tool-types/{id} with valid data
|
||||
- THEN the system updates the tool type
|
||||
- AND validates `interface_type` is "web" or "terminal" if provided
|
||||
- AND re-validates the compose template
|
||||
- AND returns 200 OK with updated tool type
|
||||
|
||||
@@ -98,3 +106,33 @@ The system SHALL validate Docker Compose templates.
|
||||
- THEN the system SHALL require:
|
||||
- `services` key present
|
||||
- At least one service defined
|
||||
|
||||
### Requirement: Port requirement indication
|
||||
The system SHALL allow tool types to indicate whether they require port configuration.
|
||||
|
||||
#### Scenario: Web tool requires port
|
||||
- GIVEN a tool type with `interface_type` = "web"
|
||||
- WHEN the tool type is created or updated
|
||||
- THEN `requires_port` SHALL default to true
|
||||
- AND port-related configuration is shown in the UI
|
||||
|
||||
#### Scenario: Terminal tool does not require port
|
||||
- GIVEN a tool type with `interface_type` = "terminal"
|
||||
- WHEN the tool type is created or updated
|
||||
- THEN `requires_port` SHALL default to false
|
||||
- AND port-related configuration is hidden in the UI
|
||||
|
||||
### Requirement: Single interface validation
|
||||
The system SHALL enforce that each tool type has exactly one interface type.
|
||||
|
||||
#### Scenario: Invalid interface type
|
||||
- GIVEN a tool type creation request with `interface_type` = "invalid"
|
||||
- WHEN the request is processed
|
||||
- THEN the system returns 400 Bad Request
|
||||
- AND the error message indicates valid values are "web" or "terminal"
|
||||
|
||||
#### Scenario: Missing interface type
|
||||
- GIVEN a tool type creation request without `interface_type`
|
||||
- WHEN the request is processed
|
||||
- THEN the system returns 400 Bad Request
|
||||
- AND the error message indicates interface_type is required
|
||||
|
||||
Reference in New Issue
Block a user