# A-Monster Guard Control Center - Developer Notes & Roadmap

Welcome! This file provides a comprehensive guide for developers and AI agents on the system architecture, completed features, deployment configurations, and manual testing steps.

---

## 1. Project Overview & Architecture

We have built a centralized security management dashboard (**A-Monster Guard Control Center**) that controls remote WordPress websites running the lightweight **A-Monster Guard Agent** plugin.

### Technology Stack
- **Backend:** Laravel 12 (PHP 8.3 compatible), MariaDB, Redis, queueing, scheduler.
- **Frontend:** React 19, TypeScript, Vite, Tailwind CSS v4, Zustand.
- **Security:** HMAC-SHA256 request verification, timestamp checks, nonce caching replay protection, One-Time Deactivation Tokens. No RSA is used.
- **Folder Structure:** Feature-Based Modular Architecture under `app/Features/`.

---

## 2. Completed Phases (1 to 10)

### Phase 1: Project Initialization & Foundations (Completed)
- Bootstrapped Laravel 12 framework at the project root `C:\laragon\www\a-monster-panel` connected to DB `a_monster_panel`.
- Integrated React 19 + TypeScript + Vite + Tailwind CSS v4.
- Installed `laravel/sanctum` and configured stateful session authentication inside `routes/api.php` and `bootstrap/app.php`.
- Created modular `User` and `AuthController` under `app/Features/Auth/`.
- Seeded default administrator credentials:
  - **Email:** `manager@gmail.com`
  - **Password:** `Abc@@123`
- Built frontend layout shells: `LoginForm` component, `DashboardLayout` shell, and Zustand auth stores.

### Phase 2: Core Foundation & Security Middleware (Completed)
- **Database Tables:** Created migrations, models, and clean repository classes for:
  - `telegram_profiles`: Telegram notification channels.
  - `agent_groups`: Group structures for website agents.
  - `activation_keys`: Active keys mapping domain restrictions and expiration dates.
  - `agents`: Registry of clients mapped with UUID primary keys and HMAC secrets.
  - `policies`: Settings payload JSON configs.
- **Agent Handshake API:** Added `/api/v1/agent/activate` to process agent activation requests.
- **HMAC Signatures Middleware:** Created `VerifyAgentSignature` (agent.auth) verifying headers, timestamps, and nonce cache parameters to block replay attacks.

### Phase 3: Core Infrastructure & Agent Engine (Completed)
- **Remote Commands Queue:** Created migrations and models (`Command`) enabling command queueing (e.g. `run_scan`, `emergency_lock`) for agents.
- **Heartbeat & Telemetry API:** Created protected `POST /api/v1/agent/telemetry` which registers agent check-in times and sites metadata, compiles the latest policy configurations, pulls pending commands, and processes command results.
- **Policy Engine Merge Hierarchy:** Resolves configurations recursively: `Global Policy` ➔ `Group Policy` ➔ `Website Override`.
- **Scheduled Agent Offline Checks:** Configured cron task in `routes/console.php` running every minute to detect missed heartbeats and update status to `offline`.

### Phase 4: Control Center Dashboard UI (Completed)
- **Backend CRUD APIs:** Created Secure REST controllers for Groups, Telegram Profiles, Agents, and Policy scope updates protected by Sanctum stateful sessions.
- **Visual Client Screens:** Developed and compiled React 19 pages: `DashboardView`, `AgentsView`, `KeysView`, `TelegramView`, and `PolicyView`.

### Phase 5: WordPress Agent Refactoring (Completed)
- **Autoload Registration:** Updated autoloader mapping class files.
- **HMAC Signer Client:** Created `AMG_Client` carrying out signed API requests containing custom validation header checksums.
- **Telemetry Sync Cron:** Created `AMG_Sync` running via WP-Cron (`amg_telemetry_heartbeat` event) checking in pings, saving policy rules, and running remote task commands. Supports dynamic schedule intervals.
- **Connection Panel:** Replaced all standalone options screens in `class-amg-admin.php` with a single, sleek connection panel showing status credentials, connect form, and deactivation token releases.
- **Deactivation Token Lock:** Updated hooks in `class-amg-core.php` and verification forms in `class-amg-admin.php` to prevent plugin deactivations unless released locally by verification of the one-time token.

### Phase 6: Monitoring & Audits Ingestion (Completed)
- **Database Tables:** Created migrations, models, and repositories for:
  - `audit_logs`: security event lines, login failures, block lists, etc.
  - `malware_reports`: files scanned quotas and malicious files path metadata.
  - `performance_metrics`: page load times, DB query count logs, and slow queries.
- **Ingestion Pipeline:** Built validations inside `TelemetryRequest` and database writes inside `TelemetryProcessingService`.
- **Visual Dashboards:** Built dynamic React 19 views:
  - `AuditLogsView`: Keyword search and severity filtering logs tab.
  - `MalwareReportsView`: Malware threat metadata summaries.
  - `PerformanceView`: Premium custom CSS line columns charting page speeds, queries, and slow DB execution logs.

