feat(gmw): public features #7-14 — scam domains, top channels, hourly heatmap, category drill-down, coverage stats, channel culture glossary, term KB, edit history

ALSO fixes: dashboard.repository still JOINed dropped user_reputations table (listUsers/getUserDetail crash).
This commit is contained in:
asepharyana
2026-08-18 20:45:12 +07:00
parent 2a8f6d9062
commit 00e8d68ce5
38 changed files with 1542 additions and 25 deletions
+7
View File
@@ -6,9 +6,16 @@ export { orpc } from "../orpc/client";
export { chatbotApi } from "./chatbot";
export { configApi } from "./config";
export { dashboardApi } from "./dashboard";
export { knowledgeApi } from "./knowledge";
export { mediaApi } from "./media";
export { messagesApi } from "./messages";
export { moderationApi } from "./moderation";
export { recordingsApi } from "./recordings";
// Re-export server-side fetchers for use inside React Server Components.
export {
getChannelCultures,
getGlossary,
getRecentEdits,
} from "./server";
export { uiStateApi } from "./ui-state";
export { voiceApi } from "./voice";
@@ -0,0 +1,16 @@
import { orpc } from "@/lib/orpc/client";
import type { ChannelCultureRow, GlossaryRow } from "@/lib/types";
export const knowledgeApi = {
channelCultures: (limit = 100, search?: string) =>
orpc.knowledge.channelCultures({
limit,
search,
}) as unknown as Promise<ChannelCultureRow[]>,
glossary: (limit = 100, search?: string) =>
orpc.knowledge.glossary({
limit,
search,
}) as unknown as Promise<GlossaryRow[]>,
};
@@ -1,6 +1,7 @@
import { orpc } from "@/lib/orpc/client";
import type {
AttachmentRecord,
EditHistoryRow,
MessageActivityBucket,
MessageRecord,
SemanticSearchResult,
@@ -80,4 +81,10 @@ export const messagesApi = {
orpc.messages.activity({ days }) as unknown as Promise<
MessageActivityBucket[]
>,
// Public, read-only recent message edits (evasion tracker).
getRecentEdits: (limit = 50, channelId?: string) =>
orpc.messages.editHistory({ limit, channelId }) as unknown as Promise<
EditHistoryRow[]
>,
};
@@ -1,5 +1,10 @@
import { orpc } from "@/lib/orpc/client";
import type {
CategoryAction,
FlaggedChannel,
FlaggedDomain,
HourlyModeration,
ModerationCoverage,
ModerationStats,
ModerationTrends,
PaginatedModerationActions,
@@ -24,4 +29,25 @@ export const moderationApi = {
getTrends: (days = 30) =>
orpc.moderation.trends({ days }) as unknown as Promise<ModerationTrends>,
getTopDomains: (days = 30) =>
orpc.moderation.topDomains({ days }) as unknown as Promise<FlaggedDomain[]>,
getTopChannels: (days = 30) =>
orpc.moderation.topChannels({ days }) as unknown as Promise<
FlaggedChannel[]
>,
getHourlyModeration: (days = 30) =>
orpc.moderation.byHour({ days }) as unknown as Promise<HourlyModeration[]>,
getByCategory: (days = 30, category: string) =>
orpc.moderation.byCategory({ days, category }) as unknown as Promise<
CategoryAction[]
>,
getCoverage: (days = 30) =>
orpc.moderation.coverage({
days,
}) as unknown as Promise<ModerationCoverage>,
};
+52
View File
@@ -16,11 +16,19 @@ import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/fetch";
import type {
AppConfig,
ChannelCultureRow,
DashboardActivity,
DashboardStats,
EditHistoryRow,
FlaggedChannel,
FlaggedDomain,
GlossaryRow,
Guild,
HourlyModeration,
MediaState,
ModerationCoverage,
ModerationStats,
ModerationTrends,
PaginatedModerationActions,
PaginatedRecordings,
VoiceStatus,
@@ -84,6 +92,33 @@ export async function getModerationActions(limit = 100) {
})) as unknown as PaginatedModerationActions;
return res.data;
}
export async function getModerationTrends(
days = 30,
): Promise<ModerationTrends> {
return serverOrpc().moderation.trends({
days,
}) as unknown as Promise<ModerationTrends>;
}
export async function getTopFlaggedDomains(days = 30) {
return serverOrpc().moderation.topDomains({
days,
}) as unknown as FlaggedDomain[];
}
export async function getTopFlaggedChannels(days = 30) {
return serverOrpc().moderation.topChannels({
days,
}) as unknown as FlaggedChannel[];
}
export async function getHourlyModeration(days = 30) {
return serverOrpc().moderation.byHour({
days,
}) as unknown as HourlyModeration[];
}
export async function getCoverage(days = 30) {
return serverOrpc().moderation.coverage({
days,
}) as unknown as ModerationCoverage;
}
// ---- Voice ----
export async function getGuilds(): Promise<Guild[]> {
@@ -122,3 +157,20 @@ export async function getMessages(
nextCursor: string | null;
}>;
}
// ---- Knowledge (public read-only) ----
export async function getChannelCultures(limit = 100) {
return serverOrpc().knowledge.channelCultures({
limit,
}) as unknown as Promise<ChannelCultureRow[]>;
}
export async function getGlossary(limit = 100) {
return serverOrpc().knowledge.glossary({
limit,
}) as unknown as Promise<GlossaryRow[]>;
}
export async function getRecentEdits(limit = 50): Promise<EditHistoryRow[]> {
return serverOrpc().messages.editHistory({
limit,
}) as unknown as Promise<EditHistoryRow[]>;
}