Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
103 lines
3.8 KiB
TypeScript
103 lines
3.8 KiB
TypeScript
import type { DatabaseSync } from "node:sqlite";
|
|
import type { CreateOrganizationInput } from "../../shared/commands";
|
|
import { PROVIDER_CATALOG } from "../../shared/provider-catalog";
|
|
import { createId } from "../../shared/ids";
|
|
import { AuditService } from "./audit-service";
|
|
import { PolicyService } from "./policy-service";
|
|
import { IdentityAccessService } from "./identity-access-service";
|
|
import { OrgGovernanceService } from "./org-governance-service";
|
|
import { OperationsService } from "./operations-service";
|
|
import { assertUsableMentionName } from "../../shared/mention-handles";
|
|
|
|
/**
|
|
* Seeds a brand-new organization in one transaction's worth of writes: the org
|
|
* row and its Board Chair employee, the identity / governance / operations /
|
|
* SDLC / policy defaults, the starter chat channels, the disabled provider
|
|
* catalog, and the active-org pointer. Returns the new organization id.
|
|
*/
|
|
export function seedOrganization(db: DatabaseSync, input: CreateOrganizationInput): string {
|
|
const audit = new AuditService(db);
|
|
const policy = new PolicyService(db);
|
|
const identityAccess = new IdentityAccessService(db);
|
|
const governance = new OrgGovernanceService(db);
|
|
const operations = new OperationsService(db);
|
|
|
|
assertUsableMentionName(input.employeeName);
|
|
const orgId = createId("org");
|
|
const employeeId = createId("emp");
|
|
const now = new Date().toISOString();
|
|
|
|
db.prepare(`
|
|
insert into organizations(
|
|
id, name, mission, goal, description, execution_mode, auto_approve_hires, review_deliverables, created_at
|
|
)
|
|
values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`).run(
|
|
orgId,
|
|
input.organizationName.trim(),
|
|
input.mission.trim(),
|
|
input.goal.trim(),
|
|
input.description?.trim() ?? "",
|
|
input.executionMode ?? "ai_ceo",
|
|
input.autoApproveHires === false ? 0 : 1,
|
|
input.reviewDeliverables === true ? 1 : 0,
|
|
now,
|
|
);
|
|
db.prepare("insert into employees(id, org_id, display_name, role, created_at) values (?, ?, ?, ?, ?)")
|
|
.run(employeeId, orgId, input.employeeName.trim(), "Board Chair", now);
|
|
identityAccess.seedEmployeeAccess(orgId, employeeId, now);
|
|
governance.seedOrganizationGovernance(orgId, employeeId, now);
|
|
operations.seedOrganizationOperations(orgId, now);
|
|
|
|
for (const space of [
|
|
["company", "general", "Company coordination", "workspace"],
|
|
["department", "product", "Product decisions", "workspace"],
|
|
["department", "engineering", "Engineering delivery", "workspace"],
|
|
["company", "board", "Board decisions", "restricted"],
|
|
]) {
|
|
const spaceId = createId("spc");
|
|
db.prepare(`
|
|
insert into chat_spaces(id, org_id, space_type, name, topic, visibility, created_at)
|
|
values (?, ?, ?, ?, ?, ?, ?)
|
|
`).run(spaceId, orgId, space[0], space[1], space[2], space[3], now);
|
|
db.prepare(`
|
|
insert into chat_memberships(space_id, principal_type, principal_id, role, mute_state)
|
|
values (?, ?, ?, ?, ?)
|
|
`).run(spaceId, "employee", employeeId, space[1] === "board" ? "approver" : "member", "unmuted");
|
|
}
|
|
|
|
for (const provider of PROVIDER_CATALOG) {
|
|
db.prepare(`
|
|
insert into providers(id, org_id, provider_key, label, auth_type, model, credential_id, enabled, created_at)
|
|
values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`).run(
|
|
createId("prv"),
|
|
orgId,
|
|
provider.key,
|
|
provider.label,
|
|
provider.authType,
|
|
provider.defaultModel,
|
|
null,
|
|
0,
|
|
now,
|
|
);
|
|
}
|
|
|
|
policy.seedOrganizationPolicies(orgId, now);
|
|
db.prepare(`
|
|
insert into app_state(id, active_org_id, updated_at)
|
|
values (1, ?, ?)
|
|
on conflict(id) do update set active_org_id = excluded.active_org_id, updated_at = excluded.updated_at
|
|
`).run(orgId, now);
|
|
audit.record({
|
|
orgId,
|
|
entityType: "organization",
|
|
entityId: orgId,
|
|
actorType: "employee",
|
|
actorId: employeeId,
|
|
action: "created",
|
|
payload: { name: input.organizationName.trim() },
|
|
});
|
|
return orgId;
|
|
}
|