feat(gmw): public features #2-#6 — live moderation feed, toxic topic trends, channel timeline, CSV export, activity heatmap
- Live Moderation Feed: gateway publishes discord:moderation:action (Redis) → backend WS emits moderation_action → public web shows realtime stream. - Toxic Topic Trends: backend moderation.trends aggregates categories/severity/action_type (read-only) → SVG bar + donut. - Channel Timeline: messages view gets Feed/Timeline toggle with date-grouped separators. - CSV Export: client-side downloadCsv for moderation actions (no backend write scope). - Activity Heatmap: backend messages.activity (per-hour volume by channel) → pure-SVG grid. User reputation deliberately excluded — no such feature exists in the codebase. All read-only / public-facing / fully automatic per project rules.
This commit is contained in:
@@ -4,8 +4,16 @@ import type * as schema from "../../shared/database/schema.js";
|
||||
import { moderationActionsTable } from "../../shared/database/schema.js";
|
||||
import { buildCursorCondition, pageResult } from "../../shared/index.js";
|
||||
import { createChildLogger, type Logger } from "../../shared/logger/index.js";
|
||||
import type { EventBroadcaster } from "../event-broadcaster/eventBroadcaster.js";
|
||||
import type { ModerationAction, PageResult } from "../message-capture/types.js";
|
||||
|
||||
let _eventBroadcaster: EventBroadcaster | null = null;
|
||||
|
||||
/** Inject the gateway's event broadcaster so actions can be published live. */
|
||||
export function setModerationEventBroadcaster(eb: EventBroadcaster): void {
|
||||
_eventBroadcaster = eb;
|
||||
}
|
||||
|
||||
// ─── ModerationActionsDb Class ──────────────────────────────────────────────
|
||||
|
||||
export class ModerationActionsDb {
|
||||
@@ -38,7 +46,16 @@ export class ModerationActionsDb {
|
||||
})
|
||||
.returning();
|
||||
|
||||
return rows[0] as ModerationAction;
|
||||
const created = rows[0] as ModerationAction;
|
||||
|
||||
// Fire-and-forget live broadcast (backend WS → frontend feed).
|
||||
if (_eventBroadcaster) {
|
||||
_eventBroadcaster
|
||||
.moderationAction(created as unknown as Record<string, unknown>)
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
return created;
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user