feat: ship enterprise control and desktop governance

This commit is contained in:
AI Bot
2026-05-11 14:59:26 +08:00
parent 0757d07521
commit a311280238
285 changed files with 48574 additions and 2428 deletions

View File

@@ -0,0 +1,614 @@
import { NextRequest } from "next/server";
import { requireRequestSession } from "@/lib/boss-auth";
import { buildRequestAuditMeta } from "@/lib/boss-audit";
import { requireCsrfSafeMutation } from "@/lib/boss-csrf";
import { BOSS_PERMISSION_TEMPLATES } from "@/lib/boss-access-templates";
import {
appendPermissionAuditLog,
assignAccountCompanyByAdmin,
assignDeviceCompanyByAdmin,
bulkImportAuthAccountsByAdmin,
previewBulkImportAuthAccountsByAdmin,
readState,
reclaimAuthAccountByAdmin,
resetAuthAccountPasswordByAdmin,
revokeAccessGrant,
saveAccountDeviceGrant,
saveAccountProjectGrant,
saveAccountSkillGrant,
setAdminCompanyStatusByAdmin,
setAuthAccountMfaRequiredByAdmin,
setAuthAccountStatusByAdmin,
upsertAdminCompanyByAdmin,
upsertAuthAccountByAdmin,
} from "@/lib/boss-data";
import type { AuthAccount, AuthAccountStatus, AuthRole, BossPermission, Device, Project } from "@/lib/boss-data";
import { jsonNoStore } from "@/lib/api-response";
const validRoles = new Set<AuthRole>(["member", "admin", "highest_admin"]);
const validImportRoles = new Set<AuthRole>(["member", "admin"]);
const validAccountStatuses = new Set<AuthAccountStatus>(["active", "disabled"]);
const validCompanyStatuses = new Set(["active", "disabled"]);
const validCompanyPlanTiers = new Set(["trial", "standard", "enterprise"]);
const validPermissions = new Set<BossPermission>([
"device.view",
"device.manage",
"project.view",
"thread.chat",
"master_agent.ask",
"master_agent.takeover",
"computer.control",
"skill.view",
"skill.use",
"skill.manage",
"account.manage",
"audit.view",
]);
function publicAuthAccount(account: AuthAccount) {
const { passwordHash, mfaSecret, ...safeAccount } = account;
void passwordHash;
void mfaSecret;
return safeAccount;
}
function publicAdminDevice(device: Device) {
return {
id: device.id,
name: device.name,
avatar: device.avatar,
account: device.account,
status: device.status,
companyId: device.companyId,
source: device.source,
lastSeenAt: device.lastSeenAt,
preferredExecutionMode: device.preferredExecutionMode,
capabilities: device.capabilities,
};
}
function publicAdminProject(project: Project) {
return {
id: project.id,
name: project.name,
deviceIds: project.deviceIds,
threadMeta: project.threadMeta,
isGroup: project.isGroup,
updatedAt: project.updatedAt,
lastMessageAt: project.lastMessageAt,
collaborationMode: project.collaborationMode,
approvalState: project.approvalState,
riskLevel: project.riskLevel,
};
}
function buildSkillCatalog(skills: Array<{
skillId: string;
deviceId: string;
name: string;
description: string;
path: string;
invocation: string;
category: string;
updatedAt: string;
}>) {
const catalog = new Map<string, {
name: string;
invocation: string;
description: string;
deviceCount: number;
devices: Array<{ skillId: string; deviceId: string; path: string; category: string; updatedAt: string }>;
}>();
for (const skill of skills) {
const key = skill.name.trim() || skill.skillId;
const existing = catalog.get(key) ?? {
name: key,
invocation: skill.invocation,
description: skill.description,
deviceCount: 0,
devices: [],
};
existing.devices.push({
skillId: skill.skillId,
deviceId: skill.deviceId,
path: skill.path,
category: skill.category,
updatedAt: skill.updatedAt,
});
existing.deviceCount = existing.devices.length;
catalog.set(key, existing);
}
return [...catalog.values()].sort((left, right) => left.name.localeCompare(right.name, "zh-CN"));
}
function forbidden() {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
async function requireHighestAdmin(request: NextRequest) {
const session = await requireRequestSession(request);
if (!session) {
return { ok: false as const, response: jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 }) };
}
if (session.role !== "highest_admin") {
return { ok: false as const, response: forbidden() };
}
return { ok: true as const, session };
}
function stringValue(value: unknown) {
return typeof value === "string" ? value.trim() : "";
}
function permissionValues(value: unknown): BossPermission[] {
if (!Array.isArray(value)) {
return [];
}
return value.filter((item): item is BossPermission =>
typeof item === "string" && validPermissions.has(item as BossPermission),
);
}
function stringArray(value: unknown) {
if (!Array.isArray(value)) {
return [];
}
return value.map(stringValue).filter(Boolean);
}
function accountImportValues(value: unknown) {
if (!Array.isArray(value)) {
return [];
}
return value
.filter((item): item is Record<string, unknown> => item !== null && typeof item === "object")
.map((item) => ({
account: stringValue(item.account),
displayName: stringValue(item.displayName),
role: validImportRoles.has(stringValue(item.role) as AuthRole) ? (stringValue(item.role) as AuthRole) : "member",
password: stringValue(item.password),
verificationEmail: stringValue(item.verificationEmail),
}))
.filter((item) => Boolean(item.account));
}
function idSegment(value: string) {
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "item";
}
export async function GET(request: NextRequest) {
const auth = await requireHighestAdmin(request);
if (!auth.ok) {
return auth.response;
}
const state = await readState();
return jsonNoStore({
ok: true,
companies: state.adminCompanies,
accounts: state.authAccounts.map(publicAuthAccount),
devices: state.devices.map(publicAdminDevice),
projects: state.projects.map(publicAdminProject),
skills: state.deviceSkills,
skillCatalog: buildSkillCatalog(state.deviceSkills),
permissionTemplates: BOSS_PERMISSION_TEMPLATES,
grants: {
devices: state.accountDeviceGrants,
projects: state.accountProjectGrants,
skills: state.accountSkillGrants,
},
auditLogs: state.permissionAuditLogs,
});
}
export async function POST(request: NextRequest) {
const csrf = requireCsrfSafeMutation(request);
if (csrf) return csrf;
const auth = await requireHighestAdmin(request);
if (!auth.ok) {
return auth.response;
}
const body = (await request.json().catch(() => ({}))) as Record<string, unknown>;
const action = stringValue(body.action);
const auditMeta = buildRequestAuditMeta(request);
if (action === "upsert_account") {
const account = stringValue(body.account);
const role = stringValue(body.role) as AuthRole;
if (!account || !validRoles.has(role)) {
return jsonNoStore({ ok: false, message: "ACCOUNT_OR_ROLE_INVALID" }, { status: 400 });
}
const saved = await upsertAuthAccountByAdmin({
account,
displayName: stringValue(body.displayName),
role,
password: stringValue(body.password),
verificationEmail: stringValue(body.verificationEmail),
companyId: stringValue(body.companyId) || undefined,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, account: publicAuthAccount(saved) });
}
if (action === "set_account_status") {
const account = stringValue(body.account);
const status = stringValue(body.status) as AuthAccountStatus;
if (!account || !validAccountStatuses.has(status)) {
return jsonNoStore({ ok: false, message: "ACCOUNT_STATUS_INVALID" }, { status: 400 });
}
try {
const saved = await setAuthAccountStatusByAdmin({
account,
status,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, account: publicAuthAccount(saved) });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore(
{ ok: false, message },
{ status: message === "ACCOUNT_NOT_FOUND" ? 404 : 400 },
);
}
}
if (action === "set_account_mfa_required") {
const account = stringValue(body.account);
if (!account) {
return jsonNoStore({ ok: false, message: "ACCOUNT_REQUIRED" }, { status: 400 });
}
try {
const saved = await setAuthAccountMfaRequiredByAdmin({
account,
required: body.required === true,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({
ok: true,
account: publicAuthAccount(saved),
mfaSetupSecret: body.required === true ? saved.mfaSecret : undefined,
});
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message === "ACCOUNT_NOT_FOUND" ? 404 : 400 });
}
}
if (action === "reset_account_password") {
const account = stringValue(body.account);
const password = stringValue(body.password);
if (!account || !password) {
return jsonNoStore({ ok: false, message: "ACCOUNT_OR_PASSWORD_INVALID" }, { status: 400 });
}
try {
const saved = await resetAuthAccountPasswordByAdmin({
account,
password,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, account: publicAuthAccount(saved) });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore(
{ ok: false, message },
{ status: message === "ACCOUNT_NOT_FOUND" ? 404 : 400 },
);
}
}
if (action === "upsert_company") {
const companyId = stringValue(body.companyId);
if (!companyId) {
return jsonNoStore({ ok: false, message: "COMPANY_ID_REQUIRED" }, { status: 400 });
}
const company = await upsertAdminCompanyByAdmin({
companyId,
name: stringValue(body.name),
ownerAccount: stringValue(body.ownerAccount),
successOwnerAccount: stringValue(body.successOwnerAccount),
planTier: validCompanyPlanTiers.has(stringValue(body.planTier))
? (stringValue(body.planTier) as "trial" | "standard" | "enterprise")
: undefined,
contractExpiresAt: stringValue(body.contractExpiresAt),
note: stringValue(body.note),
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, company });
}
if (action === "set_company_status") {
const companyId = stringValue(body.companyId);
const status = stringValue(body.status);
if (!companyId || !validCompanyStatuses.has(status)) {
return jsonNoStore({ ok: false, message: "COMPANY_STATUS_INVALID" }, { status: 400 });
}
try {
const result = await setAdminCompanyStatusByAdmin({
companyId,
status: status as "active" | "disabled",
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, ...result });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message === "COMPANY_NOT_FOUND" ? 404 : 400 });
}
}
if (action === "assign_account_company") {
const account = stringValue(body.account);
const companyId = stringValue(body.companyId);
if (!account || !companyId) {
return jsonNoStore({ ok: false, message: "ACCOUNT_OR_COMPANY_INVALID" }, { status: 400 });
}
try {
const saved = await assignAccountCompanyByAdmin({
account,
companyId,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, account: publicAuthAccount(saved) });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message.endsWith("_NOT_FOUND") ? 404 : 400 });
}
}
if (action === "assign_device_company") {
const deviceId = stringValue(body.deviceId);
const companyId = stringValue(body.companyId);
if (!deviceId || !companyId) {
return jsonNoStore({ ok: false, message: "DEVICE_OR_COMPANY_INVALID" }, { status: 400 });
}
try {
const device = await assignDeviceCompanyByAdmin({
deviceId,
companyId,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, device });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message.endsWith("_NOT_FOUND") ? 404 : 400 });
}
}
if (action === "bulk_import_accounts") {
const companyId = stringValue(body.companyId);
const accounts = accountImportValues(body.accounts);
if (!companyId || accounts.length === 0) {
return jsonNoStore({ ok: false, message: "BULK_IMPORT_INVALID" }, { status: 400 });
}
try {
const imported = await bulkImportAuthAccountsByAdmin({
companyId,
accounts,
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({ ok: true, imported: imported.map(publicAuthAccount) });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message.endsWith("_NOT_FOUND") ? 404 : 400 });
}
}
if (action === "preview_bulk_import_accounts") {
const companyId = stringValue(body.companyId);
const accounts = accountImportValues(body.accounts);
if (!companyId || accounts.length === 0) {
return jsonNoStore({ ok: false, message: "BULK_IMPORT_INVALID" }, { status: 400 });
}
try {
const preview = await previewBulkImportAuthAccountsByAdmin({
companyId,
accounts,
});
return jsonNoStore({ ok: true, preview });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message === "COMPANY_NOT_FOUND" ? 404 : 400 });
}
}
if (action === "reclaim_account") {
const account = stringValue(body.account);
if (!account) {
return jsonNoStore({ ok: false, message: "ACCOUNT_REQUIRED" }, { status: 400 });
}
try {
const result = await reclaimAuthAccountByAdmin({
account,
reason: stringValue(body.reason),
actorAccount: auth.session.account,
auditMeta,
});
return jsonNoStore({
ok: true,
account: publicAuthAccount(result.account),
removedGrants: result.removedGrants,
});
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: message === "ACCOUNT_NOT_FOUND" ? 404 : 400 });
}
}
if (action === "grant_device") {
const account = stringValue(body.account);
const deviceId = stringValue(body.deviceId);
const permissions = permissionValues(body.permissions);
if (!account || !deviceId || permissions.length === 0) {
return jsonNoStore({ ok: false, message: "DEVICE_GRANT_INVALID" }, { status: 400 });
}
const grant = await saveAccountDeviceGrant({
grantId: stringValue(body.grantId) || undefined,
account,
deviceId,
permissions,
grantedBy: auth.session.account,
expiresAt: stringValue(body.expiresAt) || undefined,
note: stringValue(body.note) || undefined,
auditMeta,
});
return jsonNoStore({ ok: true, grant });
}
if (action === "grant_project") {
const account = stringValue(body.account);
const projectId = stringValue(body.projectId);
const permissions = permissionValues(body.permissions);
if (!account || !projectId || permissions.length === 0) {
return jsonNoStore({ ok: false, message: "PROJECT_GRANT_INVALID" }, { status: 400 });
}
const grant = await saveAccountProjectGrant({
grantId: stringValue(body.grantId) || undefined,
account,
projectId,
deviceId: stringValue(body.deviceId) || undefined,
permissions,
inheritFromDeviceGrant: body.inheritFromDeviceGrant === true,
grantedBy: auth.session.account,
expiresAt: stringValue(body.expiresAt) || undefined,
note: stringValue(body.note) || undefined,
auditMeta,
});
return jsonNoStore({ ok: true, grant });
}
if (action === "grant_skill") {
const account = stringValue(body.account);
const skillId = stringValue(body.skillId);
const permissions = permissionValues(body.permissions);
if (!account || !skillId || permissions.length === 0) {
return jsonNoStore({ ok: false, message: "SKILL_GRANT_INVALID" }, { status: 400 });
}
const grant = await saveAccountSkillGrant({
grantId: stringValue(body.grantId) || undefined,
account,
skillId,
deviceId: stringValue(body.deviceId) || undefined,
projectId: stringValue(body.projectId) || undefined,
permissions,
grantedBy: auth.session.account,
expiresAt: stringValue(body.expiresAt) || undefined,
note: stringValue(body.note) || undefined,
auditMeta,
});
return jsonNoStore({ ok: true, grant });
}
if (action === "apply_template") {
const account = stringValue(body.account);
const templateId = stringValue(body.templateId);
const template = BOSS_PERMISSION_TEMPLATES.find((item) => item.templateId === templateId);
const deviceIds = stringArray(body.deviceIds);
const projectIds = stringArray(body.projectIds);
const skillIds = stringArray(body.skillIds);
if (!account || !template || deviceIds.length + projectIds.length + skillIds.length === 0) {
return jsonNoStore({ ok: false, message: "ACCESS_TEMPLATE_INVALID" }, { status: 400 });
}
const state = await readState();
if (!state.authAccounts.some((item) => item.account === account)) {
return jsonNoStore({ ok: false, message: "ACCOUNT_NOT_FOUND" }, { status: 404 });
}
const missingDevice = deviceIds.find((deviceId) => !state.devices.some((device) => device.id === deviceId));
const missingProject = projectIds.find((projectId) => !state.projects.some((project) => project.id === projectId));
const missingSkill = skillIds.find((skillId) => !state.deviceSkills.some((skill) => skill.skillId === skillId));
if (missingDevice || missingProject || missingSkill) {
return jsonNoStore({
ok: false,
message: "ACCESS_TEMPLATE_TARGET_NOT_FOUND",
missingDevice,
missingProject,
missingSkill,
}, { status: 404 });
}
const deviceGrants = [];
for (const deviceId of deviceIds) {
deviceGrants.push(await saveAccountDeviceGrant({
grantId: `grant-template-${idSegment(templateId)}-device-${idSegment(account)}-${idSegment(deviceId)}`,
account,
deviceId,
permissions: template.devicePermissions,
grantedBy: auth.session.account,
note: template.name,
auditMeta,
}));
}
const projectGrants = [];
for (const projectId of projectIds) {
projectGrants.push(await saveAccountProjectGrant({
grantId: `grant-template-${idSegment(templateId)}-project-${idSegment(account)}-${idSegment(projectId)}`,
account,
projectId,
permissions: template.projectPermissions,
grantedBy: auth.session.account,
note: template.name,
auditMeta,
}));
}
const skillGrants = [];
for (const skillId of skillIds) {
const skill = state.deviceSkills.find((item) => item.skillId === skillId);
skillGrants.push(await saveAccountSkillGrant({
grantId: `grant-template-${idSegment(templateId)}-skill-${idSegment(account)}-${idSegment(skillId)}`,
account,
skillId,
deviceId: skill?.deviceId,
permissions: template.skillPermissions,
grantedBy: auth.session.account,
note: template.name,
auditMeta,
}));
}
await appendPermissionAuditLog({
actorAccount: auth.session.account,
action: "grant.updated",
targetAccount: account,
permissions: [
...template.devicePermissions,
...template.projectPermissions,
...template.skillPermissions,
],
detail: `template:${template.templateId}`,
...auditMeta,
});
return jsonNoStore({
ok: true,
template,
grants: {
devices: deviceGrants,
projects: projectGrants,
skills: skillGrants,
},
});
}
if (action === "revoke_grant") {
const grantId = stringValue(body.grantId);
if (!grantId) {
return jsonNoStore({ ok: false, message: "GRANT_ID_REQUIRED" }, { status: 400 });
}
const grant = await revokeAccessGrant(grantId, auth.session.account, auditMeta);
return jsonNoStore({ ok: true, grant });
}
return jsonNoStore({ ok: false, message: "UNKNOWN_ACTION" }, { status: 400 });
}

