# NexusGuard Config Architecture

## TL;DR

> Unified config system for non-Docker deployment: `/etc/nexusguard/nexusguard.conf` (shell-sourceable), install/uninstall scripts, systemd service, and nginx runtime config injection for dashboard.
> 
> **Deliverables**:
> - Server-core config file loader
> - Dashboard runtime config via nginx
> - Install/uninstall shell scripts
> - Systemd service file
> - Nginx config template
> 
> **Estimated Effort**: Medium
> **Parallel Execution**: YES - 3 waves
> **Critical Path**: Config loader → Dashboard changes → Install scripts → Testing

---

## Context

### Original Request
User wants unified config architecture for non-Docker deployment. Currently config is split:
- Server-core: env vars from docker-compose `.env`
- Dashboard: `VITE_API_BASE_URL` baked at build time
- Device-agent: CLI args (no change needed)

### Interview Summary
**Key Discussions**:
- Config format: Shell-sourceable (export KEY=VALUE)
- Config location: `/etc/nexusguard/nexusguard.conf`
- Structure: Server-core + dashboard-ui share ONE config file
- Device-agent: No config file (uses CLI args)
- Dashboard: Runtime config via nginx template (window.__CONFIG__)
- Docker: Keep env vars unchanged
- Non-Docker: Read from nexusguard.conf
- Install: Shell script (nexusguard-install.sh)
- Uninstall: Shell script (nexusguard-uninstall.sh)
- Systemd: Service file for server-core

**Research Findings**:
- Server-core config loading: `internal/config/config.go` reads env vars via `os.Getenv()`
- Dashboard config: `src/services/api.ts` uses `import.meta.env.VITE_API_BASE_URL`
- Existing patterns: Device-agent's `install_agent.sh` and `sys-bridge.service`
- Real server: 172.20.8.191 for testing

### Metis Review
**Identified Gaps** (addressed):
- Config file path should be overridable via `NEXUSGUARD_CONF` env var
- nginx can't source bash files → use `envsubst` with template
- Secrets in conf file need `chmod 600` permissions
- Config loading order: conf file → env vars → defaults
- Install script must be idempotent
- Dashboard `window.__CONFIG__` timing: script tag MUST appear before Vue bundle
- Edge cases: empty values, spaces, special characters, BOM, Windows line endings

---

## Work Objectives

### Core Objective
Implement unified config system for non-Docker NexusGuard deployment with `/etc/nexusguard/nexusguard.conf`, install/uninstall scripts, and nginx runtime config injection.

### Concrete Deliverables
- `apps/server-core/internal/config/config_loader.go` - Config file loader
- `apps/server-core/internal/config/config_test.go` - Unit tests
- `apps/server-core/main.go` - Updated to call config loader
- `apps/dashboard-ui/src/services/api.ts` - Runtime config support
- `apps/dashboard-ui/nginx.conf.template` - Nginx config template
- `nexusguard-install.sh` - Install script
- `nexusguard-uninstall.sh` - Uninstall script
- `apps/server-core/nexusguard-server.service` - Systemd service file

### Definition of Done
- [x] Server-core reads config from `/etc/nexusguard/nexusguard.conf`
- [x] Dashboard reads runtime config from nginx-injected `window.__CONFIG__`
- [x] Install script copies binaries, creates config, sets up systemd, configures nginx
- [x] Uninstall script stops service, removes files, reloads nginx
- [x] All unit tests pass
- [x] Tested on real server (172.20.8.191)

### Must Have
- Config file loading with fallback to env vars
- Dashboard runtime config injection via nginx
- Idempotent install/uninstall scripts
- Secure config file permissions (chmod 600)
- Systemd service with restart on failure

### Must NOT Have (Guardrails)
- **NEVER** modify Docker behavior (docker-compose.yml, Dockerfiles stay unchanged)
- **NEVER** touch device-agent (uses CLI args, not config file)
- **NEVER** add PostgreSQL/Redis installation to install script
- **NEVER** add TLS/HTTPS setup to install script
- **NEVER** add auto-reload on config changes
- **NEVER** add config file validation (schema)
- **NEVER** add log rotation or monitoring
- **NEVER** add multi-server deployment support
- **NEVER** add `nexusguard-ctl` management CLI

---

## Verification Strategy

> **ZERO HUMAN INTERVENTION** - ALL verification is agent-executed. No exceptions.