### Phase 7: Dispatcher Notifications (Completed)
- **Queueable Jobs:** Created `SendTelegramNotification` dispatching HTML alert templates for malware detections, offline agents, and blocked deactivation logs.
- **Fallback Cascading Cascade:** Prioritizes configurations cleanly: `Website Override Policy` ➔ `Assigned Telegram Profile mapping` ➔ `Group Policy settings override` ➔ `Global Default settings`.
- **System Integration:** Hooked trigger dispatches inside offline schedules and telemetry log processors.

### Phase 8: Agent Self-Update Server (Completed)
- **Control Center side:** `UpdateCheckController` dynamically scans the releases directory `storage/app/releases/*.zip` and parses filenames to identify the latest version available.
- **WordPress Agent side:** `AMG_Updater` hooks into WordPress's native core `pre_set_site_transient_update_plugins` to display updates. It caches check-in responses inside transient memory for 6 hours to protect client performance, and hooks outgoing HTTP filesystem calls (`http_request_args`) to inject valid HMAC signature headers automatically.

### Phase 9: Testing Suite (Completed)
- Built **34 feature tests and 142 assertions** checking all aspects of telemetry, encryption, signatures, update endpoints, and priorities.

### Phase 11: Final Architecture Upgrade (Phase 2) & Attack Surface Protection Module (Completed)
- **Advanced Websites Management & Search:** Replaced simple tables with a full Directory View featuring global text search (across websites, domains, UUIDs, IP addresses, tags), filter dropdowns (by group, status), sorting, and pagination.
- **Bulk Operations:** Built POST `/api/v1/agents/bulk` endpoint allowing operators to trigger malware/integrity scans, sync policy revisions, lock down sites, set "Under Attack" configurations, rotate secrets, re-assign groups, and suspend/archive websites in bulk.
- **Attack Surface Protection Module (Control Center & Agent):**
  - **XML-RPC Block:** Added modes (disabled, log_only, disable_all, allow_ips, jetpack) verifying visitor client IP and Automattic user agents.
  - **REST API Restrictions:** Restricted user enumeration requests (`/wp/v2/users`) and sensitive endpoints for unauthorized calls.
  - **Login protection:** Delayed failed attempts, rate-limited wp-login, and genericized error feedback.
- **Admin lockdown:** Restricts administration files by whitelisted IPs.
- **File alterations blocker:** Enforces `DISALLOW_FILE_EDIT` and filters user capabilities (`install_plugins`, `update_core`, etc.) if file modification blocks are enabled.
- **Directory Repair & Uploads lock:** Enforces PHP block rules in `.htaccess` and generates missing index.php files.
- **Diagnostics Dashboard Panels:** Developed website details tabs mapping Overview meta/notes/tags, Module Inheritances (`Reset to Group/Global` configurations), telegram notifications routing, scan threats, Recharts performance memory/speed charting, activation key logs, and raw telemetry diagnostics.

---

## v1.0 Critical Fixes — Phase 1: Client Management Removed (Completed)

Pre-production single-administrator deployment. Multi-tenant client accounts removed:

- Deleted `Client` model, `ClientAdminController`, and `ClientsView.tsx`
- Migration `2026_06_30_000001_remove_clients_system.php` drops `clients` table and `agents.client_id`
- Removed `/api/v1/clients` routes and all frontend/backend references

Hierarchy is now: **Global Policy → Agent Group → Website (Agent)**

---

## v1.0 Critical Fixes — Phase 2: Database Schema Migrations (Completed)

Three additive, reversible migrations applied (batch 5). No columns dropped or modified — only new nullable/defaulted fields added.

| Migration | Table | New Columns |
|-----------|-------|-------------|
| `2026_06_30_000002_add_telegram_tracking_fields` | `telegram_profiles` | `last_notification_at`, `connection_status` (default `unknown`), `verified_at` |
| `2026_06_30_000003_add_disconnect_fields_to_agents` | `agents` | `disconnect_secret_hash`, `disconnect_secret_expires_at`, `disconnect_allowed_at` |
| `2026_06_30_000004_add_2fa_fields_to_users` | `users` | `two_factor_secret`, `two_factor_enabled` (default `false`), `two_factor_recovery_codes`, `two_factor_confirmed_at` |

**Pre-migration state verified:** 1 telegram profile, 5 agents, 1 user — all preserved with safe defaults (`connection_status=unknown`, `two_factor_enabled=false`, disconnect fields null).

**Models updated:** `TelegramProfile`, `Agent`, `User` — fillable + casts aligned to new schema.

**Rollback verified:** All three migrations roll back cleanly via `migrate:rollback --step=3`.

---

## v1.0 Critical Fixes — Phase 3: Telegram Notifications Pipeline (Completed)

Telegram configuration is **database-driven only** — no `.env` fallback for bot token or chat ID.

**Credential resolution (3 levels):**
1. Website-specific policy override (`telegram_bot_token` / `telegram_chat_id` in agent policy)
2. Assigned Telegram Profile (`agent.telegram_profile_id`)
3. Default Telegram Profile (`telegram_profiles.is_default = true`)

