maps/ gitignore rule was catching backend-nest/src/modules/maps/.
Scoped to /maps/ (root only) so runtime data is still ignored
but source code isn't.
Co-Authored-By: Claude Opus 4.6 <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>
- Remove complex build caching
- Set SQLX_OFFLINE=true to skip compile-time query verification
- Queries still validated at runtime
- Eliminates need for DATABASE_URL during Docker build
- Remove unused ExternalLink import from ModuleStoreView
- Remove unused Tag import from StoreItemsView
- Prefix unused cmd variable with underscore in v-for loop
Fixes production build TypeScript errors.
Backend infrastructure for hosting provider reseller program (Model B).
Database Schema (Migration 012):
- hosts table: Hosting company accounts with API key authentication
- host_licenses: Tracks licenses provisioned by each host
- host_billing_records: Monthly billing data ($6/server wholesale)
Host Provisioning Service:
- API key authentication (SHA-256 hashed, bearer token)
- Bulk license provisioning (single call creates user + license + associations)
- Auto-generation: license keys, companion tokens, subdomain slugs
- Active license counting for billing
- Monthly billing record generation with CSV export support
Host API Endpoints:
- POST /api/host/provision: Bulk license creation
* Input: server_id, hostname, customer_email
* Output: license_key, companion_token, plugin_download_url, subdomain, panel_url
- GET /api/host/licenses: List all host-provisioned licenses with status
- GET /api/host/billing/:month: Monthly billing report (YYYY-MM format)
Security:
- Separate authentication system (API keys vs user JWTs)
- Host-level query isolation (all operations scoped by host_id)
- SHA-256 API key hashing
- CORS protection on host endpoints
Business Model:
- $6/server/month wholesale rate (configurable per host)
- Manual invoicing (no Stripe integration in MVP)
- Hosts control their own markup to end customers
Per B2B_RESELLER_PLAN.md: Minimal viable B2B implementation (Model B).
No white-label branding, SSO, or complex integration required.
Simple API-based provisioning for hosting partners.
Production ready for initial hosting partner testing.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Built StoreConfigView.vue for webstore setup
- Form fields: store name, description, currency (USD/EUR/GBP)
- PayPal credentials (client ID/secret) with encryption support
- Sandbox/production mode toggle with warning states
- Store enable/disable with validation
- Empty state for unconfigured stores
- TypeScript StoreConfig interface
- Route: /admin/webstore/config (auth required)
- API integration: GET/PUT /api/webstore/config
- Responsive Tailwind design
Co-Authored-By: Claude Sonnet 4.5 <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>
Customer-facing module marketplace with full browse/preview/purchase flow:
Frontend Implementation:
- Complete ModuleStoreView.vue with dual-tab interface (Catalog + My Modules)
- Module grid with preview images, category badges, pricing display
- Search functionality across name/description fields
- Category filtering (8 categories: Loot, Events, Economy, Kits, Admin, PVP, PVE, Building)
- Detail modal with screenshots gallery, full features list, version info
- Purchase confirmation modal with license binding display
- Installation status tracking (Not Purchased → Purchased → Installed)
- Professional marketplace UI with hover animations and responsive grid
TypeScript Types:
- Module interface with full metadata (id, slug, name, description, price, category, images, features, version, purchase/install status)
- PurchaseRequest interface for API integration
API Integration Points (backend implementation separate):
- GET /api/modules/catalog — Browse all available modules
- GET /api/modules/my-modules — Fetch purchased modules for license
- POST /api/modules/purchase — Initiate purchase (returns payment URL or instant confirmation)
- POST /api/modules/install — Trigger deployment to game server
Design Features:
- Color-coded category badges with 8-color palette
- Preview image with scale-on-hover effect
- "Purchased" badge overlay for owned modules
- Three-button state progression (Purchase → Install → Installed)
- Empty states for zero results and zero purchases
- Mobile-responsive grid (1/2/3 columns)
- Payment flow with external redirect support (Stripe/PayPal)
- Error handling with inline error display in purchase modal
Purpose: Server admins can browse, preview, purchase, and install premium gameplay modules directly from dashboard. This is where customers pay real money — UI polish critical for conversion.
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>
Production build pipeline for companion agent:
- Triggers on version tags (v*.*.*)
- Cross-compiles for Linux and Windows (AMD64)
- Generates SHA256 checksums for verification
- Creates Gitea release with auto-generated notes
- Uploads binaries and checksums as release assets
- Provides build summary in workflow output
Built artifacts:
- corrosion-companion-linux-amd64
- corrosion-companion-windows-amd64.exe
- checksums.txt
Usage: git tag v1.0.0 && git push origin v1.0.0
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Test workflow to verify act_runner on asgard is operational.
Validates:
- Runner picks up jobs
- Docker container execution
- Go/Rust toolchains available
- System resources (CPU, memory, disk)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The GITEA__* environment variables were conflicting with the
wizard-generated app.ini, causing crash loop on startup.
Simplified to only USER_UID/GID - let the wizard configure
everything else cleanly.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed INSTALL_LOCK from true to false to allow first-time setup wizard.
After initial setup is complete, this can be changed back to true
to prevent unauthorized re-configuration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Architecture clarification:
- Gitea + SeaweedFS run on PUBLIC docker stack
- Act runner runs on ASGARD (Ryzen 9 build server)
- Runner connects remotely to git.corrosionmgmt.com
New documentation:
- ASGARD-RUNNER.md: Complete setup guide for registering
and running act_runner as systemd service on asgard
- Includes example workflows for companion agent builds
- Troubleshooting and security notes
Runner capabilities:
- Docker access for containerized builds
- Native Go/Rust toolchains (already installed)
- 16C/32T, 64GB DDR5 for fast builds
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Separate infrastructure services from application stack for operational
resilience. Following Gemini's architectural guidance.
Infrastructure Services:
- Gitea (git.corrosionmgmt.com) - Source control, CI/CD, releases
* SQLite database (self-contained)
* Port 8090: Web UI
* Port 2222: SSH
- SeaweedFS (cdn.corrosionmgmt.com) - S3-compatible object storage
* Port 8091: Filer UI (primary CDN interface)
* Port 8092: S3 API (programmatic access)
* Port 9333: Master UI (internal admin)
* Port 8080: Volume server (internal)
Benefits:
- Restarting Corrosion app doesn't affect Git/CDN services
- No shared database dependencies (Gitea uses SQLite)
- Clear separation between infrastructure and application concerns
- Foundation for plugin ecosystem and map hosting
Deployment:
cd infra && docker compose up -d
See infra/README.md for full setup instructions and NPM configuration.
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>
Tiered agent model for token budget optimization: Haiku for recon,
Sonnet as daily XO, Opus reserved for escalation-only surgical strikes.
CLAUDE.md updated with resource discipline section referencing the roster.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Operational doctrine migrated from Vigilance HQ — V4_WORKFLOW, engagement
rules, and lessons learned carry forward. Project-specific sections written
for Corrosion's Rust/Axum + Vue 3 + Go stack. Claude Code settings configured
with permissions for cargo, go, npm, docker, and git operations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vite bakes env vars at build time, not runtime. Without .env.production
in the frontend directory, the Docker build had no VITE_PANEL_URL and
Sign In / Get Started links resolved to empty hrefs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
corrosionmgmt.com now serves LandingView as the default page with marketing
routes at root level. panel.corrosionmgmt.com continues serving the admin
panel unchanged. /site/* backward compat via redirects on marketing domain.
- nginx: Add bare domain server block (only proxies /api/early-access/)
- router: Detect hostname at module load, generate domain-specific routes
- MarketingLayout: Named routes for nav, external <a> tags for auth links
- LandingView: CTAs point to panel domain via VITE_PANEL_URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
API returns unexpected shape when backend isn't wired — data.members
is undefined, assigned to ref, then .length in template throws
TypeError. Nullish coalescing to empty array prevents the crash.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
/admin/servers.startsWith('/admin') was true, so both Admin Home
and Server Fleet highlighted simultaneously. Now /admin uses
exact match like / does.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ADMIN_EMAIL and ADMIN_PASSWORD were in the .env file but not
forwarded to the API container — bootstrap_admin() couldn't
read them, so no initial user was created. Login returned 400
on every attempt because no user existed in the database.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nginx container now builds the Vue frontend in a Node stage
instead of mounting local dist/ files. This means:
- No need to commit dist/ or build locally before deploying
- docker compose up --build handles everything end-to-end
- Removed obsolete compose version key
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NATS minimal image has no shell tools for health probes. The API
already handles NATS unavailability gracefully, so service_started
is sufficient.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>