### Test Decision
- **Infrastructure exists**: YES (Go tests for server-core, npm for dashboard)
- **Automated tests**: YES (Tests-after)
- **Framework**: Go testing (server-core), no framework for dashboard (manual verification)

### QA Policy
Every task MUST include agent-executed QA scenarios.
Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`.

- **Go code**: Use `go test` - Run tests, assert pass
- **Shell scripts**: Use `bash` - Run script, verify exit code and file creation
- **Config loading**: Use Go test with temp files
- **Nginx config**: Use `nginx -t` to validate syntax
- **Real server**: SSH to 172.20.8.191 and test

---

## Execution Strategy

### Parallel Execution Waves

```
Wave 1 (Start Immediately - foundation):
├── Task 1: Config file loader for server-core [deep]
├── Task 2: Dashboard runtime config support [quick]
└── Task 3: Nginx config template [quick]

Wave 2 (After Wave 1 - scripts):
├── Task 4: Install script (depends: 1, 2, 3) [deep]
├── Task 5: Uninstall script (depends: 4) [quick]
└── Task 6: Systemd service file (depends: 1) [quick]

Wave FINAL (After ALL tasks):
├── Task F1: Plan compliance audit (oracle)
├── Task F2: Code quality review (unspecified-high)
├── Task F3: Real manual QA on server 172.20.8.191 (unspecified-high)
└── Task F4: Scope fidelity check (deep)
```

### Dependency Matrix

| Task | Depends On | Blocks |
|------|-----------|--------|
| 1 | None | 4, 6 |
| 2 | None | 4 |
| 3 | None | 4 |
| 4 | 1, 2, 3 | F1-F4 |
| 5 | 4 | F1-F4 |
| 6 | 1 | F1-F4 |

### Agent Dispatch Summary

- **Wave 1**: 3 tasks - T1 → `deep`, T2 → `quick`, T3 → `quick`
- **Wave 2**: 3 tasks - T4 → `deep`, T5 → `quick`, T6 → `quick`
- **FINAL**: 4 tasks - F1 → `oracle`, F2 → `unspecified-high`, F3 → `unspecified-high`, F4 → `deep`

---

## TODOs

- [x] 1. Config file loader for server-core

  **What to do**:
  - Create `apps/server-core/internal/config/config_loader.go`
  - Implement `LoadConfFile(path string)` function
  - Parse shell-sourceable format (export KEY=VALUE)
  - Handle edge cases: comments (#), empty lines, spaces, Windows line endings (\r\n), BOM
  - Skip malformed lines (no = sign)
  - Trim whitespace around keys and values
  - Call `os.Setenv()` for each valid key
  - Return error if file doesn't exist (but don't fatal)
  - Support path override via `NEXUSGUARD_CONF` env var
  - Default path: `/etc/nexusguard/nexusguard.conf`

  **Must NOT do**:
  - Don't modify existing `config.Load()` function
  - Don't add external dependencies (use stdlib only)
  - Don't make config loading fatal (log warning if file missing)

  **Recommended Agent Profile**:
  - **Category**: `deep`
  - **Skills**: []
  - **Reason**: Go code, requires understanding of existing config pattern

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 1 (with Tasks 2, 3)
  - **Blocks**: Tasks 4, 6
  - **Blocked By**: None

  **References**:
  - `apps/server-core/internal/config/config.go:25-55` - Existing config loading pattern
  - `apps/server-core/main.go:176` - Where config.Load() is called
  - `apps/device-agent/scripts/install_agent.sh` - Shell script pattern to follow

  **Acceptance Criteria**:
  - [x] File created: `apps/server-core/internal/config/config_loader.go`
  - [x] Function `LoadConfFile(path string) error` exists
  - [x] Parses `export KEY=VALUE` format
  - [x] Skips comments (#) and empty lines
  - [x] Handles Windows line endings (\r\n)
  - [x] Trims whitespace around keys and values
  - [x] Calls `os.Setenv()` for each valid key
  - [x] Returns error for missing file (non-fatal)
  - [x] Supports `NEXUSGUARD_CONF` env var override

  **QA Scenarios**:

  ```
  Scenario: Parse valid config file
    Tool: Bash (go test)
    Preconditions: None
    Steps:
      1. Create temp file with: export JWT_SECRET=test123\nexport SERVER_SALT=salt456\nexport DB_HOST=customhost
      2. Call LoadConfFile(tempPath)
      3. Assert os.Getenv("JWT_SECRET") == "test123"
      4. Assert os.Getenv("DB_HOST") == "customhost"
    Expected Result: All values set correctly
    Evidence: .sisyphus/evidence/task-1-parse-valid.txt

  Scenario: Handle missing config file
    Tool: Bash (go test)
    Preconditions: None
    Steps:
      1. Call LoadConfFile("/nonexistent/path")
      2. Assert error is returned
      3. Assert no panic or fatal
    Expected Result: Error returned, process continues
    Evidence: .sisyphus/evidence/task-1-missing-file.txt

  Scenario: Skip malformed lines
    Tool: Bash (go test)
    Preconditions: None
    Steps:
      1. Create temp file with: export VALID=yes\nINVALID_LINE\nexport ALSO_VALID=ok
      2. Call LoadConfFile(tempPath)
      3. Assert os.Getenv("VALID") == "yes"
      4. Assert os.Getenv("ALSO_VALID") == "ok"
    Expected Result: Malformed line skipped
    Evidence: .sisyphus/evidence/task-1-malformed-lines.txt

  Scenario: Handle Windows line endings
    Tool: Bash (go test)
    Preconditions: None
    Steps:
      1. Create temp file with: export KEY1=val1\r\nexport KEY2=val2\r\n
      2. Call LoadConfFile(tempPath)
      3. Assert os.Getenv("KEY1") == "val1"
      4. Assert os.Getenv("KEY2") == "val2"
    Expected Result: \r\n handled correctly
    Evidence: .sisyphus/evidence/task-1-windows-endings.txt
  ```

  **Commit**: YES
  - Message: `feat(server-core): add config file loader for /etc/nexusguard/nexusguard.conf`
  - Files: `apps/server-core/internal/config/config_loader.go`
  - Pre-commit: `go test ./internal/config/... -v`

---

- [x] 2. Dashboard runtime config support

  **What to do**:
  - Modify `apps/dashboard-ui/src/services/api.ts`
  - Add TypeScript type declaration for `window.__CONFIG__`
  - Read `window.__CONFIG__?.apiBaseUrl` with fallback to `import.meta.env.VITE_API_BASE_URL`
  - Keep Docker compatibility (VITE_API_BASE_URL still works)
  - Add comment explaining runtime config injection

  **Must NOT do**:
  - Don't remove VITE_API_BASE_URL support (Docker compatibility)
  - Don't change build process
  - Don't add external dependencies

  **Recommended Agent Profile**:
  - **Category**: `quick`
  - **Skills**: []
  - **Reason**: Simple TypeScript change, single file

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 1 (with Tasks 1, 3)
  - **Blocks**: Task 4
  - **Blocked By**: None

  **References**:
  - `apps/dashboard-ui/src/services/api.ts:1-10` - Current API client setup
  - `apps/dashboard-ui/nginx.conf` - Current nginx config

  **Acceptance Criteria**:
  - [x] File modified: `apps/dashboard-ui/src/services/api.ts`
  - [x] `window.__CONFIG__` type declared
  - [x] Runtime config read with fallback to VITE_API_BASE_URL
  - [x] TypeScript compiles without errors

  **QA Scenarios**:

  ```
  Scenario: Runtime config override
    Tool: Bash (manual verification)
    Preconditions: None
    Steps:
      1. Read api.ts file
      2. Verify window.__CONFIG__?.apiBaseUrl is checked first
      3. Verify fallback to import.meta.env.VITE_API_BASE_URL
    Expected Result: Runtime config takes precedence
    Evidence: .sisyphus/evidence/task-2-runtime-config.txt

  Scenario: Docker compatibility
    Tool: Bash (manual verification)
    Preconditions: None
    Steps:
      1. Read api.ts file
      2. Verify VITE_API_BASE_URL fallback exists
    Expected Result: Docker builds still work
    Evidence: .sisyphus/evidence/task-2-docker-compat.txt
  ```

  **Commit**: YES (groups with Task 1)
  - Message: `feat(dashboard): add runtime config support via window.__CONFIG__`
  - Files: `apps/dashboard-ui/src/services/api.ts`

---

- [x] 3. Nginx config template

  **What to do**:
  - Create `apps/dashboard-ui/nginx.conf.template`
  - Use `envsubst` placeholders for runtime config injection
  - Proxy `/api/` to `http://127.0.0.1:${API_PORT}`
  - Serve static SPA from `/usr/share/nexusguard/dashboard`
  - Inject `window.__CONFIG__` script tag before Vue bundle
  - Handle SPA fallback (try_files $uri $uri/ /index.html)
  - Listen on port 80 (or configurable)

  **Must NOT do**:
  - Don't add TLS/HTTPS configuration
  - Don't hardcode API_PORT (use envsubst)
  - Don't modify existing Docker nginx.conf

  **Recommended Agent Profile**:
  - **Category**: `quick`
  - **Skills**: []
  - **Reason**: Simple nginx config template

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 1 (with Tasks 1, 2)
  - **Blocks**: Task 4
  - **Blocked By**: None

  **References**:
  - `apps/dashboard-ui/nginx.conf` - Current Docker nginx config
  - `apps/server-core/main.go:356` - API port default (8080)

  **Acceptance Criteria**:
  - [x] File created: `apps/dashboard-ui/nginx.conf.template`
  - [x] `envsubst` placeholders for `${API_PORT}`, `${API_BASE_URL}`
  - [x] `window.__CONFIG__` injection via `sub_filter` or template
  - [x] SPA fallback configured
  - [x] `nginx -t` validates syntax

  **QA Scenarios**:

  ```
  Scenario: Nginx config syntax
    Tool: Bash
    Preconditions: nginx installed
    Steps:
      1. Run: nginx -t -c /path/to/nginx.conf.template
      2. Assert exit code 0
    Expected Result: Config syntax valid
    Evidence: .sisyphus/evidence/task-3-nginx-syntax.txt

  Scenario: Runtime config injection
    Tool: Bash (manual verification)
    Preconditions: None
    Steps:
      1. Read nginx.conf.template
      2. Verify window.__CONFIG__ injection mechanism exists
      3. Verify it appears before Vue bundle script
    Expected Result: Config injected correctly
    Evidence: .sisyphus/evidence/task-3-config-injection.txt
  ```

  **Commit**: YES (groups with Tasks 1, 2)
  - Message: `feat(dashboard): add nginx config template for runtime config injection`
  - Files: `apps/dashboard-ui/nginx.conf.template`

