detached 9723233

refactor(structure): create DDD directory structure

commit
9723233cf4a6703ef58b6a005a19b451d2ee5139
author
bnema · · 2025-10-31 10:43 UTC
parent
bd3af61
signature
GPG Unverified2B82207D370127A0 The key is unknown
27 files · +391 -0
A docs/architecture.md +391 -0
@@ -0,0 +1,391 @@
1+# ArchUp Architecture - Domain-Driven Design (DDD)
2+
3+## Overview
4+
5+ArchUp has been restructured using Domain-Driven Design (DDD) principles to achieve:
6+- Better testability (domain logic tested without infrastructure)
7+- Clear separation of concerns (business logic isolated from infrastructure)
8+- Improved maintainability (easy to extend without modifying existing code)
9+- Reduced coupling (dependencies point inward)
10+
11+## Core Principles
12+
13+1. **Business logic ONLY in domain** - NO external dependencies (no OS, HTTP, DB, etc.)
14+2. **Domain defines interfaces (Ports)** - Infrastructure implements them (Adapters)
15+3. **Dependencies point INWARD** - Everything depends on domain, domain depends on nothing
16+
17+## Dependency Flow
18+
19+```
20+┌─────────────────────────────────────┐
21+│ User Interface (TUI/CLI) │ ← Entry points
22+├─────────────────────────────────────┤
23+│ Application Layer │ ← Use cases (commands, handlers, services)
24+├─────────────────────────────────────┤
25+│ Domain Layer │ ← Business logic (entities, value objects, rules)
26+├─────────────────────────────────────┤
27+│ Infrastructure Layer │ ← Adapters implementing domain ports
28+└─────────────────────────────────────┘
29+```
30+
31+Dependencies: UI → App → Domain ← Infrastructure
32+
33+## Directory Structure
34+
35+### `/internal/domain/` - Pure Business Logic
36+
37+**NO external dependencies allowed** (except: `context`, `errors`, `fmt`, `time`, `strings`, `github.com/google/uuid`)
38+
39+#### `domain/installation/`
40+- **installation.go** - Installation aggregate root (entity) managing lifecycle
41+- **state.go** - State enum and transition validation
42+- **events.go** - Domain events (InstallationStarted, PhaseCompleted, etc.)
43+- **errors.go** - Domain-specific error types
44+
45+#### `domain/system/`
46+- **config.go** - SystemConfig value object (hostname, locale, timezone, keymap)
47+- **validation.go** - System validation rules
48+- **cpu.go** - CPU detection value object (vendor, microcode)
49+
50+#### `domain/disk/`
51+- **disk.go** - Disk entity (device, size, partitions)
52+- **partition.go** - Partition value object (device, size, filesystem, mount point)
53+- **encryption.go** - Encryption value object (none/LUKS/LUKS-LVM, password requirements)
54+- **layout.go** - Partition layout rules and validation
55+
56+#### `domain/bootloader/`
57+- **bootloader.go** - Bootloader value object (type, configuration)
58+- **limine.go** - Limine-specific configuration and rules
59+- **systemdboot.go** - systemd-boot specific configuration
60+
61+#### `domain/user/`
62+- **user.go** - User entity (username, groups, shell)
63+- **credentials.go** - Credentials value object (password hashing, validation)
64+- **validation.go** - User validation rules (username format, password strength)
65+
66+#### `domain/packages/`
67+- **package.go** - Package value object
68+- **repository.go** - Repository configuration (Arch Linux, AUR, Chaotic-AUR)
69+- **kernel.go** - Kernel choice value object (linux, linux-zen, linux-lts, etc.)
70+
71+#### `domain/ports/` - Hexagonal Architecture Ports
72+**ALL infrastructure interactions via these interfaces**
73+
74+- **filesystem.go** - FileSystem port (Read, Write, Chmod, MkdirAll, etc.)
75+- **executor.go** - CommandExecutor, ChrootExecutor, ScriptExecutor ports
76+- **repository.go** - InstallationRepository port (Save, Load)
77+- **downloader.go** - HTTPClient port (Get, Post)
78+- **logger.go** - Logger port (Info, Warn, Error, Debug)
79+
80+### `/internal/application/` - Use Case Orchestration
81+
82+Glues together domain logic with infrastructure adapters. **Imports domain/** but not **infrastructure/**.
83+
84+#### `application/commands/`
85+Plain data structures (DTOs) representing user intents:
86+- **preflight.go** - PreflightCommand
87+- **partition.go** - PartitionDiskCommand
88+- **install_base.go** - InstallBaseCommand
89+- **configure_system.go** - ConfigureSystemCommand
90+- **install_bootloader.go** - InstallBootloaderCommand
91+- **setup_repos.go** - SetupRepositoriesCommand
92+- **post_install.go** - PostInstallCommand
93+
94+#### `application/handlers/`
95+Command handlers implementing use cases. Each handler:
96+1. Receives a command (DTO)
97+2. Uses ports to gather system info
98+3. Creates domain objects with validation
99+4. Calls domain methods
100+5. Returns result (DTO)
101+
102+- **preflight_handler.go** - Handles PreflightCommand
103+- **partition_handler.go** - Handles PartitionDiskCommand
104+- **install_base_handler.go** - Handles InstallBaseCommand
105+- **configure_system_handler.go** - Handles ConfigureSystemCommand
106+- **bootloader_handler.go** - Handles InstallBootloaderCommand
107+- **repos_handler.go** - Handles SetupRepositoriesCommand
108+- **post_install_handler.go** - Handles PostInstallCommand
109+
110+#### `application/services/`
111+Application services coordinating the overall installation:
112+- **installation_service.go** - Main orchestrator managing all handlers and state
113+- **progress_tracker.go** - Progress tracking with event publishing
114+
115+#### `application/dto/`
116+Data Transfer Objects for communication across boundaries:
117+- **installation_status.go** - InstallationStatus, PhaseStatus
118+- **progress_update.go** - ProgressUpdate for UI subscribers
119+
120+### `/internal/infrastructure/` - Adapters (External System Implementation)
121+
122+Implements domain ports. **Imports domain/** but NOT **application/**.
123+
124+#### `infrastructure/filesystem/`
125+Filesystem port adapters:
126+- **local.go** - LocalFileSystem (implements domain.FileSystem)
127+- **mock.go** - MockFileSystem (for testing)
128+
129+#### `infrastructure/executor/`
130+Command execution adapters:
131+- **shell.go** - ShellExecutor (implements domain.CommandExecutor)
132+- **chroot.go** - ChrootExecutor (implements domain.ChrootExecutor)
133+- **script.go** - ScriptExecutor for mandatory shell scripts
134+- **mock.go** - MockExecutor (for testing)
135+
136+#### `infrastructure/persistence/`
137+Data persistence adapters:
138+- **file_repository.go** - FileRepository (implements domain.InstallationRepository)
139+- **config_file.go** - Config file loader/saver (shell-compatible format)
140+
141+#### `infrastructure/http/`
142+HTTP client adapters:
143+- **client.go** - HTTPClient (implements domain.Downloader)
144+- **mock.go** - MockHTTPClient (for testing)
145+
146+#### `infrastructure/logger/`
147+Logging adapters:
148+- **slog_adapter.go** - SlogAdapter (implements domain.Logger, wraps Go's slog)
149+
150+### `/internal/interfaces/` - Entry Points (Thin Layer)
151+
152+UI/CLI layer. **Imports application/** but minimal domain access.
153+
154+#### `interfaces/tui/`
155+BubbleTea terminal UI application:
156+- **app.go** - Main TUI application
157+
158+#### `interfaces/tui/models/`
159+BubbleTea models (UI state only, no business logic):
160+- **form.go** - Form input model
161+- **installation.go** - Installation progress model
162+- **progress.go** - Progress display model
163+
164+#### `interfaces/tui/views/`
165+Pure presentation layer (rendering):
166+- **form_view.go** - Form rendering
167+- **progress_view.go** - Progress rendering
168+- **summary_view.go** - Summary rendering
169+
170+#### `interfaces/tui/handlers/`
171+UI event handlers (delegate to application services):
172+- **form_handler.go** - Form submission handler
173+- **install_handler.go** - Installation event handler
174+
175+#### `interfaces/cli/` (Future)
176+CLI commands (e.g., using Cobra):
177+- **root.go** - Root command
178+- **install.go** - Install command
179+
180+### `/cmd/archup-installer/`
181+Application entry point with dependency injection:
182+- **main.go** - Wire all dependencies (adapters, handlers, services, TUI)
183+
184+## Architecture Patterns
185+
186+### 1. Aggregate Root (Installation)
187+
188+The `Installation` aggregate manages the entire installation lifecycle:
189+```
190+Installation (aggregate root)
191+├── state: InstallationState
192+├── config: InstallationConfig (value object)
193+├── system: SystemConfig (value object)
194+├── disk: Disk (entity with partitions)
195+├── user: User (entity)
196+└── ...
197+```
198+
199+### 2. Value Objects
200+
201+Immutable, validated objects representing concepts:
202+- `SystemConfig` - hostname, timezone, locale
203+- `Encryption` - encryption type and password requirements
204+- `Credentials` - user password (hashed)
205+- `Kernel` - kernel choice
206+
207+### 3. Ports (Interfaces)
208+
209+Domain defines what external systems must provide:
210+```go
211+// domain/ports/filesystem.go
212+type FileSystem interface {
213+ ReadFile(path string) ([]byte, error)
214+ WriteFile(path string, data []byte, perm os.FileMode) error
215+ Chmod(path string, perm os.FileMode) error
216+ MkdirAll(path string, perm os.FileMode) error
217+}
218+```
219+
220+### 4. Adapters
221+
222+Infrastructure implements ports:
223+```go
224+// infrastructure/filesystem/local.go
225+type LocalFileSystem struct{}
226+
227+func (fs *LocalFileSystem) ReadFile(path string) ([]byte, error) {
228+ return os.ReadFile(path)
229+}
230+// ... implements domain.FileSystem
231+```
232+
233+### 5. Command Handler Pattern
234+
235+Each use case has:
236+1. **Command** (DTO): Input data
237+2. **Handler**: Orchestrates domain + infrastructure
238+3. **Result** (DTO): Output data
239+
240+```go
241+// Define command
242+cmd := commands.PreflightCommand{
243+ MountPoint: "/mnt",
244+}
245+
246+// Execute via handler
247+result, err := handler.Handle(ctx, cmd)
248+```
249+
250+## Testing Strategy
251+
252+### Domain Tests
253+- **Where**: `internal/domain/*/` with `_test.go` files
254+- **What**: Pure unit tests of business rules
255+- **How**: No mocks, no external dependencies
256+- **Speed**: Fast (milliseconds)
257+
258+```go
259+func TestSystemConfig_Validation(t *testing.T) {
260+ cfg, err := domain.NewSystemConfig("hostname", "UTC", "en_US.UTF-8", "us")
261+ assert.NoError(t, err)
262+ assert.Equal(t, "hostname", cfg.Hostname())
263+}
264+```
265+
266+### Application Tests
267+- **Where**: `internal/application/*/` with `_test.go` files
268+- **What**: Handler logic with mocked ports
269+- **How**: Use mock implementations (infrastructure/*/mock.go)
270+- **Speed**: Fast (milliseconds)
271+
272+```go
273+func TestPreflightHandler_Handle(t *testing.T) {
274+ mockFS := &filesystem.MockFileSystem{}
275+ mockExec := &executor.MockExecutor{}
276+ handler := handlers.NewPreflightHandler(mockFS, mockExec, logger)
277+
278+ result, err := handler.Handle(ctx, cmd)
279+ assert.NoError(t, err)
280+}
281+```
282+
283+### Integration Tests
284+- **Where**: `test/integration/` or similar
285+- **What**: Full end-to-end scenarios
286+- **How**: Real adapters in VM environment
287+- **Speed**: Slow (minutes), run before commit
288+
289+```go
290+func TestFullInstallation(t *testing.T) {
291+ // End-to-end test in VM
292+ // Uses real filesystem, chroot, pacstrap, etc.
293+}
294+```
295+
296+## Migration Checklist
297+
298+For each phase migrated from shell scripts:
299+
300+1. **Extract business rules** → domain layer
301+2. **Create value objects** with validation
302+3. **Define port interfaces** needed
303+4. **Create command DTO** for input
304+5. **Implement handler** in application layer
305+6. **Create adapters** implementing ports
306+7. **Write domain tests** (pure unit tests)
307+8. **Write application tests** (with mocks)
308+9. **Write integration tests** (in VM)
309+10. **Update TUI** to use handler
310+11. **Test in VM** to verify functionality
311+12. **Document changes**
312+
313+## Development Workflow
314+
315+### Adding a New Feature
316+
317+1. Define domain rules in `domain/*/`
318+2. Create command in `application/commands/`
319+3. Create handler in `application/handlers/`
320+4. Implement adapters in `infrastructure/*/`
321+5. Add UI in `interfaces/tui/`
322+6. Wire in `cmd/archup-installer/main.go`
323+
324+### Fixing a Bug
325+
326+1. Write failing test at appropriate layer
327+2. Fix in domain (if business logic) or adapter (if infrastructure)
328+3. Verify tests pass
329+4. Test in VM if infrastructure-related
330+
331+### Changing Infrastructure
332+
333+1. Create new adapter implementing port
334+2. Update `cmd/archup-installer/main.go` wiring
335+3. Existing domain and application code unchanged
336+4. No need to modify business logic
337+
338+## Important Files
339+
340+- **DDD_REFACTORING_PLAN.md** - Complete refactoring plan with detailed phases
341+- **docs/script-migration.md** - Shell scripts categorization and migration strategy
342+- **internal/domain/ports/** - All port interfaces (critical!)
343+- **cmd/archup-installer/main.go** - Dependency injection wiring
344+
345+## References
346+
347+- Eric Evans - Domain-Driven Design (DDD book)
348+- Hexagonal Architecture (Ports & Adapters)
349+- Clean Architecture by Robert C. Martin
350+- Project DDD Plan: `DDD_REFACTORING_PLAN.md`
351+- Shell Scripts Audit: `docs/script-migration.md`
352+
353+## Key Rules
354+
355+### Domain Layer
356+- ✅ Pure business logic
357+- ✅ Validation of invariants
358+- ✅ Value objects (immutable)
359+- ✅ Entities with identity
360+- ❌ NO external dependencies
361+- ❌ NO file system access
362+- ❌ NO HTTP calls
363+- ❌ NO database access
364+
365+### Application Layer
366+- ✅ Orchestrates domain + infrastructure
367+- ✅ Implements use cases
368+- ✅ Delegates to ports
369+- ✅ Returns DTOs
370+- ❌ NO business logic
371+- ❌ NO direct infrastructure calls
372+- ❌ NO direct UI logic
373+
374+### Infrastructure Layer
375+- ✅ Implements ports
376+- ✅ Handles external systems
377+- ✅ Contains adapters
378+- ❌ NO business logic
379+- ❌ NO use case orchestration
380+
381+### Interfaces Layer
382+- ✅ Handles user input/output
383+- ✅ Delegates to application services
384+- ✅ Pure presentation
385+- ❌ NO business logic
386+- ❌ NO infrastructure details
387+
388+---
389+
390+**Status**: Phase 2 Complete - Directory structure established
391+**Next**: Phase 3 - Define Domain Layer with entities and value objects
@@ -0,0 +1,391 @@
1+# ArchUp Architecture - Domain-Driven Design (DDD)
2+
3+## Overview
4+
5+ArchUp has been restructured using Domain-Driven Design (DDD) principles to achieve:
6+- Better testability (domain logic tested without infrastructure)
7+- Clear separation of concerns (business logic isolated from infrastructure)
8+- Improved maintainability (easy to extend without modifying existing code)
9+- Reduced coupling (dependencies point inward)
10+
11+## Core Principles
12+
13+1. **Business logic ONLY in domain** - NO external dependencies (no OS, HTTP, DB, etc.)
14+2. **Domain defines interfaces (Ports)** - Infrastructure implements them (Adapters)
15+3. **Dependencies point INWARD** - Everything depends on domain, domain depends on nothing
16+
17+## Dependency Flow
18+
19+```
20+┌─────────────────────────────────────┐
21+│ User Interface (TUI/CLI) │ ← Entry points
22+├─────────────────────────────────────┤
23+│ Application Layer │ ← Use cases (commands, handlers, services)
24+├─────────────────────────────────────┤
25+│ Domain Layer │ ← Business logic (entities, value objects, rules)
26+├─────────────────────────────────────┤
27+│ Infrastructure Layer │ ← Adapters implementing domain ports
28+└─────────────────────────────────────┘
29+```
30+
31+Dependencies: UI → App → Domain ← Infrastructure
32+
33+## Directory Structure
34+
35+### `/internal/domain/` - Pure Business Logic
36+
37+**NO external dependencies allowed** (except: `context`, `errors`, `fmt`, `time`, `strings`, `github.com/google/uuid`)
38+
39+#### `domain/installation/`
40+- **installation.go** - Installation aggregate root (entity) managing lifecycle
41+- **state.go** - State enum and transition validation
42+- **events.go** - Domain events (InstallationStarted, PhaseCompleted, etc.)
43+- **errors.go** - Domain-specific error types
44+
45+#### `domain/system/`
46+- **config.go** - SystemConfig value object (hostname, locale, timezone, keymap)
47+- **validation.go** - System validation rules
48+- **cpu.go** - CPU detection value object (vendor, microcode)
49+
50+#### `domain/disk/`
51+- **disk.go** - Disk entity (device, size, partitions)
52+- **partition.go** - Partition value object (device, size, filesystem, mount point)
53+- **encryption.go** - Encryption value object (none/LUKS/LUKS-LVM, password requirements)
54+- **layout.go** - Partition layout rules and validation
55+
56+#### `domain/bootloader/`
57+- **bootloader.go** - Bootloader value object (type, configuration)
58+- **limine.go** - Limine-specific configuration and rules
59+- **systemdboot.go** - systemd-boot specific configuration
60+
61+#### `domain/user/`
62+- **user.go** - User entity (username, groups, shell)
63+- **credentials.go** - Credentials value object (password hashing, validation)
64+- **validation.go** - User validation rules (username format, password strength)
65+
66+#### `domain/packages/`
67+- **package.go** - Package value object
68+- **repository.go** - Repository configuration (Arch Linux, AUR, Chaotic-AUR)
69+- **kernel.go** - Kernel choice value object (linux, linux-zen, linux-lts, etc.)
70+
71+#### `domain/ports/` - Hexagonal Architecture Ports
72+**ALL infrastructure interactions via these interfaces**
73+
74+- **filesystem.go** - FileSystem port (Read, Write, Chmod, MkdirAll, etc.)
75+- **executor.go** - CommandExecutor, ChrootExecutor, ScriptExecutor ports
76+- **repository.go** - InstallationRepository port (Save, Load)
77+- **downloader.go** - HTTPClient port (Get, Post)
78+- **logger.go** - Logger port (Info, Warn, Error, Debug)
79+
80+### `/internal/application/` - Use Case Orchestration
81+
82+Glues together domain logic with infrastructure adapters. **Imports domain/** but not **infrastructure/**.
83+
84+#### `application/commands/`
85+Plain data structures (DTOs) representing user intents:
86+- **preflight.go** - PreflightCommand
87+- **partition.go** - PartitionDiskCommand
88+- **install_base.go** - InstallBaseCommand
89+- **configure_system.go** - ConfigureSystemCommand
90+- **install_bootloader.go** - InstallBootloaderCommand
91+- **setup_repos.go** - SetupRepositoriesCommand
92+- **post_install.go** - PostInstallCommand
93+
94+#### `application/handlers/`
95+Command handlers implementing use cases. Each handler:
96+1. Receives a command (DTO)
97+2. Uses ports to gather system info
98+3. Creates domain objects with validation
99+4. Calls domain methods
100+5. Returns result (DTO)
101+
102+- **preflight_handler.go** - Handles PreflightCommand
103+- **partition_handler.go** - Handles PartitionDiskCommand
104+- **install_base_handler.go** - Handles InstallBaseCommand
105+- **configure_system_handler.go** - Handles ConfigureSystemCommand
106+- **bootloader_handler.go** - Handles InstallBootloaderCommand
107+- **repos_handler.go** - Handles SetupRepositoriesCommand
108+- **post_install_handler.go** - Handles PostInstallCommand
109+
110+#### `application/services/`
111+Application services coordinating the overall installation:
112+- **installation_service.go** - Main orchestrator managing all handlers and state
113+- **progress_tracker.go** - Progress tracking with event publishing
114+
115+#### `application/dto/`
116+Data Transfer Objects for communication across boundaries:
117+- **installation_status.go** - InstallationStatus, PhaseStatus
118+- **progress_update.go** - ProgressUpdate for UI subscribers
119+
120+### `/internal/infrastructure/` - Adapters (External System Implementation)
121+
122+Implements domain ports. **Imports domain/** but NOT **application/**.
123+
124+#### `infrastructure/filesystem/`
125+Filesystem port adapters:
126+- **local.go** - LocalFileSystem (implements domain.FileSystem)
127+- **mock.go** - MockFileSystem (for testing)
128+
129+#### `infrastructure/executor/`
130+Command execution adapters:
131+- **shell.go** - ShellExecutor (implements domain.CommandExecutor)
132+- **chroot.go** - ChrootExecutor (implements domain.ChrootExecutor)
133+- **script.go** - ScriptExecutor for mandatory shell scripts
134+- **mock.go** - MockExecutor (for testing)
135+
136+#### `infrastructure/persistence/`
137+Data persistence adapters:
138+- **file_repository.go** - FileRepository (implements domain.InstallationRepository)
139+- **config_file.go** - Config file loader/saver (shell-compatible format)
140+
141+#### `infrastructure/http/`
142+HTTP client adapters:
143+- **client.go** - HTTPClient (implements domain.Downloader)
144+- **mock.go** - MockHTTPClient (for testing)
145+
146+#### `infrastructure/logger/`
147+Logging adapters:
148+- **slog_adapter.go** - SlogAdapter (implements domain.Logger, wraps Go's slog)
149+
150+### `/internal/interfaces/` - Entry Points (Thin Layer)
151+
152+UI/CLI layer. **Imports application/** but minimal domain access.
153+
154+#### `interfaces/tui/`
155+BubbleTea terminal UI application:
156+- **app.go** - Main TUI application
157+
158+#### `interfaces/tui/models/`
159+BubbleTea models (UI state only, no business logic):
160+- **form.go** - Form input model
161+- **installation.go** - Installation progress model
162+- **progress.go** - Progress display model
163+
164+#### `interfaces/tui/views/`
165+Pure presentation layer (rendering):
166+- **form_view.go** - Form rendering
167+- **progress_view.go** - Progress rendering
168+- **summary_view.go** - Summary rendering
169+
170+#### `interfaces/tui/handlers/`
171+UI event handlers (delegate to application services):
172+- **form_handler.go** - Form submission handler
173+- **install_handler.go** - Installation event handler
174+
175+#### `interfaces/cli/` (Future)
176+CLI commands (e.g., using Cobra):
177+- **root.go** - Root command
178+- **install.go** - Install command
179+
180+### `/cmd/archup-installer/`
181+Application entry point with dependency injection:
182+- **main.go** - Wire all dependencies (adapters, handlers, services, TUI)
183+
184+## Architecture Patterns
185+
186+### 1. Aggregate Root (Installation)
187+
188+The `Installation` aggregate manages the entire installation lifecycle:
189+```
190+Installation (aggregate root)
191+├── state: InstallationState
192+├── config: InstallationConfig (value object)
193+├── system: SystemConfig (value object)
194+├── disk: Disk (entity with partitions)
195+├── user: User (entity)
196+└── ...
197+```
198+
199+### 2. Value Objects
200+
201+Immutable, validated objects representing concepts:
202+- `SystemConfig` - hostname, timezone, locale
203+- `Encryption` - encryption type and password requirements
204+- `Credentials` - user password (hashed)
205+- `Kernel` - kernel choice
206+
207+### 3. Ports (Interfaces)
208+
209+Domain defines what external systems must provide:
210+```go
211+// domain/ports/filesystem.go
212+type FileSystem interface {
213+ ReadFile(path string) ([]byte, error)
214+ WriteFile(path string, data []byte, perm os.FileMode) error
215+ Chmod(path string, perm os.FileMode) error
216+ MkdirAll(path string, perm os.FileMode) error
217+}
218+```
219+
220+### 4. Adapters
221+
222+Infrastructure implements ports:
223+```go
224+// infrastructure/filesystem/local.go
225+type LocalFileSystem struct{}
226+
227+func (fs *LocalFileSystem) ReadFile(path string) ([]byte, error) {
228+ return os.ReadFile(path)
229+}
230+// ... implements domain.FileSystem
231+```
232+
233+### 5. Command Handler Pattern
234+
235+Each use case has:
236+1. **Command** (DTO): Input data
237+2. **Handler**: Orchestrates domain + infrastructure
238+3. **Result** (DTO): Output data
239+
240+```go
241+// Define command
242+cmd := commands.PreflightCommand{
243+ MountPoint: "/mnt",
244+}
245+
246+// Execute via handler
247+result, err := handler.Handle(ctx, cmd)
248+```
249+
250+## Testing Strategy
251+
252+### Domain Tests
253+- **Where**: `internal/domain/*/` with `_test.go` files
254+- **What**: Pure unit tests of business rules
255+- **How**: No mocks, no external dependencies
256+- **Speed**: Fast (milliseconds)
257+
258+```go
259+func TestSystemConfig_Validation(t *testing.T) {
260+ cfg, err := domain.NewSystemConfig("hostname", "UTC", "en_US.UTF-8", "us")
261+ assert.NoError(t, err)
262+ assert.Equal(t, "hostname", cfg.Hostname())
263+}
264+```
265+
266+### Application Tests
267+- **Where**: `internal/application/*/` with `_test.go` files
268+- **What**: Handler logic with mocked ports
269+- **How**: Use mock implementations (infrastructure/*/mock.go)
270+- **Speed**: Fast (milliseconds)
271+
272+```go
273+func TestPreflightHandler_Handle(t *testing.T) {
274+ mockFS := &filesystem.MockFileSystem{}
275+ mockExec := &executor.MockExecutor{}
276+ handler := handlers.NewPreflightHandler(mockFS, mockExec, logger)
277+
278+ result, err := handler.Handle(ctx, cmd)
279+ assert.NoError(t, err)
280+}
281+```
282+
283+### Integration Tests
284+- **Where**: `test/integration/` or similar
285+- **What**: Full end-to-end scenarios
286+- **How**: Real adapters in VM environment
287+- **Speed**: Slow (minutes), run before commit
288+
289+```go
290+func TestFullInstallation(t *testing.T) {
291+ // End-to-end test in VM
292+ // Uses real filesystem, chroot, pacstrap, etc.
293+}
294+```
295+
296+## Migration Checklist
297+
298+For each phase migrated from shell scripts:
299+
300+1. **Extract business rules** → domain layer
301+2. **Create value objects** with validation
302+3. **Define port interfaces** needed
303+4. **Create command DTO** for input
304+5. **Implement handler** in application layer
305+6. **Create adapters** implementing ports
306+7. **Write domain tests** (pure unit tests)
307+8. **Write application tests** (with mocks)
308+9. **Write integration tests** (in VM)
309+10. **Update TUI** to use handler
310+11. **Test in VM** to verify functionality
311+12. **Document changes**
312+
313+## Development Workflow
314+
315+### Adding a New Feature
316+
317+1. Define domain rules in `domain/*/`
318+2. Create command in `application/commands/`
319+3. Create handler in `application/handlers/`
320+4. Implement adapters in `infrastructure/*/`
321+5. Add UI in `interfaces/tui/`
322+6. Wire in `cmd/archup-installer/main.go`
323+
324+### Fixing a Bug
325+
326+1. Write failing test at appropriate layer
327+2. Fix in domain (if business logic) or adapter (if infrastructure)
328+3. Verify tests pass
329+4. Test in VM if infrastructure-related
330+
331+### Changing Infrastructure
332+
333+1. Create new adapter implementing port
334+2. Update `cmd/archup-installer/main.go` wiring
335+3. Existing domain and application code unchanged
336+4. No need to modify business logic
337+
338+## Important Files
339+
340+- **DDD_REFACTORING_PLAN.md** - Complete refactoring plan with detailed phases
341+- **docs/script-migration.md** - Shell scripts categorization and migration strategy
342+- **internal/domain/ports/** - All port interfaces (critical!)
343+- **cmd/archup-installer/main.go** - Dependency injection wiring
344+
345+## References
346+
347+- Eric Evans - Domain-Driven Design (DDD book)
348+- Hexagonal Architecture (Ports & Adapters)
349+- Clean Architecture by Robert C. Martin
350+- Project DDD Plan: `DDD_REFACTORING_PLAN.md`
351+- Shell Scripts Audit: `docs/script-migration.md`
352+
353+## Key Rules
354+
355+### Domain Layer
356+- ✅ Pure business logic
357+- ✅ Validation of invariants
358+- ✅ Value objects (immutable)
359+- ✅ Entities with identity
360+- ❌ NO external dependencies
361+- ❌ NO file system access
362+- ❌ NO HTTP calls
363+- ❌ NO database access
364+
365+### Application Layer
366+- ✅ Orchestrates domain + infrastructure
367+- ✅ Implements use cases
368+- ✅ Delegates to ports
369+- ✅ Returns DTOs
370+- ❌ NO business logic
371+- ❌ NO direct infrastructure calls
372+- ❌ NO direct UI logic
373+
374+### Infrastructure Layer
375+- ✅ Implements ports
376+- ✅ Handles external systems
377+- ✅ Contains adapters
378+- ❌ NO business logic
379+- ❌ NO use case orchestration
380+
381+### Interfaces Layer
382+- ✅ Handles user input/output
383+- ✅ Delegates to application services
384+- ✅ Pure presentation
385+- ❌ NO business logic
386+- ❌ NO infrastructure details
387+
388+---
389+
390+**Status**: Phase 2 Complete - Directory structure established
391+**Next**: Phase 3 - Define Domain Layer with entities and value objects
A internal/application/.gitkeep +0 -0

no textual change.

A internal/application/commands/.gitkeep +0 -0

no textual change.

A internal/application/dto/.gitkeep +0 -0

no textual change.

A internal/application/handlers/.gitkeep +0 -0

no textual change.

A internal/application/services/.gitkeep +0 -0

no textual change.

A internal/domain/.gitkeep +0 -0

no textual change.

A internal/domain/bootloader/.gitkeep +0 -0

no textual change.

A internal/domain/disk/.gitkeep +0 -0

no textual change.

A internal/domain/installation/.gitkeep +0 -0

no textual change.

A internal/domain/packages/.gitkeep +0 -0

no textual change.

A internal/domain/ports/.gitkeep +0 -0

no textual change.

A internal/domain/system/.gitkeep +0 -0

no textual change.

A internal/domain/user/.gitkeep +0 -0

no textual change.

A internal/infrastructure/.gitkeep +0 -0

no textual change.

A internal/infrastructure/executor/.gitkeep +0 -0

no textual change.

A internal/infrastructure/filesystem/.gitkeep +0 -0

no textual change.

A internal/infrastructure/http/.gitkeep +0 -0

no textual change.

A internal/infrastructure/logger/.gitkeep +0 -0

no textual change.

A internal/infrastructure/persistence/.gitkeep +0 -0

no textual change.

A internal/interfaces/.gitkeep +0 -0

no textual change.

A internal/interfaces/cli/.gitkeep +0 -0

no textual change.

A internal/interfaces/mocks/.gitkeep +0 -0

no textual change.

A internal/interfaces/tui/.gitkeep +0 -0

no textual change.

A internal/interfaces/tui/handlers/.gitkeep +0 -0

no textual change.

A internal/interfaces/tui/models/.gitkeep +0 -0

no textual change.

A internal/interfaces/tui/views/.gitkeep +0 -0

no textual change.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 0

    ↑↓ moveenter openesc close