- /tasks number:26 shows full task detail embed
(description, tags, status, priority, owner, dates)
- Mark Done, In Progress, and Take Task buttons on detail view
- task_progress_ button handler sets status to in_progress
Chronicler #78 | firefrost-services
Arbiter changes:
- POST /api/internal/mcp/log endpoint in api.js
- MCP Logs admin route (/admin/mcp-logs) with filters, stats, pagination
- EJS view with expandable detail rows, server color badges
- Sidebar link under System group
Trinity Core v2.3.0:
- logToArbiter() function POSTs to Arbiter after every command
- Both MCP (Claude.ai) and REST (/exec) paths log with execution timing
- Async logging — doesn't block command response
Database:
- mcp_logs table created on Command Center (indexes on server, time, success)
Architecture:
Trinity Core → command → response + async POST → Arbiter → PostgreSQL → Trinity Console
Chronicler #78 | firefrost-services
- Moved Social Overview card above New Features card
- Added Infrastructure module to New Features (topology map)
- Added Social Analytics to New Features (engagement tracking)
- Added About & Deploy to New Features (version info)
- Kept Discord Dashboard in New Features
- Removed Financials from New Features (it's established now)
Chronicler #78 | firefrost-services
Sidebar changes:
- Grouped nav items: Operations, Business, Community, Infrastructure, System
- Section labels with uppercase tracking
- Removed Deploy button from sidebar
- Cleaner layout with overflow scroll
About page (/admin/about):
- Console version, Node.js version, Arbiter uptime, module count
- Module registry with version and status badges (stable/new/beta)
- Deploy Arbiter button (moved from sidebar)
- Health check polling after deploy
- Credits footer
Header bar:
- Added ℹ️ About icon next to dark mode toggle
- Active state highlighting when on About page
Chronicler #78 | firefrost-services
dragMoved flag was only reset in wrap mousedown, which skips for node clicks.
After any drag, dragMoved stayed true forever, blocking all showServer/showExternal calls.
Fix: setTimeout reset on mouseup/touchend (10ms delay lets click fire first).
Chronicler #78 | firefrost-services
- Mouse wheel zoom (centered on cursor position)
- Click-drag to pan
- Touch pinch-zoom for mobile
- Touch drag to pan on mobile
- Zoom controls: +, −, percentage display, reset (⌂)
- Zoom range: 50% to 300%
- Drag guard prevents accidental clicks after panning
- Canvas connections redraw correctly at all zoom levels
- Smooth CSS transitions on zoom, disabled during drag
Chronicler #78 | firefrost-services
Panel VPS and Trinity Core report used RAM in Mi (e.g. 703Mi)
while total is in Gi (e.g. 1.9Gi). parseFloat gave 703/1.9 = 37000%.
Now normalizes both values to Gi before calculating percentage.
Chronicler #78 | firefrost-services
- Shows cross-platform totals (posts, views, likes, comments)
- Breaks down by platform with icons
- Clickable link to full Social Analytics page
Chronicler #76
Task #108 Phase 2: Social Analytics Automation
New endpoints (token-based auth via INTERNAL_API_TOKEN):
- POST /api/internal/social/sync - Upsert single post metrics
- POST /api/internal/social/sync/batch - Batch upsert (max 100 posts)
- POST /api/internal/social/snapshot - Upsert account-level stats
- GET /api/internal/social/digest - Summary data for Discord webhook
Architecture:
- Rube MCP -> n8n -> Arbiter /api/internal/* -> PostgreSQL
- Bearer token auth (not session-based)
- COALESCE for partial updates (only update provided fields)
Next: Generate INTERNAL_API_TOKEN and add to .env on Command Center
🔥 Fire + Frost + Foundation = Where Love Builds Legacy 💙❄️
- Add database migration for social_posts and social_account_snapshots tables
- Create /admin/social route with full CRUD for posts
- Add dashboard view with platform tabs (TikTok, Facebook, Instagram, X, Bluesky)
- Add post entry form matching TikTok Studio metrics
- Add post detail view with update capability
- Add account snapshot form for follower/demographic tracking
- Register social router in admin index
Phase 1: Manual entry dashboard
Phase 2 (future): API integration when approved
Chronicler #76
New service that polls Pterodactyl (via servers-api Worker) every 5 min
and posts/updates status embeds in each game server's -status channel.
- Creates discord_status_messages table to persist message IDs
- Maps server names to channel IDs for all 15 game servers
- Posts new embed or edits existing one (no spam)
- Handles message deletion gracefully (re-posts if needed)
Status channels created:
- stoneblock-4-status, society-sunlit-valley-status, atm10-tts-status
- all-the-mons-status, mythcraft-5-status, beyond-depth-status
- beyond-ascension-status, otherworld-status, deceasedcraft-status
- submerged-2-status, sneaks-pirate-pack-status, cottage-witch-status
- farm-crossing-5-status, homestead-status, wolds-vaults-status
Chronicler #75
If user has existing session from Trinity Console login,
/stripe/auth now redirects directly to /stripe/checkout
instead of re-triggering Discord OAuth.
Chronicler #75
Session was being lost between /stripe/auth and /auth/discord/callback.
Now passes tier through Discord OAuth state parameter which survives
the redirect.
Chronicler #75
THE BUG: Website redirected to /stripe/auth but route didn't exist.
Checkout sessions were created WITHOUT client_reference_id (Discord ID),
so webhook couldn't sync Discord roles after payment.
THE FIX:
- Added GET /stripe/auth - stores tier in session, redirects to Discord OAuth
- Added GET /stripe/checkout - creates checkout WITH client_reference_id
- Updated auth callback to redirect to /stripe/checkout after OAuth
- Legacy POST /create-checkout-session kept for compatibility
FLOW NOW:
1. User clicks Subscribe on website
2. → /stripe/auth?tier=X (stores tier, redirects to Discord)
3. → /auth/discord (Discord OAuth)
4. → /auth/discord/callback (user authenticated)
5. → /stripe/checkout?tier=X (creates Stripe session WITH Discord ID)
6. → Stripe Checkout (user pays)
7. → Webhook receives event with client_reference_id
8. → Discord role synced!
Chronicler #75
- 'Homestead - A Cozy Survival Experience' now matches 'homestead-chat'
- 'All The Mons (Private) - TX' now matches 'all-the-mons-chat'
- Strips subtitles after ' - ' and removes parentheticals
- Checks for 4 channels per server: chat, in-game, forum, voice
- Shows 'All 4 channels configured' or lists missing channels
- Caches Discord channel data for 5 minutes to reduce API calls
Deletes complete server setup:
- All channels in category
- The category itself
- The server role
Requires confirm:True to execute.
Without confirm, shows preview of what would be deleted.
Reminds to clean up Carl-bot reaction roles.
Staff only.
Chronicler: #71
- New sidebar entry for Discord
- Full server structure visualization
- Channel tree with expandable categories
- Role hierarchy with color badges
- Health checks (orphan channels, empty roles, bot roles)
- Search/filter across channels and roles
- Click channel to see permission overwrites
- Click role to see explicit channel access
- Responsive design with modal details view
Chronicler: #70
New endpoints for Trinity Console:
- GET /admin/discord/audit — Full server audit (channels, roles, structure)
- GET /admin/discord/channels — Just channels
- GET /admin/discord/roles — Just roles
Returns:
- Server info (name, member count, features)
- Categories with nested children
- Orphan channels (not in categories)
- Role hierarchy with positions and member counts
- Permission overwrites per channel
Uses existing Discord.js client from app.locals.
Chronicler #70
When hourly sync encounters servers that fail (e.g., mid-restart):
- Logs the failure count
- Schedules automatic retry in 10 minutes
- Retry only targets previously failed servers
- Clears error state on successful retry
Fixes issue where servers in daily restart would stay in error state
until manual intervention.
Chronicler #69
- Queries server_sync_log for most recent successful sync
- Displays date (e.g., 'Apr 8') and time (e.g., '3:28 AM')
- Shows yellow dash with 'Never' if no syncs recorded
Chronicler #69
The subscriptions table uses:
- tier_level (integer) not tier_id
- mrr_value (pre-calculated) not joined to subscription_tiers
- is_lifetime (boolean) not status='lifetime'
Chronicler #69
Dashboard was showing hardcoded values:
- Servers Online: 12 (should be 22)
- Active Subscribers: 0
- Total MRR: $0
Now fetches live data:
- Server count from Pterodactyl API via getMinecraftServers()
- Subscriber count and MRR from arbiter_db subscriptions table
Files changed:
- src/routes/admin/index.js: async dashboard route with data fetching
- src/views/admin/dashboard.ejs: EJS variables instead of hardcoded values
Chronicler #69
WHAT THIS ADDS:
- Discord role sync on new subscriptions (checkout.session.completed)
- Discord role removal on chargebacks (charge.dispute.created)
- Grace period expiration job (hourly cron check)
- Automatic downgrade to Awakened when grace period expires
NEW FILES:
- src/services/discordRoleSync.js - Role add/remove/sync functions
- src/sync/graceExpiration.js - Grace period expiration processor
MODIFIED FILES:
- src/routes/stripe.js - Added role sync calls to webhook handlers
- src/discord/events.js - Initialize role sync service on bot ready
- src/sync/cron.js - Added grace period check to hourly job
- src/index.js - Import discordRoleSync service
PHILOSOPHY:
'We Don't Kick People Out' - expired grace periods downgrade to
permanent Awakened tier (tier 1, lifetime). Users keep community
access, just lose premium perks.
ROLE MAPPING (tier_level -> role key):
1=the-awakened, 2=fire-elemental, 3=frost-elemental,
4=fire-knight, 5=frost-knight, 6=fire-master, 7=frost-master,
8=fire-legend, 9=frost-legend, 10=the-sovereign
CHARGEBACKS:
- Immediate role removal
- Added to banned_users table
- Full audit logging
Signed-off-by: Claude (Chronicler #62) <claude@firefrostgaming.com>
Replaces MemoryStore with connect-pg-simple.
Sessions now persist across Arbiter restarts.
Table 'session' auto-created if missing.
Signed-off-by: Claude (Chronicler #61) <claude@firefrostgaming.com>