---

- [x] 4. Install script

  **What to do**:
  - Create `nexusguard-install.sh` at project root
  - Parse arguments (--help, --server-port, --web-port)
  - Check dependencies (nginx, systemctl)
  - Copy server-core binary to `/usr/local/bin/`
  - Copy dashboard dist to `/usr/share/nexusguard/dashboard/`
  - Create `/etc/nexusguard/nexusguard.conf` with template values
  - Set permissions: `chmod 600 /etc/nexusguard/nexusguard.conf`
  - Create systemd service file at `/etc/systemd/system/nexusguard-server.service`
  - Create nginx config at `/etc/nginx/conf.d/nexusguard.conf`
  - Enable and start service
  - Print access URL
  - Handle idempotency (check existing service, skip or overwrite gracefully)

  **Must NOT do**:
  - Don't install PostgreSQL or Redis
  - Don't install nginx (assume pre-installed)
  - Don't configure TLS/HTTPS
  - Don't build from source (expect pre-built binaries)
  - Don't modify Docker behavior

  **Recommended Agent Profile**:
  - **Category**: `deep`
  - **Skills**: []
  - **Reason**: Complex shell script with multiple system interactions

  **Parallelization**:
  - **Can Run In Parallel**: NO
  - **Parallel Group**: Wave 2 (sequential after Wave 1)
  - **Blocks**: Tasks 5, F1-F4
  - **Blocked By**: Tasks 1, 2, 3

  **References**:
  - `apps/device-agent/scripts/install_agent.sh` - Pattern to follow
  - `apps/server-core/nexusguard-server.service` - Systemd template
  - `apps/dashboard-ui/nginx.conf.template` - Nginx config to copy

  **Acceptance Criteria**:
  - [x] File created: `nexusguard-install.sh`
  - [x] `--help` flag shows usage
  - [x] Creates `/etc/nexusguard/nexusguard.conf` with chmod 600
  - [x] Creates systemd service file
  - [x] Creates nginx config
  - [x] Enables and starts service
  - [x] Idempotent (safe to run twice)

  **QA Scenarios**:

  ```
  Scenario: Install --help
    Tool: Bash
    Preconditions: None
    Steps:
      1. Run: bash nexusguard-install.sh --help
      2. Assert exit code 0
      3. Assert usage text displayed
    Expected Result: Help text shown
    Evidence: .sisyphus/evidence/task-4-install-help.txt

  Scenario: Install creates config file
    Tool: Bash
    Preconditions: None
    Steps:
      1. Run: bash nexusguard-install.sh
      2. Assert /etc/nexusguard/nexusguard.conf exists
      3. Assert file permissions are 600
      4. Assert file contains export statements
    Expected Result: Config file created securely
    Evidence: .sisyphus/evidence/task-4-config-created.txt

  Scenario: Install creates systemd service
    Tool: Bash
    Preconditions: None
    Steps:
      1. Run: bash nexusguard-install.sh
      2. Assert /etc/systemd/system/nexusguard-server.service exists
      3. Assert service is enabled
    Expected Result: Systemd service configured
    Evidence: .sisyphus/evidence/task-4-systemd-created.txt

  Scenario: Install idempotency
    Tool: Bash
    Preconditions: None
    Steps:
      1. Run: bash nexusguard-install.sh
      2. Run: bash nexusguard-install.sh (again)
      3. Assert no errors
      4. Assert service still running
    Expected Result: Safe to run multiple times
    Evidence: .sisyphus/evidence/task-4-idempotency.txt
  ```

  **Commit**: YES
  - Message: `feat: add nexusguard-install.sh for non-Docker deployment`
  - Files: `nexusguard-install.sh`
  - Pre-commit: `bash nexusguard-install.sh --help`