**Backend changes:**
- `SendTelegramNotification` — retry (`$tries=3`, `$backoff=[10,30,60]`), simplified resolution, `Log::error` on not configured, updates `last_notification_at` on success, templates for all event types
- `PolicyEngineService` — removed `env('TELEGRAM_*')` from defaults
- `TelemetryProcessingService` — dispatches `login_alert`, `plugin_whitelist_block`, `xmlrpc_block`
- `AgentAdminController` — dispatches on `emergency_lock`, `rotate_secret`, `sync_policy` bulk actions
- `TelegramProfileController` — `sendTest()` and `verify()` endpoints
- `MonitoringAdminController` — Telegram health shows `Not Configured` / `Verified` / `Unverified` / `Failed`

**API routes added:**
- `POST /api/v1/telegram-profiles/{id}/test`
- `POST /api/v1/telegram-profiles/{id}/verify`

**Frontend:** `TelegramView` — Verify Bot, Send Test, connection status badges, last notification timestamp, Not Configured warnings.

---

## v1.0 Critical Fixes — Phase 4: Disconnect Protection (Completed)

Disconnect requires explicit Control Center authorization. Secrets are bcrypt-hashed, one-time, 15-minute TTL.

**Paths:**
- **Path A (Secret):** `POST /api/v1/agents/{id}/allow-disconnect` → admin enters secret in WP plugin → verify → disconnect
- **Path B (Policy):** `POST /api/v1/agents/{id}/enable-disconnect` → nonce delivered on next heartbeat → verify → disconnect

**Agent API (HMAC-signed):**
- `POST /api/v1/agent/verify-disconnect`
- `POST /api/v1/agent/disconnect-complete`
- `POST /api/v1/agent/disconnect-unauthorized`

**Security:** `Hash::make()` storage only, `Hash::check()` verification, all disconnect fields cleared on success, expired secrets rejected and cleared.

**Audit + Telegram events:** `disconnect.authorized`, `disconnect.completed`, `disconnect.unauthorized`, `disconnect.expired`, `disconnect.secret_generated`

**WordPress Agent:** `ConnectionService::disconnect(?string $secret)` blocks without authorization; `ConnectionPage` requires secret input; policy nonce stored from heartbeat.

**E2E verified:** `plugin-dev.test` ↔ `a-monster-panel.test` via `tests/e2e-generate-disconnect-secret.php` + `A-Monster Guard WordPress Agent/tests/e2e-wp-disconnect.php`

---

## v1.0 Critical Fixes — Phase 5: Security Hardening + Optional TOTP 2FA (Completed — Awaiting Approval)

### Disconnect Hardening (Phase 4 additions)

- **Rate limiting:** 5 failed disconnect verification attempts per 15 minutes per agent (`Cache` key `amg:disconnect_fail:{agent_id}`)
- **One-time secret display:** `allow-disconnect` returns the secret only on first generation; subsequent calls while a secret is active return 422 (no retrieval)
- **Post-disconnect cleanup:** `completeDisconnect()` cancels all `pending` commands, clears disconnect authorization fields, and clears `deactivation_token`
- **Fresh reconnect:** `AgentRegistrationService` clears all disconnect/deactivation state and issues a new HMAC secret on re-activation

### Session Security

`.env` (dev) / `.env.example` (production template):

| Variable | Dev | Production (.env.example) |
|----------|-----|---------------------------|
| `SESSION_ENCRYPT` | `true` | `true` |
| `SESSION_SECURE_COOKIE` | `false` | `true` |
| `SESSION_SAME_SITE` | `lax` | `strict` |

### Security Headers Middleware

`app/Http/Middleware/SecurityHeaders.php` — registered globally in `bootstrap/app.php`:

- `X-Content-Type-Options`, `X-Frame-Options`, `X-XSS-Protection`, `Referrer-Policy`, `Permissions-Policy`, CSP, HSTS (HTTPS only)

### Login Security

- Login rate limit: `throttle:5,1` on `POST /api/v1/login`
- All login attempts logged to `admin_security_logs` (IP, user agent, event type)
- Optional `remember` checkbox (no longer forced `true`)
- 2FA challenge flow: credentials → `{ requires_2fa: true }` → `POST /api/v1/2fa/challenge` → session

### Optional TOTP 2FA

**Not required after installation** — `two_factor_enabled` defaults to `false`. Administrator enables from **System → Security Settings**.

**Packages:** `pragmarx/google2fa`, `bacon/bacon-qr-code`

**API routes (authenticated unless noted):**

| Method | Route | Purpose |
|--------|-------|---------|
| GET | `/api/v1/2fa/status` | Current 2FA state |
| POST | `/api/v1/2fa/enable` | Start enrollment (QR + recovery codes, shown once) |
| POST | `/api/v1/2fa/confirm` | Confirm enrollment with TOTP code |
| POST | `/api/v1/2fa/disable` | Disable (password + TOTP required) |
| POST | `/api/v1/2fa/recovery-codes` | Regenerate recovery codes (shown once) |
| POST | `/api/v1/2fa/challenge` | Login 2FA step (public, session-bound) |

### Trusted Devices

