# Architecture Rules ## Purpose These rules define the constraints for future refactor sessions. They are intentionally practical: every rule should either protect behavior, reduce Electron risk, or keep the codebase easier to test. ## Core Rules ### Preserve The Product Model - The app remains an Electron main-process wrapper around a local NodeCG runtime. - NodeCG continues to be launched locally. - Dashboards continue to load from approved local HTTP origins. - The managed runtime continues to live under Electron `userData`. - Runtime provisioning must preserve `cfg`, `db`, and `logs`. ### Avoid Unnecessary Architecture - Do not add a renderer architecture unless a user-facing feature requires it. - Do not add a preload script unless desktop APIs must be exposed to web content. - Do not add IPC for organizational neatness. - Do not introduce broad frameworks for lifecycle, dependency injection, logging, or configuration. - Add an abstraction only when it removes real complexity or isolates a risky boundary. ### Keep Behavior Stable - Preserve current behavior before reorganizing files. - Write tests around existing behavior before extracting lifecycle code. - Move files separately from behavior changes. - Run typecheck, tests, and lint after meaningful refactor steps. ## TypeScript Rules - Do not use `any`. - Prefer explicit domain types at module boundaries. - Validate unknown external input before narrowing. - Keep pure functions pure. - Prefer narrow interfaces over large service objects. - Avoid global mutable state outside bootstrap or explicit controllers. ## Electron Rules ### BrowserWindow Defaults Every application window must use secure defaults: ```text nodeIntegration: false contextIsolation: true sandbox: true webSecurity: true ``` Additional rules: - Devtools availability must be controlled by environment or explicit config. - Permission requests must be denied by default. - New-window behavior must be blocked unless explicitly allowed. - Navigation must be allowlisted. - Remote content must not gain Node.js access. ### Preload Rules Current decision: - No preload script is required. If a preload becomes necessary: - Keep it minimal. - Expose APIs only through `contextBridge`. - Do not expose raw `ipcRenderer`. - Do not include business logic in preload. - Validate all payloads crossing the boundary. - Treat preload as part of the security boundary, not as a convenience layer. ### Renderer Rules Current decision: - There is no custom renderer. If a renderer is added later: - It must not assume Node.js access. - It must communicate through typed, validated IPC only. - It must not own NodeCG process lifecycle. - It must not bypass navigation or permission policies. ## IPC Rules Current decision: - No IPC layer is needed. If IPC becomes necessary: - Define all channel names in one module. - Use explicit request and response types. - Validate every payload at runtime. - Use allowlisted handlers only. - Never expose filesystem, process, shell, or update primitives directly. - Never expose raw Electron APIs to web content. - Keep handlers small and delegate to tested services. - Return structured errors instead of throwing raw implementation details across IPC. Example target shape: ```text src/main/ipc/ channels.ts register-handlers.ts validators.ts src/shared/ipc/ types.ts ``` Do not create this structure until IPC is genuinely needed. ## NodeCG Runtime Rules - Keep NodeCG process ownership in the main process. - Launch NodeCG with `ELECTRON_RUN_AS_NODE`. - Validate the runtime installation before launching it. - Wait for HTTP readiness before loading dashboards. - Treat process stdout and stderr as diagnostic information only. - Stop the full process tree on app shutdown. - Keep platform process termination behind an adapter. ## Filesystem Rules - Filesystem behavior must live behind domain modules. - Runtime provisioning must never delete user-owned `cfg`, `db`, or `logs`. - Downloads must stay inside safe temporary directories. - Paths from config, remote metadata, or user-controlled sources must be validated before use. - Avoid scattering path construction across unrelated modules. ## Update Rules - Treat remote update metadata as untrusted. - Validate update JSON with a runtime schema. - Validate asset URLs before download. - Prefer `https:` URLs for production updates. - Fail closed when metadata is malformed. - Download to a safe temporary file. - Finalize downloads atomically. - Keep fetch, validation, download, dialog, and install steps separate. - Fix user-facing encoding issues when touching updater text. - Do not execute downloaded installers unless validation has succeeded. ## Navigation Rules - Allow only expected NodeCG dashboard origins. - Prefer explicit URL parsing over string prefix checks. - Block external navigation by default. - Block unexpected new-window attempts. - Keep navigation policy testable as pure logic where possible. ## Configuration Rules - Parse configuration once. - Keep configuration access centralized. - Avoid reading environment variables throughout the codebase. - Keep runtime defaults explicit. - Ensure build scripts and app runtime agree on shared constants where appropriate. ## Process Rules - Child process management must sit behind a small interface. - Platform-specific kill behavior must be isolated. - Windows process termination must validate numeric PIDs before command construction. - Shutdown must be idempotent. - Repeated quit events must not trigger duplicate process cleanup. ## Testing Rules - Test pure path and URL functions directly. - Test lifecycle states without launching real Electron where possible. - Test updater validation with malformed metadata. - Test navigation allow and block cases. - Test process shutdown edge cases. - Add integration-style coverage only where unit tests cannot represent the Electron behavior. ## Refactor Rules - Do not refactor unrelated modules in the same change. - Do not change formatting across the repository unless requested. - Do not move folders and change behavior in the same step. - Prefer small commits or small reviewable patches. - Leave existing passing tests intact unless the product behavior intentionally changes. ## Security Baseline The secure baseline is: - No Node.js in web content. - No preload unless needed. - No IPC unless needed. - Local navigation only. - Deny permissions by default. - Validate remote update data. - Validate downloaded update assets. - Keep process and filesystem access in main-process services only.