---

- [x] 5. Uninstall script

  **What to do**:
  - Create `nexusguard-uninstall.sh` at project root
  - Stop and disable nexusguard-server service
  - Remove `/usr/local/bin/nexusguard-server-core`
  - Remove `/usr/share/nexusguard/dashboard/`
  - Remove `/etc/nexusguard/nexusguard.conf`
  - Remove `/etc/systemd/system/nexusguard-server.service`
  - Remove `/etc/nginx/conf.d/nexusguard.conf`
  - Reload nginx
  - Reload systemd daemon
  - Print confirmation message

  **Must NOT do**:
  - Don't remove PostgreSQL or Redis
  - Don't remove database data
  - Don't remove WireGuard state
  - Don't remove device-agent (separate concern)

  **Recommended Agent Profile**:
  - **Category**: `quick`
  - **Skills**: []
  - **Reason**: Simple cleanup script

  **Parallelization**:
  - **Can Run In Parallel**: NO
  - **Parallel Group**: Wave 2 (after Task 4)
  - **Blocks**: F1-F4
  - **Blocked By**: Task 4

  **References**:
  - `nexusguard-install.sh` - Install script to reverse

  **Acceptance Criteria**:
  - [x] File created: `nexusguard-uninstall.sh`
  - [x] Stops and disables service
  - [x] Removes all installed files
  - [x] Reloads nginx and systemd
  - [x] Preserves database and WireGuard state

  **QA Scenarios**:

  ```
  Scenario: Uninstall removes files
    Tool: Bash
    Preconditions: Install script run first
    Steps:
      1. Run: bash nexusguard-uninstall.sh
      2. Assert /etc/nexusguard/nexusguard.conf does not exist
      3. Assert /etc/systemd/system/nexusguard-server.service does not exist
      4. Assert service is stopped
    Expected Result: All files removed
    Evidence: .sisyphus/evidence/task-5-uninstall-removes.txt

  Scenario: Uninstall preserves data
    Tool: Bash
    Preconditions: Install script run first
    Steps:
      1. Run: bash nexusguard-uninstall.sh
      2. Assert PostgreSQL data still exists
      3. Assert Redis data still exists
    Expected Result: User data preserved
    Evidence: .sisyphus/evidence/task-5-uninstall-preserves.txt
  ```

  **Commit**: YES (groups with Task 4)
  - Message: `feat: add nexusguard-uninstall.sh`
  - Files: `nexusguard-uninstall.sh`