| Method | Route | Purpose |
|--------|-------|---------|
| GET | `/api/v1/sessions` | List active sessions |
| DELETE | `/api/v1/sessions/{id}` | Revoke a session |
| DELETE | `/api/v1/sessions` | Revoke all except current |

### Admin Telegram Notifications

`SendAdminTelegramNotification` job (uses default Telegram profile):

- New device login
- 2FA enabled / disabled
- Recovery code regeneration

### Agent Auth Logging

`VerifyAgentSignature` — `Log::warning()` on all failed auth attempts (agent ID, IP, reason)

### Frontend

- `LoginForm.tsx` — 2FA step + recovery code fallback + remember device
- `SecuritySettingsView.tsx` — 2FA enrollment/disable, recovery codes, trusted devices
- `DashboardLayout.tsx` — **Security Settings** nav item under System
- `useAuthStore.ts` — `requires2FA`, `verify2FA` actions

### Phase 5 Verification

| Check | Result |
|-------|--------|
| PHPUnit | **56/56 passing** (261 assertions) |
| npm build | ✅ Pass |
| Manual login | Pending operator verification |
| TOTP enrollment | Pending operator verification |
| Recovery code flow | Covered by `TwoFactorAuthTest` |
| Trusted device flow | Covered by `TwoFactorAuthTest` |
| Session timeout | `SESSION_LIFETIME=120` (configurable) |
| CSRF validation | Sanctum stateful + `ValidateCsrfToken` on admin routes |
| Rate limiting | `AuthSecurityTest`, `DisconnectProtectionTest` |
| Security headers | `SecurityHeadersTest` |

---

## v1.0 Critical Fixes — Phase 6: Configurable Heartbeat Interval (Completed — Approved)

Heartbeat interval is fully policy-driven with a **5-minute global default** and eight supported values: **1, 2, 3, 5, 10, 15, 30, 60 minutes** (60–3600 seconds).

### Backend

- **`HeartbeatInterval`** (`app/Features/Policy/Support/HeartbeatInterval.php`) — allowed values, normalization, labels
- **`PolicyEngineService`** — normalizes `heartbeat_interval` on compile (invalid → 300s default)
- **`PolicyAdminController`** — validates interval on save; returns effective interval + source for agent scope
- **`GET /api/v1/check-in-summary`** — latest `last_heartbeat_at` for dashboard header

### Policy hierarchy

Global (default 300s) → Group → **Website Override wins**

### WordPress Agent

- **`PolicySyncService`** — only allows the eight configured intervals
- **`HeartbeatScheduler`** — clears all existing cron events before rescheduling; skips when interval unchanged; uses global `\wp_*` calls; `HeartbeatService` calls `reschedule()` after each successful sync

### Frontend

- **`HeartbeatIntervalSelect`** — shared dropdown + 1-minute load warning
- **`PolicyView`** — global/group interval dropdown (replaces free-text input)
- **`AgentsView`** — Protection Rules tab + Overview show effective interval and source (Global / Group / Website Override)
- **`timeAgo.ts` + `useTimeTicker`** — human-friendly labels (`Just now`, `45 seconds ago`, etc.) with 15s auto-refresh
- **`DashboardLayout`** — dynamic Last Check-in badge from `/check-in-summary`
- **`DashboardView`** — improved relative timestamps with auto-refresh

### Phase 6 Verification

| Check | Result |
|-------|--------|
| PHPUnit | **81/81 passing** (313 assertions) |
| npm build | ✅ Pass |
| All 8 intervals | `HeartbeatIntervalTest` + `WordPressHeartbeatSchedulerTest` |
| WP-Cron reschedule / no duplicates | `WordPressHeartbeatSchedulerTest` |
| Reconnect heartbeat | `HeartbeatIntervalTest::test_heartbeat_continues_after_reconnect` |
| Policy sync propagation | `HeartbeatIntervalTest::test_telemetry_returns_normalized_policy_interval` |
| Website override precedence | `HeartbeatIntervalTest::test_website_override_takes_precedence_over_global_policy` |

---

## v1.0 Critical Fixes — Phase 7: Dashboard UX Improvements (Completed — Approved)

Live dashboard widgets with efficient polling, composite website health, and a pending-actions table — no full-page reload.

### Backend

- **`WebsiteHealthService`** — evaluates each website as **healthy**, **warning**, **offline**, or **critical** from:
  - Heartbeat recency (offline when `seconds_since > heartbeat_interval × 3`; warning when overdue but still within threshold)
  - Security score (critical &lt; 50; warning 50–74)
  - Pending critical/warning audit alerts (7-day window)
  - Last malware scan (critical if malicious files found; warning if scan missing or &gt; 7 days old)
- **`DashboardAdminController`** — `GET /api/v1/dashboard/refresh` returns summary counts, check-in, website health rows, pending commands, and infrastructure health in one payload
- **`MonitoringAdminController`**
  - `getPendingCommands()` — includes `pending`, `sent`, and `failed` with `started_at`, `completed_at`, `duration_seconds`
  - `getCheckInSummary()` — adds `next_expected_heartbeat_at` and `heartbeat_interval_seconds`
