Add CEO company branding endpoint

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta
2026-03-18 21:03:41 -05:00
parent 87b17de0bd
commit 7b4a4f45ed
8 changed files with 264 additions and 2 deletions

View File

@@ -1,16 +1,18 @@
import { Router } from "express";
import { Router, type Request } from "express";
import type { Db } from "@paperclipai/db";
import {
companyPortabilityExportSchema,
companyPortabilityImportSchema,
companyPortabilityPreviewSchema,
createCompanySchema,
updateCompanyBrandingSchema,
updateCompanySchema,
} from "@paperclipai/shared";
import { forbidden } from "../errors.js";
import { validate } from "../middleware/validate.js";
import {
accessService,
agentService,
budgetService,
companyPortabilityService,
companyService,
@@ -21,10 +23,25 @@ import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
export function companyRoutes(db: Db) {
const router = Router();
const svc = companyService(db);
const agents = agentService(db);
const portability = companyPortabilityService(db);
const access = accessService(db);
const budgets = budgetService(db);
async function assertCanUpdateBranding(req: Request, companyId: string) {
assertCompanyAccess(req, companyId);
if (req.actor.type === "board") return;
if (!req.actor.agentId) throw forbidden("Agent authentication required");
const actorAgent = await agents.getById(req.actor.agentId);
if (!actorAgent || actorAgent.companyId !== companyId) {
throw forbidden("Agent key cannot access another company");
}
if (actorAgent.role !== "ceo") {
throw forbidden("Only CEO agents can update company branding");
}
}
router.get("/", async (req, res) => {
assertBoard(req);
const result = await svc.list();
@@ -165,6 +182,29 @@ export function companyRoutes(db: Db) {
res.json(company);
});
router.patch("/:companyId/branding", validate(updateCompanyBrandingSchema), async (req, res) => {
const companyId = req.params.companyId as string;
await assertCanUpdateBranding(req, companyId);
const company = await svc.update(companyId, req.body);
if (!company) {
res.status(404).json({ error: "Company not found" });
return;
}
const actor = getActorInfo(req);
await logActivity(db, {
companyId,
actorType: actor.actorType,
actorId: actor.actorId,
agentId: actor.agentId,
runId: actor.runId,
action: "company.branding_updated",
entityType: "company",
entityId: companyId,
details: req.body,
});
res.json(company);
});
router.post("/:companyId/archive", async (req, res) => {
assertBoard(req);
const companyId = req.params.companyId as string;