---

- [x] 6. Systemd service file

  **What to do**:
  - Create `apps/server-core/nexusguard-server.service`
  - Use `EnvironmentFile=/etc/nexusguard/nexusguard.conf`
  - Set `Restart=always` and `RestartSec=5`
  - Run as root (needed for nftables/WireGuard)
  - Set working directory to `/usr/local/bin`
  - Add proper logging (journal)
  - Add `After=network.target postgresql.service redis.service`

  **Must NOT do**:
  - Don't hardcode paths (use EnvironmentFile)
  - Don't add Docker-specific settings
  - Don't add resource limits (cgroup)

  **Recommended Agent Profile**:
  - **Category**: `quick`
  - **Skills**: []
  - **Reason**: Simple systemd unit file

  **Parallelization**:
  - **Can Run In Parallel**: YES
  - **Parallel Group**: Wave 2 (with Tasks 4, 5)
  - **Blocks**: F1-F4
  - **Blocked By**: Task 1

  **References**:
  - `apps/device-agent/scripts/sys-bridge.service` - Systemd template

  **Acceptance Criteria**:
  - [x] File created: `apps/server-core/nexusguard-server.service`
  - [x] `EnvironmentFile=/etc/nexusguard/nexusguard.conf`
  - [x] `Restart=always` and `RestartSec=5`
  - [x] Runs as root
  - [x] `After=network.target postgresql.service redis.service`

  **QA Scenarios**:

  ```
  Scenario: Systemd service syntax
    Tool: Bash
    Preconditions: systemd installed
    Steps:
      1. Run: systemd-analyze verify nexusguard-server.service
      2. Assert exit code 0
    Expected Result: Service file valid
    Evidence: .sisyphus/evidence/task-6-systemd-syntax.txt

  Scenario: Environment file configured
    Tool: Bash
    Preconditions: None
    Steps:
      1. Read nexusguard-server.service
      2. Assert EnvironmentFile=/etc/nexusguard/nexusguard.conf exists
    Expected Result: Config file path correct
    Evidence: .sisyphus/evidence/task-6-env-file.txt
  ```

  **Commit**: YES (groups with Tasks 4, 5)
  - Message: `feat: add systemd service file for non-Docker deployment`
  - Files: `apps/server-core/nexusguard-server.service`