- **`routes/console.php`** — offline scheduler threshold changed to **`heartbeat_interval × 3`** (was `interval + 120`)

### Frontend

- **`DashboardView.tsx`** — polls `/dashboard/refresh` every **15s** (silent refresh; initial load only shows spinner); summary cards, website status table, pending actions table, infrastructure panel
- **`DashboardLayout.tsx`** — header Last Check-in + **Next expected** heartbeat (live `timeAgo` / `timeUntil`)
- **`dashboard.ts`** — health badge styling, command labels, duration/timestamp formatters
- **`timeAgo.ts`** — added `timeUntil()` for upcoming heartbeat display
- **`app.tsx` + `AgentsView.tsx`** — clicking a pending-action row opens Website Details via `onOpenAgent`

### Website health rules (dynamic heartbeat monitoring)

Health is calculated per website from the **effective heartbeat interval** (Website Override → Group → Global Policy) via `HeartbeatHealthCalculator` and `WebsiteHealthService`.

| Status | Missed heartbeats | Label |
|--------|-------------------|-------|
| **Healthy** | 0 | Healthy |
| **Warning** | 1 | Missed 1 Sync |
| **Degraded** | 2 | Missed 2 Syncs |
| **Critical** | ≥ 3 | Missed N Syncs |
| **Offline** | No check-in for `max(12 × interval, 1 hour)` | Offline |

- **Missed count** is derived from `last_heartbeat_at` and interval (not stored in DB); it resets automatically when a new heartbeat arrives.
- **Security factors** (malware, critical alerts, low security score) can still elevate status to **Critical** independently.
- **Dashboard summary** counts degraded sites in the Warning card total (`warning + degraded`).
- **API:** `GET /api/v1/agents/{id}/health`, health block on `GET /api/v1/agents`, dashboard `/dashboard/refresh` website rows.

### Phase 7 Verification (superseded by dynamic heartbeat pass)

| Check | Result |
|-------|--------|
| PHPUnit | **86/86 passing** (348 assertions) |
| npm build | ✅ Pass |
| Dashboard refresh API | `DashboardUxTest::test_dashboard_refresh_returns_live_widgets` |
| Pending commands columns | `DashboardUxTest::test_pending_commands_include_running_and_failed_actions` |
| Offline × 3 threshold | `DashboardUxTest::test_offline_detection_uses_three_times_heartbeat_interval` |
| Critical health | `DashboardUxTest::test_website_health_is_critical_when_malware_is_detected` |
| Next expected heartbeat | `DashboardUxTest::test_check_in_summary_includes_next_expected_heartbeat` |
| Manual UI / live heartbeat | Pending operator verification |

---

## v1.0 Critical Fixes — Phase 8: Infrastructure Health (Completed — Approved)

Live infrastructure monitoring with real checks — no placeholder values. Dashboard polls infrastructure every **30 seconds** via `GET /api/v1/health-status`.

### Backend

- **`InfrastructureHealthService`** — performs live checks for 8 monitors, each returning **status**, **summary**, **last_checked_at**, and **metrics**:
  - **Database** — PDO connection + `SELECT 1` query latency (ms)
  - **Redis** — ping latency when `REDIS_HOST` configured; `not_configured` when unset
  - **Queue** — running workers (cache heartbeats), pending/failed job counts, last processed job
  - **Scheduler** — last successful execution from cache marker; next expected run
  - **Telegram** — live `getMe` bot verification, last notification, last error
  - **Storage** — writable check + free/used bytes at `storage_path()`
  - **Disk Usage** — partition usage % (warning ≥ 80%, error ≥ 95%)
  - **PHP Version** — runtime version; warning if below 8.2
- **`TrackQueueWorkerActivity`** listener — records worker heartbeats on `Looping`, last processed job on `JobProcessed`
- **`InfrastructureMonitorKeys`** — cache keys for scheduler and queue tracking
- **`routes/console.php`** — writes `amg:scheduler:last_run` on every scheduled offline-detection run
- **Migration** — `telegram_profiles.last_error` for persisted Telegram failure messages
- **`GET /api/v1/health-status`** and **`GET /api/v1/dashboard/refresh`** both use the same service

### Frontend

- **`DashboardView.tsx`** — dedicated **30s** poll to `/health-status`; expanded infrastructure cards with status badge, health summary, and last-checked timestamp
- **`dashboard.ts`** — `InfrastructureMonitor` type, `infraStatusClass`, `infraStatusLabel`, `infraDotClass`

### Status levels

| Level | Color | Use |
|-------|-------|-----|
| **Healthy** | Green | Service operating normally |
| **Warning** | Amber | Degraded (failed jobs, high disk, stale scheduler) |
| **Error** | Red | Service down or critical failure |
| **Not Configured** | Slate | Redis/Telegram not set up |

### Phase 8 Verification

