-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Overview
Currently, the UserOutput type is instantiated in multiple places throughout the presentation layer, which can lead to inconsistent user-facing messages with different verbosity levels, styles, or formatting. This task centralizes UserOutput instantiation in the application bootstrap phase and passes it down through the command execution chain using dependency injection via Arc<UserOutput>.
Problem: Decentralized construction creates inconsistency risk in:
src/presentation/commands/mod.rs- Error handler creates its own instancesrc/presentation/commands/create/subcommands/template.rs- Template generation creates its own instancesrc/presentation/commands/context.rs- Command context creates its own instance
Solution: Bootstrap a single UserOutput instance during application initialization and pass it down using Arc<UserOutput> for shared ownership.
Specification
See detailed specification: docs/issues/107-centralize-user-output-via-dependency-injection.md
🏗️ Architecture Requirements
DDD Layer: Infrastructure (Container), Presentation (usage)
Module Path:
- Container:
src/bootstrap/container.rs(new module) - Bootstrap integration:
src/bootstrap/app.rs(existing) - Presentation layer: Multiple files
Pattern: Dependency Injection Container + Function Parameter Threading
Module Structure Requirements
- Create
Containertype insrc/bootstrap/container.rsfor centralized service initialization - Bootstrap container in
src/bootstrap/app.rsafter logging initialization - Thread
Arc<UserOutput>through presentation layer function signatures - Update existing
UserOutputconstruction sites to use injected dependency - Respect layering: Container in bootstrap, usage in presentation
Architectural Constraints
- No global state - Use
Arc<UserOutput>for shared ownership, not global variables - Thread-safe -
UserOutputmust be thread-safe (already is withArc) - Bootstrap only - Container initialization happens once during app startup
- Dependency flow - Bootstrap → Presentation layer only (no reverse dependency)
- Maintain existing behavior - User-facing output behavior must remain unchanged
Anti-Patterns to Avoid
- ❌ Global mutable state - Don't use
static mutorlazy_static!forUserOutput - ❌ Service locator pattern - Don't create a global registry for dependency lookup
- ❌ Hidden dependencies - All functions should explicitly declare
Arc<UserOutput>parameter - ❌ Layer violations - Don't pass container into domain or application layers
Implementation Plan
Phase 1: Create Bootstrap Container (1-2 hours)
- Create
src/bootstrap/container.rswithContainertype - Add
Arc<UserOutput>field toContainer - Implement
new()anduser_output()methods - Update
src/bootstrap/mod.rsto exportContainer - Add unit tests for
Containerconstruction anduser_output()access
Phase 2: Integrate Container in Bootstrap (1 hour)
- Create
Containerinsrc/bootstrap/app.rsafter logging initialization - Pass
container.user_output()topresentation::execute() - Pass
container.user_output()topresentation::handle_error()
Phase 3: Update Presentation Layer Signatures (2-3 hours)
- Update
presentation::execute()signature to acceptArc<UserOutput> - Update
presentation::handle_error()signature to acceptArc<UserOutput> - Update
create::handle_create_command()signature - Update
destroy::handle_destroy_command()signature - Update all subcommand handlers in
create/subcommands/anddestroy/subcommands/
Phase 4: Remove Local UserOutput Constructions (1-2 hours)
- Remove
UserOutput::new()call inpresentation::handle_error() - Remove
UserOutput::new()call increate/subcommands/template.rs - Update
CommandContext::new()to acceptuser_output: Arc<UserOutput>parameter - Update all
CommandContext::new()call sites to pass injecteduser_output - Search codebase for remaining
UserOutput::new()calls and update them
Phase 5: Update Tests (2-3 hours)
- Update all presentation layer tests to create and pass
Arc<UserOutput> - Update command handler tests
- Update subcommand tests
- Verify E2E tests still pass with new signatures
- Add integration test verifying consistent output configuration
Phase 6: Documentation and Cleanup (1 hour)
- Update module documentation in
src/bootstrap/container.rs - Update function documentation for all changed signatures
- Add architectural note to
docs/codebase-architecture.mdabout centralized services - Run pre-commit checks:
./scripts/pre-commit.sh
Acceptance Criteria
Note for Contributors: These criteria define what the PR reviewer will check. Use this as your pre-review checklist before submitting the PR to minimize back-and-forth iterations.
Quality Checks:
- Pre-commit checks pass:
./scripts/pre-commit.sh - All linters pass (markdown, yaml, toml, clippy, rustfmt, shellcheck)
- All unit tests pass
- All E2E tests pass
Architecture Checks:
-
Containertype exists insrc/bootstrap/container.rs -
Containeris bootstrapped insrc/bootstrap/app.rsafter logging initialization - No
UserOutput::new()calls exist in presentation layer (except in tests) - All presentation layer functions accept
Arc<UserOutput>parameter -
CommandContextrequiresArc<UserOutput>in constructor and stores it as a field -
CommandContext::new()acceptsuser_output: Arc<UserOutput>parameter - No global mutable state used for
UserOutput - No service locator pattern used
Behavior Checks:
- User-facing output behavior remains unchanged (no visual differences)
- Default verbosity level (
DEFAULT_VERBOSITY) is used consistently - Error messages still display correctly with help text
- Progress messages still display correctly
- All commands produce consistent output style
Testing Checks:
- Container construction is tested
- Presentation layer functions are tested with injected
UserOutput - Integration test verifies consistent output configuration
- E2E tests pass without modification
Documentation Checks:
- Module documentation explains container purpose and usage
- Function documentation updated for new signatures
- Architecture documentation mentions centralized service pattern
Related
- Parent: [EPIC] User Output Architecture Improvements #102 (Epic: User Output Architecture Improvements)
- Related: Extract Verbosity Filtering Logic #103 (Extract Verbosity Filtering Logic)
- Roadmap: Roadmap #1 (Project Roadmap)
- Specification: docs/issues/107-centralize-user-output-via-dependency-injection.md