forked from EduCraft/curriculum-project-hub
feat: org capacity policy admin surface
ADR-0022 / Spec.System.Capacity pins layered capacity limits: a platform ceiling per dimension is unbreakable, and each organization may only set a lower `organizationLimit`. The effective limit is the minimum of the two (`LayeredLimit.effective`); dimensions with no org override fall back to the platform ceiling. No dimension may be unlimited (a ceiling must exist before an org limit can be set, `LayeredLimit.Valid`). Add the backend: the pinned 23 CapacityDimension set + labels (src/capacity/dimensions.ts), platform ceilings sourced from existing runtime env vars plus `HUB_CEILING_<DIMENSION>` (src/capacity/ceilings.ts), the OrganizationCapacityPolicy prisma model + migration, the getCapacityPolicy/setCapacityPolicy service enforcing LayeredLimit.Valid, and org-admin GET/PUT /api/org/:orgSlug/capacity-policy routes wired into the org route tree. Add the admin-web surface: CapacityDimension/CapacityPolicyView api client types, capacityPolicy/setCapacityPolicy methods, a `容量` nav entry, and a capacity page that lists every dimension with its platform ceiling (or `未配置` when unset), an org-limit input (disabled until a ceiling exists), and a live effective-value column. Saving sends the partial limits map; the service rejects values above the ceiling or for unconfigured dimensions.
This commit is contained in:
@@ -37,6 +37,7 @@ model Organization {
|
||||
|
||||
memberships OrganizationMembership[]
|
||||
projectSettings OrganizationProjectSettings?
|
||||
capacityPolicy OrganizationCapacityPolicy?
|
||||
folders Folder[]
|
||||
projects Project[]
|
||||
teams Team[]
|
||||
@@ -160,6 +161,20 @@ model OrganizationProjectSettings {
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
/// ADR-0022 layered capacity policy. Org admins may set per-dimension lower
|
||||
/// limits; `limits` is a JSON map of CapacityDimension → number (only the set
|
||||
/// ones). Each set value must be ≤ the platform ceiling for that dimension
|
||||
/// (validated in service; spec `LayeredLimit.Valid`). Dimensions with no entry
|
||||
/// fall back to the platform ceiling (`LayeredLimit.effective`).
|
||||
model OrganizationCapacityPolicy {
|
||||
organizationId String @id
|
||||
limits Json
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
/// A person known to the Hub. `feishuOpenId` remains a legacy compatibility
|
||||
/// key; new customer-app identities live in FeishuUserIdentity and store a
|
||||
/// connection-scoped opaque USER principal here instead of a raw open_id.
|
||||
|
||||
Reference in New Issue
Block a user