| Check | Result |
|-------|--------|
| PHPUnit | **96/96 passing** (426 assertions) |
| npm build | ✅ Pass |
| All monitors return real data | `InfrastructureHealthTest::test_health_status_returns_all_live_monitors` |
| Redis down simulation | `InfrastructureHealthTest::test_redis_reports_connection_failure_when_unreachable` |
| Queue worker stop | `InfrastructureHealthTest::test_queue_reports_error_when_pending_jobs_have_no_workers` |
| Telegram failure | `InfrastructureHealthTest::test_telegram_reports_failure_when_bot_verification_fails` |
| Scheduler stop | `InfrastructureHealthTest::test_scheduler_reports_error_when_last_run_is_stale` |
| Manual service validation | Pending operator verification |

---

## v1.0 Critical Fixes — Phase 9: Testing & Verification (Completed — Awaiting Final Approval)

Final quality assurance before Release Candidate. No new features — defect fixes only.

### Defects fixed during Phase 9

| Defect | Fix |
|--------|-----|
| WP `DeactivationProtectionTest` stub missing disconnect nonce methods | Added `storeDisconnectPolicyNonce` / `consumeDisconnectPolicyNonce` to stub |
| WP `HeartbeatSchedulerTest` data provider ignored under PHPUnit 12 | Migrated `@dataProvider` docblock → `#[DataProvider]` attribute |
| TypeScript `tsc --noEmit` failures (unused imports/locals) | Cleaned 9 frontend component files |

---

### Test summary

| Suite | Tests | Assertions | Result |
|-------|-------|------------|--------|
| **Control Center PHPUnit** (Feature + Unit) | 96 | 426 | ✅ 100% pass |
| **WP Agent — ProtocolTest** | 5 | 7 | ✅ Pass |
| **WP Agent — SecurityModulesTest** | 8 | 20 | ✅ Pass |
| **WP Agent — DeactivationProtectionTest** | 3 | 5 | ✅ Pass |
| **WP Agent — HeartbeatSchedulerTest** | 10 | 27 | ✅ Pass |
| **Combined automated total** | **112** | **485** | ✅ **100% pass** |

**Breakdown (Control Center 96):**

| Area | Test class | Count |
|------|-----------|-------|
| Agent registration & telemetry | `AgentRegistrationTest`, `AgentTelemetryTest`, `AgentTelemetryIngestionTest` | 9 |
| Agent self-update | `AgentUpdateTest` | 2 |
| Auth & 2FA | `AuthSecurityTest`, `TwoFactorAuthTest` | 8 |
| Dashboard CRUD & UX | `DashboardCrudTest`, `DashboardUxTest` | 12 |
| Disconnect protection | `DisconnectProtectionTest` | 9 |
| Heartbeat interval | `HeartbeatIntervalTest` | 15 |
| Infrastructure health | `InfrastructureHealthTest` | 10 |
| Monitoring admin | `MonitoringAdminTest` | 4 |
| Policy engine (unit) | `PolicyEngineTest` | 3 |
| Security headers | `SecurityHeadersTest` | 1 |
| Telegram notifications | `TelegramNotificationTest` | 6 |
| HMAC / replay | `VerifyAgentSignatureTest` | 5 |
| WP heartbeat scheduler (unit) | `WordPressHeartbeatSchedulerTest` | 10 |
| Example / smoke | `ExampleTest` (×2) | 2 |

---

### Frontend verification

| Check | Result |
|-------|--------|
| `npm run build` | ✅ Pass |
| `npx tsc --noEmit` | ✅ Pass (0 errors after cleanup) |
| TypeScript strict mode | ✅ Enabled (`strict`, `noUnusedLocals`) |
| React warnings | ⚠️ Not instrumented in CI — manual browser check pending |
| Console errors | ⚠️ Manual browser check pending |
| Bundle size warning | ⚠️ Vite reports JS chunk &gt; 500 kB (pre-existing; non-blocking) |

---

### WordPress Agent verification matrix

| Capability | Automated | Manual |
|------------|-----------|--------|
| Fresh installation | — | ☐ Operator |
| Existing installation | — | ☐ Operator |
| Activation / registration | ✅ `AgentRegistrationTest` | ☐ Operator |
| Reconnection | ✅ `HeartbeatIntervalTest::test_heartbeat_continues_after_reconnect` | ☐ Operator |
| Policy sync | ✅ `AgentTelemetryTest`, `ProtocolTest` | ☐ Operator |
| Heartbeat | ✅ `AgentTelemetryTest`, `WordPressHeartbeatSchedulerTest` | ☐ Operator |
| Telegram | ✅ `TelegramNotificationTest` | ☐ Operator |
| Disconnect protection | ✅ `DisconnectProtectionTest`, `DeactivationProtectionTest` | ☐ Operator |
| Secret rotation | ✅ `DisconnectProtectionTest` (partial) | ☐ Operator |
| Under Attack Mode | ✅ `SecurityModulesTest::testAttackSurfaceModuleReadsSettingsFromPolicy` | ☐ Operator |
| Plugin Whitelist | ✅ `SecurityModulesTest` (2 tests) | ☐ Operator |
| Emergency Lock | ✅ `SecurityModulesTest` (3 tests) | ☐ Operator |
| Upload Protection | ✅ `SecurityModulesTest` (2 tests) | ☐ Operator |
| XML-RPC Protection | ⚠️ Policy-driven; no dedicated unit test | ☐ Operator |
| Malware Scan | ✅ `AgentTelemetryIngestionTest` | ☐ Operator |
| Performance Metrics | ✅ `MonitoringAdminTest`, ingestion test | ☐ Operator |
| Audit Logs | ✅ `MonitoringAdminTest` | ☐ Operator |
| Remote Commands | ✅ `AgentTelemetryTest` | ☐ Operator |
| Self Update | ✅ `AgentUpdateTest` | ☐ Operator |