View File

@@ -0,0 +1,219 @@
import { NextRequest } from "next/server";
import { jsonNoStore } from "@/lib/api-response";
import { requireRequestSession } from "@/lib/boss-auth";
import { BOSS_PERMISSION_TEMPLATES } from "@/lib/boss-access-templates";
import { buildAdminOverview } from "@/lib/boss-admin-overview";
import { readState, type BossState } from "@/lib/boss-data";
const MENU_TREE = [
{ key: "workbench", label: "工作台" },
{ key: "tenant", label: "租户管理" },
{ key: "user", label: "账号管理" },
{ key: "role", label: "角色权限" },
{
key: "resource",
label: "资源授权",
children: [
{ key: "resource.devices", label: "设备资源" },
{ key: "resource.projects", label: "项目线程" },
{ key: "resource.skills", label: "Skill 资源" },
],
},
{ key: "skills", label: "Skill 中心" },
{ key: "risk", label: "风险告警" },
{ key: "audit", label: "审计日志" },
{ key: "system", label: "系统设置" },
] as const;
function companyNameMap(state: BossState) {
return new Map(state.adminCompanies.map((company) => [company.companyId, company.name]));
}
function companyNameFor(state: BossState, companyId?: string) {
if (!companyId || companyId === "default") return "默认公司";
return companyNameMap(state).get(companyId) ?? companyId;
}
function safeUsers(state: BossState) {
return state.authAccounts.map((account) => ({
id: account.id,
account: account.account,
displayName: account.displayName,
role: account.role,
status: account.status ?? "active",
companyId: account.companyId ?? "default",
companyName: companyNameFor(state, account.companyId),
primaryDeviceId: account.primaryDeviceId,
codexNodeId: account.codexNodeId,
codexNodeLabel: account.codexNodeLabel,
lastLoginAt: account.lastLoginAt,
lastLoginMethod: account.lastLoginMethod,
mfaRequired: Boolean(account.mfaRequired),
createdAt: account.createdAt,
updatedAt: account.updatedAt,
}));
}
function skillResources(state: BossState) {
const byName = new Map<
string,
{
skillId: string;
name: string;
description: string;
category?: string;
invocation?: string;
sourceType: "device" | "catalog";
deviceCount: number;
devices: Array<{ deviceId: string; updatedAt: string }>;
updatedAt: string;
}
>();
for (const skill of state.deviceSkills) {
const existing = byName.get(skill.name);
if (existing) {
existing.deviceCount += existing.devices.some((device) => device.deviceId === skill.deviceId) ? 0 : 1;
existing.devices.push({ deviceId: skill.deviceId, updatedAt: skill.updatedAt });
if (skill.updatedAt.localeCompare(existing.updatedAt) > 0) {
existing.updatedAt = skill.updatedAt;
}
continue;
}
byName.set(skill.name, {
skillId: skill.skillId,
name: skill.name,
description: skill.description,
category: skill.category,
invocation: skill.invocation,
sourceType: "device",
deviceCount: 1,
devices: [{ deviceId: skill.deviceId, updatedAt: skill.updatedAt }],
updatedAt: skill.updatedAt,
});
}
for (const catalogItem of state.skillCatalog) {
if (byName.has(catalogItem.name)) continue;
byName.set(catalogItem.name, {
skillId: catalogItem.skillId,
name: catalogItem.name,
description: catalogItem.description,
category: catalogItem.category,
sourceType: "catalog",
deviceCount: 0,
devices: [],
updatedAt: catalogItem.updatedAt,
});
}
return [...byName.values()].sort(
(left, right) => right.deviceCount - left.deviceCount || left.name.localeCompare(right.name, "zh-CN"),
);
}
function projectResources(state: BossState) {
return state.projects.map((project) => ({
id: project.id,
name: project.name,
deviceIds: project.deviceIds,
deviceCount: project.deviceIds.length,
folderName: project.threadMeta.folderName,
threadId: project.threadMeta.threadId,
threadDisplayName: project.threadMeta.threadDisplayName,
isGroup: project.isGroup,
collaborationMode: project.collaborationMode,
unreadCount: project.unreadCount,
riskLevel: project.riskLevel,
updatedAt: project.updatedAt,
lastMessageAt: project.lastMessageAt,
}));
}
function rolesContract() {
return {
builtInRoles: [
{
role: "highest_admin",
label: "超级管理员",
description: "平台侧最高权限可管理全部公司、账号、设备、项目、Skill、风险和审计。",
},
{
role: "admin",
label: "企业管理员",
description: "企业内管理员,按授权范围管理本公司资源。",
},
{
role: "member",
label: "成员账号",
description: "企业子账号,只能访问已分配的电脑、项目和 Skill。",
},
],
permissionTemplates: BOSS_PERMISSION_TEMPLATES,
};
}
function buildBackofficePayload(state: BossState) {
const overview = buildAdminOverview(state);
const skills = skillResources(state);
return {
ok: true,
menuTree: MENU_TREE,
workbench: {
summary: overview.summary,
companies: overview.companies.slice(0, 10),
devices: overview.devices.slice(0, 20),
risks: overview.risks.slice(0, 20),
notifications: overview.notifications,
grantsSummary: overview.grantsSummary,
},
tenants: overview.companies.map((company) => ({
...company,
lifecycleStatus: company.status ?? "active",
})),
users: safeUsers(state),
roles: rolesContract(),
resourceGroups: {
devices: overview.devices,
projects: projectResources(state),
skills,
grants: {
devices: state.accountDeviceGrants,
projects: state.accountProjectGrants,
skills: state.accountSkillGrants,
},
},
audit: {
risks: overview.risks,
notifications: overview.notifications,
riskTimeline: overview.riskTimeline,
permissionLogs: state.permissionAuditLogs
.slice()
.sort((left, right) => right.createdAt.localeCompare(left.createdAt))
.slice(0, 100),
},
yudaoMapping: {
tenant: "adminCompanies",
user: "authAccounts",
role: "BOSS_PERMISSION_TEMPLATES",
menu: "menuTree",
operateLog: "permissionAuditLogs",
resource: "devices/projects/deviceSkills",
risk: "opsFaults/threadContextAlerts/masterAgentTasks/adminNotifications",
},
};
}
export async function GET(request: NextRequest) {
const session = await requireRequestSession(request);
if (!session) {
return jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
}
if (session.role !== "highest_admin") {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
const state = await readState();
return jsonNoStore(buildBackofficePayload(state));
}

View File

@@ -0,0 +1,29 @@
import { NextRequest } from "next/server";
import { jsonNoStore } from "@/lib/api-response";
import { requireRequestSession } from "@/lib/boss-auth";
import { requireCsrfSafeMutation } from "@/lib/boss-csrf";
import { dispatchAdminRiskNotifications } from "@/lib/boss-data";
function forbidden() {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
export async function POST(request: NextRequest) {
const csrf = requireCsrfSafeMutation(request);
if (csrf) return csrf;
const session = await requireRequestSession(request);
if (!session) {
return jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
}
if (session.role !== "highest_admin") {
return forbidden();
}
const body = (await request.json().catch(() => ({}))) as { max?: number };
const result = await dispatchAdminRiskNotifications({
actorAccount: session.account,
max: typeof body.max === "number" && Number.isFinite(body.max) ? body.max : undefined,
});
return jsonNoStore({ ok: true, ...result });
}

View File

@@ -0,0 +1,21 @@
import { NextRequest } from "next/server";
import { jsonNoStore } from "@/lib/api-response";
import { requireRequestSession } from "@/lib/boss-auth";
import { buildAdminOverview } from "@/lib/boss-admin-overview";
import { readState } from "@/lib/boss-data";
export async function GET(request: NextRequest) {
const session = await requireRequestSession(request);
if (!session) {
return jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
}
if (session.role !== "highest_admin") {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
const state = await readState();
return jsonNoStore({
ok: true,
...buildAdminOverview(state),
});
}

View File

@@ -0,0 +1,67 @@
import { NextRequest } from "next/server";
import { jsonNoStore } from "@/lib/api-response";
import { requireRequestSession } from "@/lib/boss-auth";
import { requireCsrfSafeMutation } from "@/lib/boss-csrf";
import { handleAdminRiskAction, type AdminRiskAction } from "@/lib/boss-data";
const validActions = new Set<AdminRiskAction>(["ack", "resolve", "create_repair_ticket", "assign_owner", "set_sla"]);
function stringValue(value: unknown) {
return typeof value === "string" ? value.trim() : "";
}
function statusForError(error: unknown) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
if (message === "RISK_TARGET_NOT_FOUND") return 404;
if (
message === "RISK_ACTION_UNSUPPORTED" ||
message === "RISK_ID_INVALID" ||
message === "RISK_OWNER_REQUIRED" ||
message === "RISK_SLA_REQUIRED"
) return 400;
return 500;
}
export async function POST(request: NextRequest) {
const csrf = requireCsrfSafeMutation(request);
if (csrf) return csrf;
const session = await requireRequestSession(request);
if (!session) {
return jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
}
if (session.role !== "highest_admin") {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
const body = (await request.json().catch(() => ({}))) as Record<string, unknown>;
const riskId = stringValue(body.riskId);
const action = stringValue(body.action) as AdminRiskAction;
if (!riskId || !validActions.has(action)) {
return jsonNoStore({ ok: false, message: "RISK_ACTION_INVALID" }, { status: 400 });
}
const ownerAccount = stringValue(body.ownerAccount);
const slaDueAt = stringValue(body.slaDueAt);
const note = stringValue(body.note);
if (action === "assign_owner" && !ownerAccount) {
return jsonNoStore({ ok: false, message: "RISK_OWNER_REQUIRED" }, { status: 400 });
}
if (action === "set_sla" && !slaDueAt) {
return jsonNoStore({ ok: false, message: "RISK_SLA_REQUIRED" }, { status: 400 });
}
try {
const result = await handleAdminRiskAction({
riskId,
action,
actorAccount: session.account,
ownerAccount,
slaDueAt,
note,
});
return jsonNoStore({ ok: true, riskId, action, ...result });
} catch (error) {
const message = error instanceof Error ? error.message : "UNKNOWN_ERROR";
return jsonNoStore({ ok: false, message }, { status: statusForError(error) });
}
}

View File

@@ -0,0 +1,27 @@
import { NextRequest } from "next/server";
import { jsonNoStore } from "@/lib/api-response";
import { requireRequestSession } from "@/lib/boss-auth";
import { requireCsrfSafeMutation } from "@/lib/boss-csrf";
import { scanAdminRiskNotifications } from "@/lib/boss-data";
function forbidden() {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
export async function POST(request: NextRequest) {
const csrf = requireCsrfSafeMutation(request);
if (csrf) return csrf;
const session = await requireRequestSession(request);
if (!session) {
return jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
}
if (session.role !== "highest_admin") {
return forbidden();
}
const result = await scanAdminRiskNotifications({
actorAccount: session.account,
});
return jsonNoStore({ ok: true, ...result });
}

View File

@@ -0,0 +1,110 @@
import { NextRequest } from "next/server";
import { requireRequestSession } from "@/lib/boss-auth";
import { buildRequestAuditMeta } from "@/lib/boss-audit";
import { requireCsrfSafeMutation } from "@/lib/boss-csrf";
import {
createSkillLifecycleRequest,
readState,
type SkillLifecycleAction,
} from "@/lib/boss-data";
import { jsonNoStore } from "@/lib/api-response";
const validActions = new Set<SkillLifecycleAction>([
"install",
"update",
"uninstall",
"rollback",
"version_lock",
]);
function stringValue(value: unknown) {
return typeof value === "string" ? value.trim() : "";
}
function forbidden() {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
async function requireHighestAdmin(request: NextRequest) {
const session = await requireRequestSession(request);
if (!session) {
return { ok: false as const, response: jsonNoStore({ ok: false, message: "UNAUTHORIZED" }, { status: 401 }) };
}
if (session.role !== "highest_admin") {
return { ok: false as const, response: forbidden() };
}
return { ok: true as const, session };
}
export async function GET(request: NextRequest) {
const auth = await requireHighestAdmin(request);
if (!auth.ok) {
return auth.response;
}
const state = await readState();
return jsonNoStore({
ok: true,
requests: [...state.skillLifecycleRequests].sort((left, right) =>
right.requestedAt.localeCompare(left.requestedAt),
),
});
}
export async function POST(request: NextRequest) {
const csrf = requireCsrfSafeMutation(request);
if (csrf) return csrf;
const auth = await requireHighestAdmin(request);
if (!auth.ok) {
return auth.response;
}
const body = (await request.json().catch(() => ({}))) as Record<string, unknown>;
const action = stringValue(body.action) as SkillLifecycleAction;
const deviceId = stringValue(body.deviceId);
const skillId = stringValue(body.skillId);
const sourceUrl = stringValue(body.sourceUrl);
const trustedSource = stringValue(body.trustedSource);
const trustedSourceId = stringValue(body.trustedSourceId);
if (!validActions.has(action)) {
return jsonNoStore({ ok: false, message: "SKILL_ACTION_INVALID" }, { status: 400 });
}
if (!deviceId) {
return jsonNoStore({ ok: false, message: "DEVICE_ID_REQUIRED" }, { status: 400 });
}
if (!skillId && !sourceUrl && !trustedSource && !trustedSourceId) {
return jsonNoStore({ ok: false, message: "SKILL_ID_OR_SOURCE_URL_REQUIRED" }, { status: 400 });
}
const state = await readState();
if (!state.devices.some((device) => device.id === deviceId)) {
return jsonNoStore({ ok: false, message: "DEVICE_NOT_FOUND" }, { status: 404 });
}
if (
skillId &&
!state.deviceSkills.some((skill) => skill.deviceId === deviceId && skill.skillId === skillId)
) {
return jsonNoStore({ ok: false, message: "SKILL_NOT_FOUND" }, { status: 404 });
}
const requestRecord = await createSkillLifecycleRequest({
action,
deviceId,
skillId: skillId || undefined,
sourceUrl: sourceUrl || undefined,
trustedSource: trustedSource || undefined,
trustedSourceId: trustedSourceId || undefined,
checksum: stringValue(body.checksum) || undefined,
expectedChecksum: stringValue(body.expectedChecksum) || undefined,
targetVersion: stringValue(body.targetVersion) || undefined,
rollbackToVersion: stringValue(body.rollbackToVersion) || undefined,
lockedVersion: stringValue(body.lockedVersion) || undefined,
requestedBy: auth.session.account,
note: stringValue(body.note) || undefined,
auditMeta: buildRequestAuditMeta(request),
});
return jsonNoStore({ ok: true, request: requestRecord });
}