refactor: [#298] Phase 3 Port Topology Domain Model - Foundation (P3.1-P3.3)#299
Merged
Conversation
…alidation This commit implements Phase 3 (P3.1-P3.3) of Epic #287: P3.1 - Create Port domain types: - Add PortBinding struct with protocol, host/container ports, host IP, description - Reuse existing Protocol enum from domain/tracker - Add convenience constructors: tcp(), udp(), localhost_tcp() - Add docker_compose_binding() for YAML rendering P3.2 - Extend ServiceTopology with ports: - Add ports: Vec<PortBinding> to ServiceTopology - Add new() constructor with networks and ports - Add with_networks() backward-compatible convenience constructor - Add ports() and has_ports() methods P3.3 - Add cross-service port validation: - Add validate_port_uniqueness() to DockerComposeTopology - Create PortConflict error with actionable details - Create TopologyError enum for topology validation errors All PORT-* rules from the original refactoring plan are now representable as domain types. P3.4 (template integration) is tracked separately.
- Split Phase 3 into two PRs for better reviewability - PR #298: Domain foundation (P3.1-P3.3) - this PR - Follow-up PR: Template integration (P3.4) - Mark P3.1-P3.3 tasks as complete in spec - Update acceptance criteria to show partial completion - Add key decision about PR split and DDD error conventions
Member
Author
|
ACK dd3ab12 |
16 tasks
21 tasks
21 tasks
josecelano
added a commit
that referenced
this pull request
Jan 25, 2026
6 tasks
josecelano
added a commit
that referenced
this pull request
Jan 26, 2026
…on (P3.4) 8dcbbc9 fix: [#300] workaround for clippy large_stack_arrays by commenting tests (Jose Celano) 3ea8c65 refactor: [#300] Phase 3 Port Topology Template Integration (P3.4) (Jose Celano) Pull request description: ## Summary Integrates the `PortBinding` domain types (created in #298) into the Docker Compose template rendering, completing Phase 3 of the topology refactoring. ## Changes ### Port Derivation (`port_derivation.rs`) - Implements PORT-01 through PORT-11 rules from the refactoring plan - `derive_tracker_ports()` - UDP always exposed, HTTP/API only when no TLS - `derive_caddy_ports()` - Always exposes 80, 443, 443/udp - `derive_prometheus_ports()` - 9090 on localhost only - `derive_grafana_ports()` - 3000 only when no TLS - `derive_mysql_ports()` - No exposed ports ### Port Definition DTO (`port_definition.rs`) - `PortDefinition` struct with `binding` and `description` fields - `From<&PortBinding>` trait for idiomatic conversion - Serializable for Tera template context ### Service Context Updates - Added `ports: Vec<PortDefinition>` to all service configs - Tracker, Caddy, Prometheus, Grafana, MySQL all derive their ports ### Template Simplification (`docker-compose.yml.tera`) - Replaced conditional port logic with simple loops - Added description comments using `# {{ port.description }}` - Removed `needs_ports_section` checks (replaced by `ports | length > 0`) ### Validation - `try_build()` method on `DockerComposeContextBuilder` validates port uniqueness - `PortConflictError` with `help()` method for actionable error messages - DDD "always valid" pattern: `DockerComposeTopology::new()` returns `Result` ### Documentation - Created Issue #301 spec for Phase 4 (DDD Layer Alignment - future work) - Updated Epic #287 with Phase 4 tasks ## Testing - 15 unit tests for port derivation functions - Unit tests for `PortDefinition` conversion - Tests for `try_build()` validation - All E2E tests pass ## Rendered Output Example ```yaml services: tracker: ports: # BitTorrent UDP announce - "6969:6969/udp" # HTTP tracker announce - "7070:7070" # HTTP API (stats/whitelist) - "1212:1212" ``` ## Checklist - [x] Pre-commit checks pass: `./scripts/pre-commit.sh` - [x] All PORT-* rules implemented in port derivation functions - [x] Port descriptions render as YAML comments in generated output - [x] Template uses loops over `service.ports` - [x] Cross-service port conflicts detected before rendering via `try_build()` - [x] All existing E2E tests pass ## Related - **Issue**: #300 - **Epic**: #287 - Docker Compose Topology Domain Model Refactoring - **Foundation PR**: #299 (merged) - **Spec**: `docs/issues/300-phase-3-port-topology-template-integration.md` ACKs for top commit: josecelano: ACK 8dcbbc9 Tree-SHA512: 2a71fd13df0353e57d5800210a9e4aeded11e1550f6a5c65b4ff3ae50b6cd111389cc9504bdff4229681c79cbfc639e55720f69e4f4d402d2cbfe5fdaae1ebaf
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements the domain layer foundation for Phase 3 of the Docker Compose Topology refactoring (Epic #287). It creates type-safe port binding types and cross-service port conflict validation, following the same pattern established for networks in Phase 1-2.
Changes
P3.1: Create Port Domain Types ✅
Protocolenum fromdomain/tracker/protocol.rs(no duplication)PortBindingstruct with:host_port,container_port,protocol,host_ip,descriptiontcp(),udp(),localhost_tcp()docker_compose_binding()method for YAML rendering (e.g.,"6969:6969/udp")P3.2: Extend ServiceTopology with Ports ✅
ports: Vec<PortBinding>field toServiceTopologynew()constructor with ports parameterwith_networks()for backward compatibilityP3.3: Add Cross-Service Port Validation ✅
PortConflicterror type with full context (both services, both bindings)TopologyErrorenum withhelp()method (DDD error conventions)validate_port_uniqueness()onDockerComposeTopologyDDD Compliance
All code follows the project's DDD practices (docs/contributing/ddd-practices.md):
#[must_use]on gettershelp()TopologyError::help()What's NOT in this PR
P3.4 (Template Integration) will be a follow-up PR:
DockerComposeContextto use derived portsdocker-compose.yml.teraport sectionsThis split allows the domain foundation to be reviewed and merged independently.
Testing
Files Changed
src/domain/topology/port.rsPortBindingstructsrc/domain/topology/error.rsPortConflict,TopologyErrorsrc/domain/topology/aggregate.rsServiceTopologywith portssrc/domain/topology/mod.rsdocs/issues/287-*.mddocs/issues/298-*.mdRelated