Table of Contents

v0.2.3 - Moderation, Embeds & UI Overhaul

Features

Moderation System

  • Added server roles: Owner, Admin, Mod, Member — first registered user is automatically Owner
  • New /kick, /ban, /unban, /mute, /unmute, /role, /nuke commands for moderators and admins
  • ModerationController with full REST API for role assignment, kicks, bans, mutes, message deletion, and channel nuking
  • Mutes support optional duration (auto-expire) and blocked users cannot log in
  • Role claim included in JWT tokens; role badges shown in the online users panel
  • Kicked and banned users are forcibly disconnected in real time — server cleans up presence, broadcasts departures, and signals client disconnect
  • Works for both SignalR and IRC connections; client shows an error dialog with the reason

Private Channels

  • Channels can be created as public or private via a checkbox in the Create Channel dialog
  • Public channels are visible to all users; private channels only appear for members who joined them
  • Persistent channel membership tracked in the database (ChannelMembership table)
  • GET /api/channels returns the combined list: public channels + user's joined private channels
  • Channel creators are automatically added as members
  • Messages containing URLs now show a rich preview below the message text
  • Multiple URLs per message supported (up to 3) — each gets its own embed
  • Server-side fetching: detects URLs in a message, fetches each page, and parses OpenGraph meta tags (og:title, og:description, og:site_name)
  • Embeds are persisted in the database as a JSON array and included in channel history
  • TUI client renders embeds with a left border bar — site name and border in blue, title in white, description in gray; text word-wraps at actual viewport width
  • IRC gateway receives a text-only embed preview (site name, title, description)
  • Falls back to <title> tag when no OG tags are present; gracefully skips if no useful metadata is found
  • 5-second fetch timeout ensures message delivery is never significantly delayed
  • SSRF protection rejects private/loopback IP addresses before fetching

Notification Sounds

  • Incoming messages play a notification sound when the terminal is not focused
  • Embedded MP3 asset with cross-platform playback support

Online Users Panel

  • Collapsible right-side panel showing online users in the current channel (toggle with F2)
  • Users displayed with status indicators, role badges, and their custom nickname colors
  • Panel updates on join, leave, and status change events

@mention Highlighting

  • @username text rendered in orange accent color in all messages
  • Messages mentioning the current user get a full-line amber background highlight
  • Works across multi-line messages and continuation lines

ASCII Art Improvements

  • Half-block character rendering (/) with separate foreground + background colors for 2x vertical resolution
  • Switched from ANSI escape codes to printable color tags ({F:RRGGBB}, {B:RRGGBB}, {X}) — no control bytes in stored content
  • Optional size parameter for /send command: -s (40x40), -m (80x80, default), -l (120x120)
  • IRC gateway converts color tags back to ANSI for IRC client compatibility

Client UI

  • Version number shown in the status bar
  • Custom colored rendering for channel list (active indicator, unread count badges)
  • Avatar upload field added to the profile edit dialog (file path or URL)
  • Profile avatar now renders with full color tag support in the profile view dialog
  • Update check notification on connect — shows a system message if a newer GitHub release exists
  • Chat messages no longer show selection/focus highlight
  • Exit shortcut changed from Ctrl+C to Alt+Q — frees Ctrl+C for copy
  • Default history increased from 50 to 100 messages on channel join

Fixes

  • Fixed #general channel not visible after adding the IsPublic column — migration default changed to true and startup service ensures it
  • Fixed channels disappearing when creating a new channel — replaced full re-fetch with incremental updates
  • Wired OnChannelUpdated SignalR event so new public channels appear for all connected users in real time
  • Fixed color tag parser using wrong regex group numbers (6,7,8 instead of 1,2,3) — new ASCII art was rendering without colors
  • Full Unicode/emoji support — renderers use Terminal.Gui v2 grapheme cluster API (GraphemeHelper, AddStr) for proper wide character handling
  • Emoji-to-text shortcode conversion for consistent cross-platform rendering
  • Fixed /send and /avatar commands not handling file paths with spaces correctly, even when quoted
  • Server-side newline spam protection — consecutive blank/whitespace-only lines collapsed to 1 and total lines capped at 30
  • Fixed OG tag regex truncating descriptions containing apostrophes (e.g. "HueByte's portfolio" was cut to "HueByte") — switched to backreference-based quote pairing

Infrastructure

  • New LinkEmbedService on the server — URL detection, HTML fetching (first 64KB), OG tag parsing via compiled regex
  • EmbedDto record added to shared Core DTOs; MessageDto.Embeds list for multiple embeds per message
  • EmbedJson nullable column on the Message table stores serialized embed data as JSON array (max 8KB); DataMigrationService auto-migrates old single-object format
  • Dedicated "OgFetch" named HttpClient with bot User-Agent header and 5-second timeout
  • PresenceTracker.ForceRemoveUser() for atomic user cleanup on kick/ban
  • IChatBroadcaster.ForceDisconnectUserAsync() and IEchoHubClient.ForceDisconnect for force-disconnect signaling
  • NotificationSoundService for cross-platform audio playback of embedded notification sounds
  • Startup DataMigrationService automatically converts old ANSI-format messages to the new color tag format on server boot, logging the count of migrated records
  • EmojiHelper utility for emoji-to-shortcode conversion
  • Heartbeat handling in ServerDirectoryService for connection health checks
  • Four new EF Core migrations: AddModerationRoles, AddChannelIsPublic, AddChannelMembership, AddMessageEmbed
  • ChannelMembership table with cascade delete on both channel and user removal