---

## Final Verification Wave

- [x] F1. **Plan Compliance Audit** — `oracle`
  Read the plan end-to-end. For each "Must Have": verify implementation exists. For each "Must NOT Have": search codebase for forbidden patterns. Check evidence files exist.
  Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT`

- [x] F2. **Code Quality Review** — `unspecified-high`
  Run `go vet`, `go test`, `npm run build`. Review all changed files for: empty catches, console.log in prod, commented-out code, unused imports. Check AI slop: excessive comments, over-abstraction.
  Output: `Build [PASS/FAIL] | Tests [N pass/N fail] | Files [N clean/N issues] | VERDICT`

- [x] F3. **Real Manual QA on 172.20.8.191** — `unspecified-high`
  SSH to server. Run install script. Verify config file created. Verify systemd service running. Verify nginx serving dashboard. Verify runtime config injection. Test uninstall.
  Output: `Install [PASS/FAIL] | Service [RUNNING/STOPPED] | Dashboard [ACCESSIBLE/INACCESSIBLE] | VERDICT`

- [x] F4. **Scope Fidelity Check** — `deep`
  For each task: read "What to do", read actual diff. Verify 1:1 — everything in spec was built, nothing beyond spec was built. Check "Must NOT do" compliance. Detect cross-task contamination.
  Output: `Tasks [N/N compliant] | Contamination [CLEAN/N issues] | Unaccounted [CLEAN/N files] | VERDICT`

---

## Commit Strategy

- **Task 1**: `feat(server-core): add config file loader for /etc/nexusguard/nexusguard.conf`
- **Task 2-3**: `feat(dashboard): add runtime config support and nginx template`
- **Task 4-6**: `feat: add install/uninstall scripts and systemd service`

---

## Success Criteria

### Verification Commands
```bash
# Server-core config loading
cd apps/server-core && go test ./internal/config/... -v  # Expected: PASS

# Dashboard build
cd apps/dashboard-ui && npm run build  # Expected: succeeds

# Install script
bash nexusguard-install.sh --help  # Expected: shows usage

# Uninstall script
bash nexusguard-uninstall.sh  # Expected: removes files, stops service

# Real server test (172.20.8.191)
ssh root@172.20.8.191 "bash nexusguard-install.sh"  # Expected: success
ssh root@172.20.8.191 "systemctl status nexusguard-server"  # Expected: active (running)
ssh root@172.20.8.191 "curl -s http://localhost/"  # Expected: HTML with window.__CONFIG__
```

### Final Checklist
- [x] All "Must Have" present
- [x] All "Must NOT Have" absent
- [x] All tests pass
- [x] Tested on real server (172.20.8.191)
