feat: add comprehensive architecture documentation and migration plan for refactor sessions

This commit is contained in:
2026-05-24 15:38:15 +02:00
parent 67f3e60953
commit c168c3b84a
5 changed files with 1334 additions and 0 deletions
+310
View File
@@ -0,0 +1,310 @@
# Migration Plan
## Goal
Refactor the Electron main-process architecture without changing product behavior. The plan is sequential and should be followed in order so future sessions can make progress without reinterpreting the architecture.
## Migration Principles
- Preserve behavior before moving structure.
- Add tests around risky lifecycle behavior before refactoring it.
- Keep the NodeCG runtime model intact.
- Keep Electron minimal.
- Avoid introducing IPC, preload, or renderer code unless required by a concrete feature.
- Prefer small pure functions for paths, URLs, update metadata, asset selection, and navigation policy.
- Rewrite only the degraded areas: updater, lifecycle orchestration, and platform process shutdown.
## Phase 1: Freeze Existing Behavior
Purpose:
Protect current startup, shutdown, provisioning, navigation, and update behavior before extracting modules.
Tasks:
- Add tests for first-run runtime provisioning and relaunch behavior.
- Add tests for loading window and main window ordering.
- Add tests for update scheduling behavior.
- Add tests for shutdown when NodeCG is running.
- Add tests for shutdown when NodeCG is already stopped.
- Add tests for double quit or repeated shutdown calls.
- Add tests for macOS-style activation after windows are closed.
Acceptance criteria:
- Existing tests continue to pass.
- New tests describe current behavior, not the desired future behavior.
- No folder reorganization occurs in this phase.
## Phase 2: Extract Pure Path And URL Logic
Purpose:
Remove deterministic calculations from `main.ts` while keeping Electron side effects in the entrypoint.
Target files:
```text
src/main/app/paths.ts
src/main/config/runtime-config.ts
```
Tasks:
- Extract `userData` path calculation.
- Extract managed runtime path calculation.
- Extract NodeCG dashboard URL construction.
- Extract runtime configuration parsing.
- Keep Electron `app.setPath`, `app.setName`, and lock handling in bootstrap code.
Acceptance criteria:
- Extracted functions are pure.
- Tests cover path and URL edge cases.
- No Electron app object is required to test the extracted logic.
## Phase 3: Introduce ApplicationController
Purpose:
Make lifecycle explicit without redesigning the app.
Target file:
```text
src/main/app/application-controller.ts
```
Required states:
```text
idle
preparing
starting
ready
stopping
stopped
failed
```
Responsibilities:
- Prepare runtime.
- Start NodeCG.
- Wait for readiness.
- Create or reuse windows through a window service.
- Load dashboards only after NodeCG readiness.
- Schedule update checks.
- Handle activation safely.
- Handle shutdown idempotently.
Non-responsibilities:
- Direct process-kill command construction.
- Direct update metadata parsing.
- Direct Electron `BrowserWindow` option construction.
- Business logic inside preload or renderer code.
Acceptance criteria:
- `main.ts` becomes a thin bootstrap.
- Activation uses readiness-aware startup behavior.
- Shutdown is idempotent.
- Tests cover state transitions and failure paths.
## Phase 4: Extract Shutdown Service
Purpose:
Make shutdown behavior predictable and easy to test.
Target files:
```text
src/main/app/shutdown-service.ts
src/main/nodecg/nodecg-process-service.ts
```
Tasks:
- Centralize app shutdown sequencing.
- Ensure NodeCG is stopped before app exit completes.
- Handle repeated shutdown requests.
- Handle process already exited.
- Preserve current quit behavior.
Acceptance criteria:
- Repeated quit calls do not duplicate process termination.
- Tests cover `before-quit`, process exit before shutdown, and shutdown failure logging.
## Phase 5: Rewrite Updater In Small Modules
Purpose:
Replace the fragile updater internals while preserving user-visible behavior.
Target files:
```text
src/main/updates/update-service.ts
src/main/updates/update-config.ts
src/main/updates/update-download.ts
src/main/updates/update-schema.ts
```
Tasks:
- Define a runtime schema for update metadata.
- Validate remote JSON before using it.
- Validate update asset URLs.
- Restrict protocols to `https:` unless an explicit local development mode exists.
- Select platform assets through pure functions.
- Download to a safe temporary path.
- Finalize downloads atomically.
- Keep dialog behavior outside fetch and download helpers.
- Correct Spanish encoding issues.
- Add tests for malformed JSON, missing assets, invalid URLs, failed downloads, and cancelled dialogs.
Acceptance criteria:
- Invalid update metadata fails closed.
- Downloaded files cannot escape the intended temporary directory.
- User-facing strings render correctly.
- Existing update behavior is preserved where valid metadata is provided.
## Phase 6: Isolate Platform Process Termination
Purpose:
Keep OS-specific process-kill details outside NodeCG lifecycle logic.
Target file:
```text
src/main/nodecg/platform-process-killer.ts
```
Tasks:
- Implement a small interface for terminating process trees.
- Provide Windows and POSIX implementations.
- Validate that Windows PIDs are numeric before command construction.
- Avoid spreading platform conditionals through the process manager.
- Test command selection and error handling.
Acceptance criteria:
- `taskkill` construction is isolated.
- POSIX process termination is isolated.
- Process manager tests no longer need to know platform command details.
## Phase 7: Harden Electron Window Policy
Purpose:
Make Electron browser security explicit and testable.
Target files:
```text
src/main/windows/window-service.ts
src/main/windows/navigation-policy.ts
```
Tasks:
- Explicitly set `webSecurity: true`.
- Keep `nodeIntegration: false`.
- Keep `contextIsolation: true`.
- Keep `sandbox: true`.
- Add a permission request handler that denies by default.
- Define devtools policy by environment.
- Keep navigation allowlist limited to approved local NodeCG origins.
- Prevent unexpected new-window behavior.
- Review CSP options for NodeCG-hosted content where feasible.
Acceptance criteria:
- BrowserWindow options are covered by tests.
- Permission requests are denied unless explicitly allowed.
- Navigation policy has tests for allowed and blocked origins.
## Phase 8: Normalize Scripts And Shared Constants
Purpose:
Reduce packaging fragility without changing the build system.
Targets:
```text
scripts/
src/main/config/
```
Tasks:
- Make repository layout assumptions explicit.
- Validate required paths before build work starts.
- Share package/runtime constants where reasonable.
- Improve error messages for missing parent project or missing NodeCG runtime.
- Keep scripts simple `.mjs` utilities.
Acceptance criteria:
- CI failures explain missing external dependencies clearly.
- Local build behavior remains unchanged.
- No new framework is introduced.
## Phase 9: Reorganize Folders Last
Purpose:
Move files only after behavior is protected and new ownership is clear.
Target structure:
```text
src/main/
app/
config/
windows/
nodecg/
updates/
logging/
src/shared/
```
Tasks:
- Move files into target folders after tests pass.
- Update imports mechanically.
- Avoid changing logic during moves.
- Run typecheck, tests, and lint after each group of moves.
Acceptance criteria:
- File moves are behavior-neutral.
- Test output remains unchanged.
- Imports reflect the target architecture.
## Required Verification Per Phase
Run the relevant subset while iterating, then run all checks before closing a phase:
```text
npm run typecheck
npm test
npm run lint
```
## Stop Conditions
Stop and reassess if:
- A change requires adding IPC without a product need.
- A refactor changes the NodeCG runtime model.
- Update validation requires a product or release-server decision.
- CSP changes break NodeCG dashboards.
- CI requires external repository layout decisions outside this package.