Introduce a Supervisor trait (async-trait) so the agent manages games with
different models behind one wire contract. ProcessSupervisor (spawned process:
rust/conan/soulmask) and the new DockerComposeSupervisor (dune) both impl it;
Agent.supervisors is now HashMap<String, Arc<dyn Supervisor>> and instancecmd
dispatch is game-agnostic — start/stop/restart/status identical across games,
selected by a per-game factory in main. InstanceState moved to the shared
supervisor module.
DockerComposeSupervisor drives docker-compose up-d / stop / restart against
the instance's compose project, with -f/-p/single-service support and a
configurable compose binary. New [instance.docker_compose] config block.
First cut = lifecycle + cached state; container crash-detection + restart
adoption deferred to Phase 3b (reconcilable with a compose ps probe).
Trait choice (dyn over enum) per Commander: scales to future planes (kubectl,
AMP/podman, SSH) as new struct+impl, no central match.
56 tests green (6 new docker-compose mock-binary tests + 5 refactored process
tests), zero warnings. Live verification pending a real Dune stack.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
COA-B cleanup:
- Sidebar agent-health footer now reads the fleet store (host count / online
count / per-host status + last heartbeat) instead of the single legacy
server.connection row, which disagreed with the multi-host fleet. Removed the
legacy useServerStore dependency from the shell.
- Removed the unused 'vuefinder' dependency (replaced by the native file
manager): dep + main.ts plugin/CSS registration. Main JS chunk 588kB -> 165kB.
Recon reclassified the 'dead cmd.server v1' item: it is the LIVE license-level
command path (module config applies, plugin install, schedules, legacy
start/stop) served only by the Go agent — a Rust-agent parity gap, not dead
code. Left intact.
Build-green (vue-tsc) + boots clean in-browser (0 console errors).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The shell skin / sidebar nav / dashboard terminology now follow the games
actually deployed (game_instances.game, agent-reported) instead of a
localStorage-only toggle. syncActiveGameFromFleet() derives: one game ->
auto-skin to it; zero/multiple -> 'all' neutral. A manual GameSwitcher pick
persists and overrides the heuristic. Wired into DashboardLayout via a watch
on the fleet store.
No schema change: a license's games are the distinct games of its instances
(the normalized source of truth) — deliberately not duplicating into a
licenses.game column that would drift (Lesson 20).
Build-green (vue-tsc) + boots clean in-browser (0 console errors, theming
initializes). Authenticated auto-derive confirms live on next instance deploy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every page previously titled 'Corrosion Management' with zero meta -
marketing invisible to search and link previews. Router afterEach now
sets title/description/og per route (no new deps); marketing pages get
real content-backed descriptions, panel views mechanical titles.
index.html carries defaults for pre-JS crawlers. Verified in-browser
per page via Playwright.
test-runner.yml: per-tool presence checks instead of green-lighting
missing toolchains; workflow_dispatch instead of every push.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New corrosion-host-agent/ crate (Go companion-agent stays as behavior
reference until parity). Wire protocol v2 per COA-B: instance-scoped
subjects corrosion.{license}.{instance}.* + host-level .host.* — spec
in PROTOCOL.md, designed for the license->host->instance fleet model.
- Multi-instance TOML config in the foundation, not retrofitted
- NATS layer on the Vigilance production profile (infinite reconnect,
capped backoff, 30s ping, 8192-msg offline buffer)
- Heartbeat with real sysinfo telemetry — Go agent shipped hardcoded
disk/cpu placeholders; this is the panel's first true Resources data
- Connectivity prober (outbound TCP, periodic + on-demand)
- Host cmd channel (ping/probe/sysinfo), going-offline beacon,
CancellationToken shutdown
- Live-fire verified against production NATS; artifacts: 3.7MB static
linux-musl, 3.8MB windows .exe (static CRT)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Full-site fake-data audit findings:
- SetupWizard showed a curl|sh installer (get.corrosionmgmt.com) and a
'corrosion-agent' binary that don't exist -> real host-agent commands
- 'View live demo' CTA on 5 marketing pages linked to a login, not a
demo -> honest 'Sign in'
- Google Fonts @import was silently dropped from the production CSS
bundle (mid-bundle @import) -> <link> tags in index.html; prod was
shipping system fallback fonts
- App-root ErrorBoundary bricked the entire SPA (incl. marketing) on a
single failed fetch until manual reload -> resets on route change +
content-scoped boundary inside DashboardLayout so nav chrome survives
- Status page KPIs showed fake zeros while the fetch failed -> em dash
- Login lacked the forgot-password link (flow already existed end-to-end)
- AdminSeedService: fresh DB had schema but no login possible; seeds
super-admin + license from ADMIN_* env when users table is empty
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements missing frontend views and API integrations:
New Views:
- SchedulesView: CRUD for scheduled tasks (restart/announcement/command/plugin_reload)
- MigrationView: Export/import interface with file upload and history tracking
- ChangelogView: Paginated changelog feed with category badges
- ForgotPasswordView: Password reset flow with email submission
- AlertsView: Alert config dashboard with threshold settings and history
Component Updates:
- ErrorBoundary: Global error handler with retry functionality
- DashboardLayout: Mobile responsive sidebar, permission-based nav, new menu items
- ServerInfoView: Complete rewrite for public server info display
Infrastructure:
- useApi: Token refresh interceptor with 401 retry and infinite loop prevention
- plugins store: Implemented all stubbed methods with real API calls
- auth store: Added hasPermission() helper for RBAC UI visibility
- Router: Added new routes with catch-all fallback
Purpose: Closes frontend implementation gaps. Hardens auth flow, improves mobile UX,
enables server automation scheduling, alert configuration, and data migration tools.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete authentication system with JWT, refresh tokens, and TOTP 2FA.
Auto-generates license keys on registration (CORR-XXXX-XXXX-XXXX format).
JwtStrategy enriches payload with license_id and permissions from roles.
Multi-tenant isolation enforced at license access layer.
Auth Module:
- 9 REST endpoints (login, register, refresh, 2FA setup/verify, profile, password reset)
- Argon2 password hashing, TOTP with QR code generation
- Public endpoints: login, register, forgot-password, reset-password, validate-key
- Authenticated endpoints require JWT Bearer token
Users Module:
- Admin CRUD for user management (requires users.view permission)
- Password fields excluded from all responses
Licenses Module:
- License lookup with owner authorization
- Public key validation endpoint for plugin verification
- License key generation via random hex parts
All DTOs use class-validator, all controllers documented via Swagger.
Custom decorators: @Public(), @CurrentUser(), @RequirePermission().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 4 Contributions (Agent Golf):
- Module auto-installation service (module_installer.rs)
- NATS subject pattern for module installation commands
- Companion agent contract documentation
- API endpoint: POST /api/modules/install
Phase 5 XO Direct Touch:
- Webstore subscription API (PayPal recurring billing)
* POST /api/webstore/subscription/create
* GET /api/webstore/subscription
* POST /api/webstore/subscription/cancel
* POST /api/webstore/subscription/webhook
- Store configuration API (CRUD for store settings)
* GET /api/webstore/config
* PUT /api/webstore/config
- Store category/item management APIs (multi-tenant CRUD)
* GET/POST/PUT/DELETE /api/webstore/categories
* GET/POST/PUT/DELETE /api/webstore/items
- Public store API (customer-facing, subdomain-scoped)
* GET /api/public-store/:subdomain
* GET /api/public-store/:subdomain/items
* POST /api/public-store/:subdomain/purchase
* POST /api/public-store/:subdomain/webhook
- Transaction history API
* GET /api/webstore/transactions
- Delivery system (NATS command execution on purchase)
- Migrations: payment_orders, webstore_subscriptions, store_config, store_items, store_transactions
Security:
- JWT auth + license_id scoping on admin endpoints
- Subdomain → license_id mapping on public endpoints
- Purchase limit enforcement
- Command injection prevention via placeholder replacement
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Build complete module activation and license-module binding system with
marketplace catalog, purchase tracking, and installation status monitoring.
Database schema (migration 009):
- modules table — Registry with pricing, features, plugin URLs
- module_purchases — License-module ownership with transaction logging
- module_installations — Deployment status tracking
- Seed data: Loot Manager module ($9.99)
Backend implementation:
- Domain models with rust_decimal pricing support
- 11 data access functions (catalog, ownership, purchases, installation)
- 5 REST endpoints with JWT auth and license scoping
- Multi-tenant enforcement via license_id from claims
Purchase flow stub:
- Immediate purchase recording without payment gateway
- PayPal integration deferred to XO's direct implementation
- Transaction ID and amount fields ready for real gateway
Module installation:
- Integration with ModuleInstaller service
- NATS-based deployment to companion agent
- Real-time status tracking via polling endpoint
All queries compile-time verified. Zero cross-tenant exposure.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Complete implementation of wipe analytics system providing operational
insights and data-driven wipe timing optimization.
Backend:
- Added comprehensive analytics query layer to db/wipes.rs:
- Success rate calculation over time ranges
- Average wipe duration tracking
- Post-wipe population curve analysis (Day 1/2/3)
- Optimal wipe timing recommendations based on player peaks
- Individual wipe entry tracking with peak population correlation
- Implemented GET /api/analytics/wipes/performance endpoint with
flexible range parameters (6d/12d/90d/all)
- All queries leverage hourly aggregate tables for 90-day retention
Frontend:
- Built WipeAnalyticsView.vue with 3 ECharts visualizations:
- Success rate timeline (scatter: green success, red failures)
- Population curve comparing Day 1/2/3 post-wipe averages
- Wipe duration trend showing execution time evolution
- Insight cards displaying success rate, avg duration, peak day, optimal timing
- Actionable recommendations banner with data-driven suggestions:
- Optimal wipe scheduling based on historical player peaks
- Wipe frequency recommendations (weekly vs bi-weekly)
- Duration optimization alerts
- Rollback protection warnings
- Time range selector and CSV export functionality
- Added /wipes/analytics route
TypeScript interfaces added: WipePerformanceMetrics, WipeAnalyticsEntry,
PopulationCurve
Answers critical operational questions: "How long do wipes take? When do
players peak post-wipe? What's my success rate? When should I wipe for
maximum population?"
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement status.corrosionmgmt.com public status page showcasing all
Corrosion servers that opt-in. Drives platform visibility and attracts
new customers.
Backend:
- Migration 007: status_page_description TEXT column
- models/public.rs: PublicServerStatus, PlatformHealth, StatusPageResponse
- db/public.rs: get_public_servers() with uptime calculations (24h/7d/30d)
- api/public.rs: GET /api/public/status (no auth)
- api/settings.rs: public site config endpoints (auth required)
Frontend:
- StatusPageView.vue: Server grid with live stats, uptime badges, wipe schedules
- Platform health header: total servers, online count, total players
- Auto-refresh every 10 seconds via polling
- Mobile-responsive design
- SettingsView.vue: Public Status tab with opt-in toggle
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add complete map analytics pipeline to answer: "Which maps drive the most
players? Is my rotation working?"
Backend Changes:
- Migration 005: Add map_id FK to server_stats and wipe_history tables
- Stats consumer now captures current_map_id when persisting stats
- Map analytics queries: get_map_analytics() returns performance metrics,
effectiveness scores, and rotation health
- API endpoint: GET /api/analytics/maps?range=90d returns summary with
best performing map and rotation effectiveness percentage
Frontend Changes:
- MapAnalyticsView.vue: Complete dashboard with performance charts,
sortable metrics table, actionable insights, and CSV export
- ECharts bar chart comparing avg vs peak players per map
- Color-coded effectiveness scoring (green ≥80%, yellow ≥60%, red <60%)
- Time range selector: 30d/90d/all
Purpose: Enables data-driven map selection for wipe day based on player
engagement metrics. Rotation effectiveness algorithm scores maps by
(avg_players / peak_players) * 100.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Backend:
- Stats ingestion consumer subscribing to corrosion.*.stats NATS subject
- Hourly aggregation scheduler (runs :05 past every hour)
- Daily cleanup job (03:00 UTC) with 7-day raw / 90-day hourly retention
- Analytics API (summary, timeseries, CSV export)
- Complete stats DB queries with aggregation and cleanup
Frontend:
- Analytics dashboard with ECharts integration
- Player count and server performance charts
- Time range selector (24h/7d/30d)
- CSV export functionality
- Real-time data loading
Infrastructure:
- Exposed NatsBridge.jetstream for consumer access
- Background service initialization in main.rs
Data flow: Plugin → NATS → Consumer → DB → Aggregation → API → Charts
Unblocks Strike 4B (dashboards) and 4C (alerting).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>