**E2E scripts available:** `tests/e2e-check-wp-connection.php`, `A-Monster Guard WordPress Agent/tests/run-wordpress-pipeline.php`, `e2e-wp-disconnect.php`

---

### Infrastructure verification

| Monitor | Automated | Result |
|---------|-----------|--------|
| Database | ✅ `InfrastructureHealthTest` | Live latency check |
| Redis | ✅ Simulated failure test | `not_configured` in test env |
| Queue | ✅ Worker stop + failed jobs tests | Pass |
| Scheduler | ✅ Stale + healthy tests | Pass |
| Telegram | ✅ Bot verification failure test | Pass |
| Storage | ✅ Writable + disk metrics test | Pass |
| Disk Usage | ✅ Included in health payload | Pass |
| PHP Version | ✅ Runtime version test | Pass |

---

### Security verification

| Control | Test coverage | Result |
|---------|--------------|--------|
| HMAC signing | `VerifyAgentSignatureTest` | ✅ |
| Replay protection | `VerifyAgentSignatureTest::test_replay_protection_blocks_identical_nonces` | ✅ |
| Rate limiting | `AuthSecurityTest`, `DisconnectProtectionTest` | ✅ |
| TOTP 2FA | `TwoFactorAuthTest` (4 tests) | ✅ |
| Trusted devices | `TwoFactorAuthTest::test_trusted_devices_list_and_revoke` | ✅ |
| CSRF | Sanctum stateful API + session middleware | ✅ Architectural |
| Sessions | `AuthSecurityTest` | ✅ |
| Security headers | `SecurityHeadersTest` | ✅ |
| Disconnect authorization | `DisconnectProtectionTest` (9 tests) | ✅ |

---

### Regression testing (Phases 1–8)

| Phase | Area | Regression signal | Result |
|-------|------|-------------------|--------|
| 1 | Client removal | No client routes/models in tests | ✅ Pass |
| 2 | Migrations | Full suite on fresh SQLite | ✅ Pass |
| 3 | Telegram pipeline | `TelegramNotificationTest` | ✅ Pass |
| 4 | Disconnect protection | `DisconnectProtectionTest` | ✅ Pass |
| 5 | Security + 2FA | `AuthSecurityTest`, `TwoFactorAuthTest`, `SecurityHeadersTest` | ✅ Pass |
| 6 | Heartbeat interval | `HeartbeatIntervalTest`, `WordPressHeartbeatSchedulerTest` | ✅ Pass |
| 7 | Dashboard UX | `DashboardUxTest` | ✅ Pass |
| 8 | Infrastructure health | `InfrastructureHealthTest` | ✅ Pass |

**No regressions detected in automated suite.**

---

### Performance summary

Measured locally (Windows / Laragon, SQLite, 5-iteration average) via `scripts/phase9-performance.php`:

| Metric | Avg (ms) | Notes |
|--------|----------|-------|
| Policy compile | **3.6** | Per-agent `PolicyEngineService::compilePolicy()` |
| Dashboard refresh API | **16.4** | Full `/api/v1/dashboard/refresh` payload |
| Telemetry processing | **2.8** | Signed POST `/api/v1/agent/telemetry` |
| Infrastructure check (all 8) | **812.8** | Dominated by live Telegram `getMe` HTTP call |

**Dashboard load time (frontend):** Not measured in CI — depends on network; API backend responds in ~17 ms. Manual Lighthouse check recommended before RC.

---

### Remaining known issues

| # | Issue | Severity | Notes |
|---|-------|----------|-------|
| 1 | Infrastructure health latency (~800 ms) | Low | Live Telegram `getMe` on every check; acceptable at 30s poll interval |
| 2 | JS bundle &gt; 500 kB | Low | Vite warning only; code-splitting deferred post-RC |
| 3 | WP fresh/existing install E2E | Medium | Requires live WordPress instance — operator checklist pending |
| 4 | XML-RPC protection | Low | No dedicated automated test; covered by policy module architecture |
| 5 | Manual UI / browser verification | Medium | React warnings, console errors, visual QA not automated |

---

### Risk assessment

| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Untested live WordPress paths | Medium | High | Operator must run E2E scripts against staging WP before production |
| Telegram API dependency in health checks | Low | Low | 30s poll; fails gracefully with error status |
| Queue worker not running in production | Medium | High | Supervisor config in `deploy/supervisor.conf`; infra monitor detects |
| Scheduler cron not configured | Medium | High | Infra monitor + deploy cron docs |
| Large frontend bundle on slow networks | Low | Medium | Acceptable for admin-only panel; split post-RC if needed |

