feat: streamline platform and secure data access

- move the relational data center to MySQL and a standalone workbench\n- add Interface Center API credentials, policies, logs, and DBeaver SSH guidance\n- harden authentication and deployment while retiring unused management surfaces
This commit is contained in:
xuelong committed 2026-08-25 02:06:28 -07:00
1 parent 15368f2779
commit 3dd5731751
137 files changed
+8571 -14151

No files matched your search

+143 -168
View File
@@ -364,65 +364,156 @@ export const exportProjectTableCsv = (
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/records/export`,
{ params, responseType: "blob" },
);
// ── Interface Center (controlled external Data APIs) ──
export type InterfaceSummary = {
active_clients: number;
active_credentials: number;
active_policies: number;
calls_24h: number;
errors_24h: number;
data_engine: string;
public_base_path: string;
direct_database_access: string;
direct_access_enabled?: boolean;
direct_access_host?: string;
direct_access_port?: number;
direct_access_transport?: string;
ssh_tunnel_required?: boolean;
ssh_host?: string;
ssh_port?: number;
ssh_auth_method?: string;
database_host?: string;
database_port?: number;
database_account_policy?: string;
mysql_host_bind?: string;
mysql_publicly_bound?: boolean;
database_audit_enabled?: boolean;
application_audit_enabled?: boolean;
sql_console_write_enabled?: boolean;
backup_enabled?: boolean;
backup_encryption_required?: boolean;
backup_retention_days?: number;
};
export type InterfaceClient = {
id: string;
name: string;
description: string;
owner: string;
status: "active" | "disabled";
credential_count?: number;
policy_count?: number;
created_at?: string;
updated_at?: string;
};
export type InterfaceCredential = {
id: string;
client_id: string;
client_name?: string;
name: string;
key_prefix: string;
api_key?: string;
expires_at?: string | null;
last_used_at?: string | null;
revoked_at?: string | null;
created_at?: string;
};
export type InterfacePolicy = {
id: string;
client_id: string;
client_name?: string;
database_id: string;
database_name?: string;
table_code: string;
actions: string[];
readable_fields: string[];
writable_fields: string[];
row_filter: Record<string, unknown>;
status: "active" | "disabled";
created_at?: string;
updated_at?: string;
};
export type InterfaceCatalogField = {
code: string;
label: string;
data_type: string;
};
export type InterfaceCatalogTable = {
code: string;
label: string;
group: string;
fields: InterfaceCatalogField[];
};
export type InterfaceCatalogDatabase = {
project_id: string;
display_name: string;
database_name: string;
tables: InterfaceCatalogTable[];
};
export type InterfaceCallLog = {
id: number;
request_id: string;
client_name?: string | null;
method: string;
path: string;
database_id?: string | null;
table_code?: string | null;
action_name?: string | null;
status_code: number;
duration_ms: number;
source_ip?: string | null;
error_message?: string | null;
created_at: string;
};
export const getInterfaceCenterSummary = () =>
api.get<InterfaceSummary>("/interface-center/summary");
export const getInterfaceCenterCatalog = () =>
api.get<InterfaceCatalogDatabase[]>("/interface-center/catalog");
export const listInterfaceClients = () =>
api.get<InterfaceClient[]>("/interface-center/clients");
export const createInterfaceClient = (data: unknown) =>
api.post<InterfaceClient>("/interface-center/clients", data);
export const updateInterfaceClient = (clientId: string, data: unknown) =>
api.patch<InterfaceClient>(`/interface-center/clients/${encodeURIComponent(clientId)}`, data);
export const deleteInterfaceClient = (clientId: string) =>
api.delete(`/interface-center/clients/${encodeURIComponent(clientId)}`);
export const listInterfaceCredentials = (clientId?: string) =>
api.get<InterfaceCredential[]>("/interface-center/credentials", {
params: clientId ? { client_id: clientId } : undefined,
});
export const createInterfaceCredential = (clientId: string, data: unknown) =>
api.post<InterfaceCredential>(
`/interface-center/clients/${encodeURIComponent(clientId)}/credentials`,
data,
);
export const revokeInterfaceCredential = (credentialId: string) =>
api.post(`/interface-center/credentials/${encodeURIComponent(credentialId)}/revoke`, {});
export const listInterfacePolicies = () =>
api.get<InterfacePolicy[]>("/interface-center/policies");
export const createInterfacePolicy = (data: unknown) =>
api.post<InterfacePolicy>("/interface-center/policies", data);
export const updateInterfacePolicy = (policyId: string, data: unknown) =>
api.patch<InterfacePolicy>(`/interface-center/policies/${encodeURIComponent(policyId)}`, data);
export const deleteInterfacePolicy = (policyId: string) =>
api.delete(`/interface-center/policies/${encodeURIComponent(policyId)}`);
export const listInterfaceCallLogs = (limit = 200) =>
api.get<InterfaceCallLog[]>("/interface-center/logs", { params: { limit } });
export const listOntologySchemas = () => api.get("/ontology-schemas");
export const getCurrentOntologySchema = () => api.get("/ontology-schemas/current");
export const getOntologySchema = (schemaId: string | number) =>
api.get(`/ontology-schemas/${encodeURIComponent(String(schemaId))}`);
// ── Source Profiles (STEP 01) ──
export const listSourceProfiles = (params?: Record<string, string>) =>
api.get("/source-profiles", { params });
export const createSourceProfile = (data: unknown) =>
api.post("/source-profiles", data);
export const updateSourceProfile = (id: number, data: unknown) =>
api.patch(`/source-profiles/${id}`, data);
// ── Batches (STEP 01) ──
export const listBatches = (params?: Record<string, string>) =>
api.get("/batches", { params });
export const getBatch = (id: number) => api.get(`/batches/${id}`);
export const getBatchRawRecords = (id: number, params?: Record<string, unknown>) =>
api.get(`/batches/${id}/raw-records`, { params });
export const getBatchQuality = (id: number) =>
api.get(`/batches/${id}/quality-summary`);
// ── Question Traces (STEP 02) ──
export const createQuestionTrace = (data: unknown) =>
api.post("/question-traces", data);
export const listQuestionTraces = (params?: Record<string, string>) =>
api.get("/question-traces", { params });
export const getQuestionTrace = (id: number) =>
api.get(`/question-traces/${id}`);
export const simulateQuestions = () =>
api.post("/question-traces/simulate");
// ── Simulation Panel (STEP 02) ──
export const listSimQuestions = () => api.get("/simulation-panel");
export const createSimQuestion = (data: unknown) =>
api.post("/simulation-panel", data);
export const updateSimQuestion = (id: number, data: unknown) =>
api.patch(`/simulation-panel/${id}`, data);
export const deleteSimQuestion = (id: number) =>
api.delete(`/simulation-panel/${id}`);
export const importSimQuestions = (text: string) =>
api.post("/simulation-panel/import", { text });
export const adoptHitQuestions = () =>
api.post("/simulation-panel/adopt-hits");
export const aiGenerateSimQuestions = (count: number, topic?: string) =>
api.post("/simulation-panel/ai-generate", { count, topic });
// ── Audit (STEP 02) ──
export const runAudit = () => api.post("/audit/run");
export const listAuditReports = () => api.get("/audit/reports");
export const latestAuditReport = () => api.get("/audit/reports/latest");
export const listAuditGaps = () => api.get("/audit/gaps");
export const getAuditRun = (id: number) => api.get(`/audit-runs/${id}`);
export const latestAuditRun = () => api.get("/audit-runs/latest");
// ── Plaza (STEP 02) ──
export const plazaOverview = () => api.get("/plaza/overview");
export const plazaUsage = () => api.get("/plaza/usage");
export const plazaAlerts = () => api.get("/plaza/alerts");
export const plazaAmapConfig = () => api.get("/plaza/amap-config");
export const plazaWeatherHourly = () => api.get("/plaza/weather/hourly");
export const plazaMapPois = () => api.get("/plaza/map-pois");
@@ -450,94 +541,6 @@ export const graphOverview = () => api.get("/graph/overview");
export const graphQuery = (cypher: string, limit = 200) =>
api.post("/graph/query", { cypher, limit });
// ── Entities (STEP 03) ──
export const listCandidates = (params?: Record<string, string>) =>
api.get("/entities", { params });
export const getEntity = (id: number) => api.get(`/entities/${id}`);
export const getEntityProvenance = (id: number) =>
api.get(`/entities/${id}/provenance`);
export const listPoiEvidenceQuality = (params?: Record<string, unknown>) =>
api.get("/evidence/poi-quality", { params });
export const getPoiEvidenceQuality = (placeKey: string, params?: Record<string, unknown>) =>
api.get(`/evidence/poi-quality/${encodeURIComponent(placeKey)}`, { params });
export const approveEntity = (id: number) =>
api.post(`/entities/${id}/approve`);
export const rejectEntity = (id: number, note?: string) =>
api.post(`/entities/${id}/reject`, null, { params: { note } });
export const fieldDecisions = (id: number, data: unknown) =>
api.patch(`/entities/${id}/field-decisions`, data);
export const mergeEntities = (id: number, targetId: number, note?: string) =>
api.post(`/entities/${id}/merge-with/${targetId}`, null, { params: { note } });
// ── Acquisition Tasks (STEP 04) ──
export const listAcquisitionTasks = (params?: Record<string, string>) =>
api.get("/acquisition-tasks", { params });
export const createAcquisitionTask = (data: unknown) =>
api.post("/acquisition-tasks", data);
export const createTaskFromGap = (data: unknown) =>
api.post("/acquisition-tasks/from-gap", data);
export const getAcquisitionTask = (id: number) =>
api.get(`/acquisition-tasks/${id}`);
export const assignTask = (id: number, assignee: string) =>
api.post(`/acquisition-tasks/${id}/assign`, { assignee });
export const startTask = (id: number) =>
api.post(`/acquisition-tasks/${id}/start`);
export const completeTask = (id: number, resultSummary?: string) =>
api.post(`/acquisition-tasks/${id}/complete`, { result_summary: resultSummary });
export const cancelTask = (id: number, note?: string) =>
api.post(`/acquisition-tasks/${id}/cancel`, { note });
// work-order review state machine + urge
export const reviewApproveTask = (id: number, note?: string) =>
api.post(`/acquisition-tasks/${id}/review-approve`, { note });
export const reviewRejectTask = (id: number, note?: string) =>
api.post(`/acquisition-tasks/${id}/review-reject`, { note });
export const urgeTask = (id: number, note?: string) =>
api.post(`/acquisition-tasks/${id}/urge`, { note });
// ── Inventory (STEP 04) ──
export const listInventoryIssues = (params?: Record<string, string>) =>
api.get("/inventory/issues", { params });
export const runInventoryScan = () => api.post("/inventory/scan");
export const resolveIssue = (id: number, note?: string) =>
api.post(`/inventory/issues/${id}/resolve`, { resolution_note: note });
// ── Treatment History (STEP 04) ──
export const listTreatmentHistory = (params?: Record<string, unknown>) =>
api.get("/treatment-history", { params });
// ── Vocabulary (STEP 05) ──
export const listVocabulary = (params?: Record<string, string>) =>
api.get("/vocabulary", { params });
export const createVocabularyTerm = (data: unknown) =>
api.post("/vocabulary", data);
export const updateVocabularyTerm = (id: number, data: unknown) =>
api.patch(`/vocabulary/${id}`, data);
export const lookupVocabulary = (name: string) =>
api.get("/vocabulary/lookup", { params: { name } });
export const mergeVocabulary = (id: number, targetId: number) =>
api.post(`/vocabulary/${id}/merge-into/${targetId}`);
// ── Conflicts (STEP 05) ──
export const listConflicts = () => api.get("/conflicts");
export const resolveConflict = (id: number, data: unknown) =>
api.post(`/conflicts/${id}/resolve`, data);
// ── Aligner (STEP 05) ──
export const alignSuggest = (candidateIds: number[]) =>
api.post("/aligner/suggest", { candidate_ids: candidateIds });
export const autoMerge = (candidateIds: number[]) =>
api.post("/aligner/auto-merge", { candidate_ids: candidateIds });
// ── Publish Jobs (STEP 05) ──
export const listPublishJobs = () => api.get("/publish-jobs");
export const getPublishJob = (id: number) => api.get(`/publish-jobs/${id}`);
export const createPublishJob = (candidateIds: number[]) =>
api.post("/publish-jobs", { candidate_ids: candidateIds });
export const getPublishDiff = (id: number) =>
api.get(`/publish-jobs/${id}/diff`);
export const rollbackPublish = (id: number, reason?: string) =>
api.post(`/publish-jobs/${id}/rollback`, { reason });
// ── RBAC & Accounts (P1) ──
export const listRoles = () => api.get("/roles");
export const createRole = (data: unknown) => api.post("/roles", data);
@@ -563,34 +566,6 @@ export const updateUser = (id: number, data: unknown) =>
api.patch(`/users/${id}`, data);
export const deleteUser = (id: number) => api.delete(`/users/${id}`);
// ── City Areas & responsibility (P3) ──
export const listAreas = () => api.get("/areas");
export const syncAreasFromGraph = () => api.post("/areas/sync-from-graph");
export const updateArea = (areaId: string, data: unknown) =>
api.patch(`/areas/${areaId}`, data);
export const getAreaTree = () => api.get("/areas/tree");
export const getUserAreas = (userId: number) =>
api.get(`/users/${userId}/areas`);
export const setUserAreas = (
userId: number,
areaIds: string[],
customAreas: string[]
) => api.put(`/users/${userId}/areas`, { area_ids: areaIds, custom_areas: customAreas });
// ── Notifications / inbox (P4) ──
export const listNotifications = (onlyUnread = false) =>
api.get("/notifications", { params: { only_unread: onlyUnread } });
export const unreadCount = () => api.get("/notifications/unread-count");
export const markNotificationRead = (id: number) =>
api.post(`/notifications/${id}/read`);
export const markAllNotificationsRead = () =>
api.post("/notifications/read-all");
// ── Agent settings ──
export const getAgentSettings = () => api.get("/agent-settings");
export const saveAgentSettings = (config: unknown) =>
api.put("/agent-settings", config);
// ── Super Agent (autonomous KG curator) ──
export const superAgentRun = () => api.post("/super-agent/run", {});
export const superAgentLatest = () => api.get("/super-agent/runs/latest");