Ticker update loop resilience: If loading the ticker list from the database fails, the update loop now skips that run and logs at most once every five minutes instead of every second, avoiding log spam. Each ticker’s database writes (remove, update message id, set last update) are wrapped with a single retry after a short delay when a disk I/O–style error occurs, and per-channel error logging is rate-limited to once every five minutes so repeated failures no longer flood the console.
Finnhub fetch reliability: Transient "fetch failed" errors from the Finnhub API (e.g. network or DNS blips) no longer break ticker updates permanently. Finnhub requests now use a 12-second timeout so hung requests don’t block indefinitely, and failed requests are retried up to two times with a short delay. Finnhub fetch errors are logged at most once per minute to keep logs readable during connectivity issues.
Spam after removing a ticker: When a ticker’s Discord message was missing (e.g. after removal or channel purge), the bot was creating a new message on every update interval, causing repeated embeds. The bot now removes the ticker from its database when the message is missing instead of respawning it, so deleted tickers no longer spam the channel.
Multiple tickers per channel: Previously only one ticker per channel was allowed; adding a second ticker replaced the first. The unique constraint on guild + channel was removed so you can add multiple stock tickers in the same channel. Each add creates a new row and a new Discord message.
Remove ticker in panel: Removing a ticker from the panel now correctly deletes the Discord message and updates the bot’s database. The panel sends both ticker id and Discord message id; the bot looks up the ticker by id first, then by message id so removal works even when panel and bot use different database files or when ids don’t match.
Edit ticker: Editing a ticker in the panel now targets the correct row when multiple tickers exist in the same channel by passing and using the ticker id.
Guild member fetch timeout: Resolved recurring "GUILD_MEMBERS_TIMEOUT: Members didn't arrive in time" errors originating from the dashboard stats endpoint when attempting to fetch all guild members.
Safer presence counting: The dashboard now calculates online and in-voice member counts from the existing member cache instead of forcing a full member fetch, avoiding timeouts on large or slow guilds.
Stability: This change keeps the analytics dashboard functional while preventing noisy presence-related errors in the bot logs.
Pane glow synced to theme: The main pane containers ([data-tab-pane]) now render a background glow using the user’s selected theme color, including a corrected hover glow color.
Glow intensity tuned: Reduced overall glow intensity across the panel for a cleaner look.
Layout fix: Adjusted spacing so the active pane content no longer clips under the page title.
Button consistency: Standardized button styling across the panel (including previously unstyled buttons like user preference modal controls).
---
### Commands documentation (in-panel wiki)
Commands → Wiki: The Commands pane now renders a wiki-style documentation view generated from the bot’s command metadata.
Panel API: Added a get_commands_metadata action to supply categorized command documentation to the panel.
---
### Autosave across settings
Removed manual saves: All “Save settings” buttons were removed in favor of autosave.
Debounced autosave helper: Added a shared autosave utility with status feedback and wired it across feature panes.
Picker integration: Emoji, channel, and role pickers now trigger the correct change events so autosave reliably persists changes.
---
### Moderator: Message Retention relocation
Moved Message Retention: Message retention controls were moved into Moderator → Audit Logging.
Navigation cleanup: Removed the standalone Message Retention pane/navigation entry to avoid duplication.
---
### Additional feature panes (wiring + autosave)
Coming-soon features wired: Added panel panes and autosave wiring for Premium, Emojis, Achievements, Automations, and Ticketing so settings persist correctly.
Bot-side placeholders: Added minimal bot-side modules for Achievements and Ticketing to read settings (ready for incremental expansion of behavior).
---
### Analytics dashboard
Real dashboard: The Dashboard now surfaces live and DB-backed server analytics (members, online, 24h activity, voice activity, recent deleted messages, recent joins, active staff, and top leaderboard).
Quick navigation: Added dashboard shortcuts to jump to commonly used settings panes.
Panel API: Added get_dashboard_stats to combine live bot metrics with database aggregates.
Bot internal API: Added /internal/dashboard_stats and /internal/resolve_user_tags to support live stats and user tag resolution.
DB + helpers: Extended schema and helpers to support dashboard metrics (including user_xp.last_message_at, plus tables/queries for joins and deleted message rollups).
---
### Stability + error handling
JavaScript robustness: Fixed a panel.php syntax error and added defensive null checks across event bindings to prevent runtime crashes when optional UI elements aren’t present.
DB error resilience: Improved dashboard query behavior so missing tables/data return safe empty results instead of 500 errors.
---
### Changelog removal (end-to-end)
Web panel: Removed all Changelog UI and navigation from the panel.
Panel API: Removed all Changelog-related API actions.
Bot: Removed Changelog-related internal routes and message behaviors.
Public endpoints/pages: Removed Changelog public endpoints/pages.
Dashboard tab rename: The analytics Dashboard now uses the dashboard tab/pane identifier instead of changelog, with automatic mapping of older tab=changelog links for backwards compatibility.
Channels & roles and Server settings: The Settings page grid was adjusted so the Channels & roles section no longer pushes the Server settings section down. The left column now stacks Bot Masters then Server settings; the right column shows Channels & roles spanning the full height of both rows. On narrow viewports the layout collapses to a single column in document order.
---
### Default embed color (Server settings)
Inline presets: The default embed color control now shows a single row: a main color swatch plus five preset swatches (Default, Purple, Teal, Green, Orange) to the right. The manual hex input and “Choose color” button were removed; the selected color is stored in a hidden input so save/load and existing logic are unchanged.
Main swatch as button: The main color preview swatch acts as the control that opens the shared color picker modal. The swatch was enlarged and given a slow, subtle bounce animation to indicate it is clickable; the animation pauses on hover.
---
### Shared color picker modal
Full custom selector: The shared “Choose color” modal (used by all color options in the panel) now includes a full custom color selector: a large saturation/lightness gradient area with a draggable handle, a hue slider, and a hex input. Preset swatches remain at the top. The duplicate preview row (native color input, preview circle, and RGB inputs) was removed so the modal matches the intended design with presets, custom S/L and hue, and hex only.
---
### Unified color picker look and behavior
Same UI everywhere: All color selection areas in the admin panel now match the default embed color look and behavior:
User settings – Theme color: One row with a main swatch (opens the shared modal for custom color) and five theme preset swatches. The previous “Custom” row (native color input and hex field) was removed. Clicking a preset still applies the named theme; clicking the main swatch opens the shared modal and applying a color there sets a custom theme and updates the panel accent.
Send embed message – Color: Swatch plus five inline presets; no visible hex or “Choose color” button.
Stock Ticker – Embed color: Same layout and behavior.
Ticker edit – Embed color: Same layout and behavior.
Reminder – Stripe color: Same layout and behavior; duplicate “Stripe color” label removed.
Changelog – Embed color: Same layout and behavior.
Data and behavior: Each of these still uses a hidden hex input with the same ID as before, so all existing save/load and API behavior is unchanged. The shared “Choose color” modal opens when the main swatch is clicked and applies the chosen color to the correct target on Done.
---
### Preset click handling
Generalized handler: The logic that runs when a user clicks a preset swatch (e.g. Default, Purple, Teal) was generalized. It now works for any color block that has preset swatches and a hidden hex input: the clicked preset’s block is found, the hidden hex is updated, the main swatch and preset selection state are updated, and the default embed color block still refreshes its UI when applicable. Theme presets in User settings continue to be handled separately so named themes still apply correctly.
Invite Tracker — Full implementation: bot caches invites on create/delete, attributes joins to inviters on member join, and the panel has a real Invite Tracker tab with a leaderboard table and refresh. Internal API for invite leaderboard is supported.
Statistics Channels — Confirmed complete: bot updates voice channel names (e.g. member count) from feature settings; panel has a Statistics Channels pane to configure channels and templates.
Phase 4 (Owner features) — Broadcast (internal route + panel UI to send a message to selected or all guilds), Leave guild (internal route + panel UI with confirmation), Blacklist (add/remove by user ID; bot ignores blacklisted users in message handling), and Audit log (table + PHP helpers, log broadcast/leave actions, Bot Settings tab to view entries).
Bot Settings — VIP section copy clarified; Blacklist, Broadcast, Leave server, and Audit log sections added; APIs for listing bot guilds and loading the audit log.
## Fixes & Behavior
PHP fatal (redeclare) — Removed redundant require of bot_db.php in api_global.php so bot_db_path() is not redeclared and the Claim owner / Bot Settings flow works.
Owner from config — When the account DB has no owner, the effective owner is taken from owner_discord_id in config/discord_config.php, persisted to the account DB, and used for Bot Settings so the owner does not need to reclaim each time.
Transfer ownership removed — The transfer-ownership input, button, and related script were removed from Bot Settings; the set_owner API action was removed so ownership cannot be changed from the panel.
## Data & Security
SQLite split (server vs account) — Server data (guild config, commands, feeds, reactions, tickers, changelog/feature settings, XP, reminders, starboard, invite cache/joins) lives in the server DB; account data (owner, delegated admins, VIP, blacklist, audit log) lives in a separate account DB. Both the Node bot and PHP use the split; account DB path is configurable via BOT_ACCOUNT_DB_PATH (Node) or defaults to the same directory as the server DB.
Session cookies (panel) — Session cookie path is scoped to the app base_path (e.g. /discord/). Optional config keys allow overriding lifetime, secure, httponly, samesite, and domain. Defaults remain secure (HttpOnly, SameSite Lax, Secure when HTTPS); config can force Secure when behind a reverse proxy. Config comments document the optional session cookie options.
---
Version 1.1 — Invite Tracker and Statistics Channels completed; Phase 4 owner features (broadcast, leave guild, blacklist, audit log) added; owner-from-config and SQLite server/account split implemented; transfer ownership removed; session cookies updated and configurable; PHP redeclare error fixed.