---

### Production readiness assessment

| Criterion | Status |
|-----------|--------|
| Automated test suite 100% passing | ✅ **Ready** |
| Frontend builds without errors | ✅ **Ready** |
| Security controls verified | ✅ **Ready** (automated) |
| Infrastructure monitoring live | ✅ **Ready** |
| Deployment configs present | ✅ **Ready** (`deploy/` folder) |
| Live WordPress E2E validation | ⚠️ **Pending operator** |
| Manual UI QA | ⚠️ **Pending operator** |

**Recommendation:** Approve as **Release Candidate** after operator completes the manual WordPress E2E checklist and browser QA on staging. Automated gate is fully green.

---

### Phase 9 verification commands

```powershell
# Full Control Center test suite
C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe vendor/bin/phpunit

# WordPress Agent standalone tests
C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe vendor/bin/phpunit "A-Monster Guard WordPress Agent/tests/ProtocolTest.php"
C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe vendor/bin/phpunit "A-Monster Guard WordPress Agent/tests/SecurityModulesTest.php"
C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe vendor/bin/phpunit "A-Monster Guard WordPress Agent/tests/DeactivationProtectionTest.php"
C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe vendor/bin/phpunit "A-Monster Guard WordPress Agent/tests/HeartbeatSchedulerTest.php"

# Frontend
npm run build
npx tsc --noEmit

# Performance benchmark
C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe scripts/phase9-performance.php
```

---

Since all 10 core development phases are completed, verified, and passing tests, the remaining steps involve operations, deployment, and packaging.

### 1. Plugin Packaging & Distribution
To package the WordPress Agent plugin for production:
1. Zip the folder `A-Monster Guard WordPress plugin/` as `a-monster-guard.zip`.
2. To test the self-updater, upload the updated plugin zip (with incremented version, e.g. `a-monster-guard-1.5.0.zip`) inside the Control Center directory `storage/app/releases/`.

### 2. Control Center Production Deployment
Follow these steps to deploy the Control Center to a production server:
1. **Nginx:** Install and copy `deploy/nginx.conf` to `/etc/nginx/sites-available/`. Modify paths and SSL directories accordingly.
2. **Supervisor:** Copy `deploy/supervisor.conf` to `/etc/supervisor/conf.d/` to start the Laravel background queue worker. Run:
   ```bash
   sudo supervisorctl reread
   sudo supervisorctl update
   sudo supervisorctl start all
   ```
3. **System Cron:** Add the cron entry inside `deploy/cron` to `/etc/crontab` or root crontab using `crontab -e`.
4. **Redis:** Copy `deploy/redis.conf` to `/etc/redis/redis.conf` and restart the Redis server.

---

## 4. Verification Check Commands

Always run these verification steps to ensure integrity before deployment:

1. **Re-run the Complete Test Suite:**
   ```powershell
   C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe artisan test
   ```
2. **Re-build Frontend Production Assets:**
   ```powershell
   npm run build
   ```
3. **Database Reset and Seed:**
   ```powershell
   C:\laragon\bin\php\php-8.3.30-Win32-vs16-x64\php.exe artisan migrate:fresh --seed
   ```

### Current Status
- **Backend & Core Engine:** 100% complete — **96/96 PHPUnit passing** (426 assertions) + **16 WP agent tests** (112 total automated).
- **Frontend Dashboard App:** 100% built; `tsc --noEmit` clean.
- **WordPress Agent plugin:** Standalone test suite green after Phase 9 fixes.
- **Phases 1–8:** Approved.
- **Phase 9 (Testing & Verification):** Complete — **awaiting final approval for Release Candidate**.

---

## Dynamic Heartbeat Health Monitoring (2026-06-30)

Replaces fixed 1-hour / `interval × 3` timeout logic with per-website missed-heartbeat evaluation.

### Backend
- **`HeartbeatHealthCalculator`** — missed count, status, offline threshold `max(12 × interval, 1 hour)`
- **`WebsiteHealthService`** — single source for dashboard, agents list, and detail health API
- **`AgentPresence`** — scheduler uses dynamic threshold per agent policy
- **`GET /api/v1/agents/{id}/health`** — reusable health payload

### Status mapping
| Missed | Status | Label |
|--------|--------|-------|
| 0 | healthy | Healthy |
| 1 | warning | Missed 1 Sync |
| 2 | degraded | Missed 2 Syncs |
| ≥ 3 | critical | Missed N Syncs |
| offline threshold exceeded | offline | Offline |

### UI (no layout redesign)
- Website Directory: **Missed** column + tooltip
- Website Details Overview: interval, last/expected check-in, missed syncs, current health badge
- SOC dashboard: latest check-ins show interval, missed count, status label

### Verification (this pass)
| Check | Result |
|-------|--------|
| PHPUnit Feature + `HeartbeatHealthCalculatorTest` | **132/132** (563 assertions) |
| npm build | Pass |
| Intervals 1 / 5 / 15 min + reset + offline | `HeartbeatHealthMonitoringTest` |

**Awaiting approval before production deploy.**
