Skip to content

refactor: separate view data from views in presentation layer#354

Merged
josecelano merged 9 commits into
mainfrom
refactor/separate-view-data-from-views
Feb 16, 2026
Merged

refactor: separate view data from views in presentation layer#354
josecelano merged 9 commits into
mainfrom
refactor/separate-view-data-from-views

Conversation

@josecelano

Copy link
Copy Markdown
Member

Overview

This refactoring establishes a clear separation between view data structures (DTOs) and view rendering logic in the presentation layer. It creates a consistent, scalable structure for all command views as a prerequisite for implementing JSON output support (EPIC #348 tasks 12.3-12.5).

Changes Summary

Implemented Proposals (4/5)

✅ Proposal #0: Create Command (Commit: 9a52ddc)

  • Separated environment_details.rs into view_data/ subdirectory
  • Moved text_view.rs and json_view.rs into views/ subdirectory
  • Updated module structure with proper re-exports

✅ Proposal #1: Provision Command (Commit: 6539e78)

  • Organized 3 DTOs in view_data/ (provision_details, connection_details, dns_reminder)
  • Organized 2 views in views/ (text_view, json_view)
  • Updated comprehensive module structure

✅ Proposal #2: List Command (Commit: 6cf2966)

  • Moved and renamed environment_list.rs to views/text_view.rs
  • Renamed EnvironmentListView to TextView throughout
  • Updated controller imports

✅ Proposal #3: Show Command (Commit: 68676e1)

  • Renamed environment_info/ directory to views/
  • Renamed EnvironmentInfoView to TextView
  • Organized 8 helper view files in consistent structure

❌ Proposal #4: Shared Components (Discarded - Not Needed)

  • Analyzed shared/service_urls/ components
  • Determined current structure is optimal
  • No changes required - clear naming, pure view helpers, well-organized

Directory Structure Achieved

src/presentation/views/commands/
├── create/
│   ├── view_data/environment_details.rs       (DTO)
│   └── views/text_view.rs, json_view.rs       (Views)
├── provision/
│   ├── view_data/provision_details.rs, ...    (DTOs)
│   └── views/text_view.rs, json_view.rs       (Views)
├── list/
│   └── views/text_view.rs                     (View only)
├── show/
│   └── views/mod.rs, basic.rs, ...            (Views only)
└── shared/
    └── service_urls/                          (No change - already optimal)

Testing & Quality Assurance

  • ✅ All 2238 tests passing (5 ignored)
  • ✅ All linters passing (markdown, yaml, toml, cspell, clippy, rustfmt, shellcheck)
  • ✅ No unused dependencies (cargo machete)
  • ✅ Module-level documentation updated
  • ✅ 9 commits with clean history

Benefits

  • Consistency: All commands now follow the Strategy Pattern with clear DTO + View separation where applicable
  • Scalability: Easy to add JSON views to remaining commands (show, run, list)
  • Discoverability: Clear directory structure makes it obvious where new code belongs
  • Maintainability: Consistent patterns reduce cognitive load for contributors

Related Documentation

Next Steps

This refactoring provides the foundation for EPIC #348 tasks 12.3-12.5:

  • Add JSON output to show command
  • Add JSON output to run command
  • Add JSON output to list command

Branch: refactor/separate-view-data-from-views
Commits: 9 total (8 implementation + 1 plan update)
Status: Ready for review

Analyzed shared/service_urls/ components and determined:
- Current structure is optimal (clear naming, well-organized)
- Components are pure view helpers (no data/view separation needed)
- Proposed rename would add churn without meaningful benefit

Updated refactor plan:
- Marked Proposal 4 as discarded (not needed)
- Updated progress tracking (4 complete, 1 discarded)
- Updated completion criteria and timeline
- Marked Phase 2 as complete
@josecelano josecelano self-assigned this Feb 16, 2026
@josecelano

Copy link
Copy Markdown
Member Author

ACK e915c25

@josecelano josecelano merged commit a0edec7 into main Feb 16, 2026
39 checks passed
josecelano added a commit that referenced this pull request Feb 17, 2026
09dfda7 docs: [#355] add JSON output format documentation for show command (Jose Celano)
9d29aad feat: [#355] add JSON output to show command (Jose Celano)

Pull request description:

  ## Overview

  Adds JSON output format support to the `show` command, enabling machine-readable environment information for automation and scripting. This implements [#355](#355) and contributes to Phase 1 of EPIC [#348](#348) (JSON output for high-value commands).

  ## Changes

  ### Implementation

  - **DTOs with Serialization** (Application Layer):
    - Added `#[derive(Serialize)]` to all show command DTOs:
      - `EnvironmentInfo`, `InfrastructureInfo`
      - `ServiceInfo`, `LocalhostServiceInfo`, `TlsDomainInfo`
      - `PrometheusInfo`, `GrafanaInfo`

  - **JsonView** (Presentation Layer):
    - Created `JsonView` struct with `render()` method using `serde_json::to_string_pretty()`
    - Reorganized `views/` module: `TextView` in separate file, new `mod.rs` with re-exports
    - Comprehensive unit tests for all state variations

  - **Controller Wiring**:
    - Updated `show` controller to accept `output_format: OutputFormat`
    - Added view selection logic: `match output_format { Text => TextView, Json => JsonView }`
    - Updated router to pass `context.output_format()` through

  ### Documentation

  - Updated [`docs/user-guide/commands/show.md`](docs/user-guide/commands/show.md):
    - Added `--output-format` option documentation
    - JSON examples for Provisioned and Running states
    - Automation examples using `jq` for JSON parsing

  ## Usage

  ```bash
  # Human-readable text output (default)
  torrust-tracker-deployer show my-env

  # Machine-readable JSON output
  torrust-tracker-deployer show my-env --output-format json
  torrust-tracker-deployer show my-env -o json
  ```

  ## Examples

  ### Provisioned State (JSON)

  ```json
  {
    "name": "my-environment",
    "state": "Provisioned",
    "provider": "LXD",
    "created_at": "2026-02-16T17:56:43.788700279Z",
    "infrastructure": {
      "instance_ip": "10.140.190.85",
      "ssh_port": 22,
      "ssh_user": "torrust",
      "ssh_key_path": "/home/user/.ssh/torrust_key"
    },
    "services": null,
    "prometheus": null,
    "grafana": null,
    "state_name": "provisioned"
  }
  ```

  ### Running State (JSON)

  ```json
  {
    "name": "my-environment",
    "state": "Running",
    "services": {
      "udp_trackers": ["udp://udp.tracker.local:6969/announce"],
      "https_http_trackers": ["https://http.tracker.local/announce"],
      "api_endpoint": "https://api.tracker.local/api",
      "api_uses_https": true,
      "health_check_url": "https://health.tracker.local/health_check",
      "tls_domains": [...]
    },
    "prometheus": {
      "access_note": "Internal only (localhost:9090)"
    },
    "grafana": {
      "url": "https://grafana.tracker.local/",
      "uses_https": true
    },
    "state_name": "running"
  }
  ```

  ### Automation Example

  ```bash
  # Extract API URL and check tracker stats
  API_URL=$(torrust-tracker-deployer show my-env -o json | \
      jq -r '.services.api_endpoint // empty')

  if [ -n "$API_URL" ]; then
      curl "$API_URL/stats"
  fi
  ```

  ## Testing

  ### Unit Tests

  - ✅ All 398 tests passing, 89 ignored, 0 failed
  - New tests in `json_view.rs`:
    - `it_should_render_json_for_created_state`
    - `it_should_render_json_for_provisioned_state`
    - `it_should_produce_valid_json` (validates with `serde_json::from_str`)
    - 2 doc tests demonstrating API usage

  ### Manual Testing

  Verified with real environments:

  ```bash
  # Provisioned state - tested with text-output-test
  cargo run -- show text-output-test -o json | python3 -m json.tool
  ✓ Valid JSON structure
  ✓ Nulls for services/prometheus/grafana (expected for Provisioned)

  # Running state - tested with lxd-local-https-example
  cargo run -- show lxd-local-https-example -o json | python3 -m json.tool
  ✓ Valid JSON structure
  ✓ Complete service information
  ✓ All tracker endpoints present
  ```

  ### Linters

  - ✅ All linters passing: markdown, yaml, toml, cspell, clippy, rustfmt, shellcheck
  - ✅ No clippy warnings with `-- -D warnings`

  ## Architecture

  Follows the Strategy Pattern established in:
  - [#349](#349) - JSON output for `create` command
  - [#352](#352) - JSON output for `provision` command

  Benefits from refactor PR [#354](#354) which properly organized the views module structure.

  ## Roadmap Progress

  - [x] Task 12.1: `create` command JSON output (#349) ✅ Merged
  - [x] Task 12.2: `provision` command JSON output (#352) ✅ Merged
  - [x] **Task 12.3: `show` command JSON output (#355)** ✅ This PR
  - [ ] Task 12.4: `run` command JSON output
  - [ ] Task 12.5: `list` command JSON output

  ## Related Issues

  - Implements: #355 (Add JSON output to show command)
  - Part of: #348 (EPIC: Add JSON output for automated workflows)
  - Parent Refactor: #354 (Separate view data from views in presentation layer)

  ## Checklist

  - [x] Implementation complete (DTOs, JsonView, controller wiring)
  - [x] Unit tests added and passing
  - [x] Manual testing with real environments
  - [x] Documentation updated
  - [x] All linters passing
  - [x] Follows Strategy Pattern from #349 and #352

ACKs for top commit:
  josecelano:
    ACK 09dfda7

Tree-SHA512: 2414b28e4cb84daa7195fe3e3088edff27f972502438cd2811df9b74054c53aa5301c6d7462f501e9cd7567e45f396133010337683a0be2792d93ae72829c3a4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant