Organizations Federation API

Organizations Service 的 HTTP 与 SDK API Reference

这篇文档描述客户端和 Bureau 可以调用的 Organizations Action。产品后端的身份和权限接入见 Bureau 接入 Organizations。

安装

import { Federation } from "@downcity/federation";
import { OrganizationsService } from "@downcity/services";

const federation = new Federation({ database });

federation.use(new OrganizationsService({
  max_organizations_per_user: 3,
}));
选项必填说明
max_organizations_per_user是一个用户在 Federation 中最多拥有的 active Organization 总数

Service 支持 better-sqlite3、PostgreSQL 和 Cloudflare D1,并统一使用 context.transaction()。

地址与鉴权

{federation_origin}/v1/organizations/{action}

所有 Action 都需要 Federation user_token:

Authorization: Bearer ub_<JWT>

Federation 从已验证 Token 读取 user_id 和 bureau_id。GET Action 使用 Query,POST Action 使用 JSON。

类型

type Organization = {
  organization_id: string;
  name: string;
  scope_type: "federation" | "bureau";
  scope_bureau_id: string;
  state: "active" | "archived";
  created_by: string;
  created_at: string;
  updated_at: string;
  archived_at: string;
};

type Membership = {
  membership_id: string;
  organization_id: string;
  user_id: string;
  role: "owner" | "admin" | "member";
  state: "active" | "removed";
  created_at: string;
  updated_at: string;
  removed_at: string;
  removed_by: string;
};

type JoinRequest = {
  request_id: string;
  organization_id: string;
  user_id: string;
  state: "pending" | "approved" | "rejected" | "canceled";
  requested_at: string;
  decided_at: string;
  decided_by: string;
};

scope_type = federation 时 scope_bureau_id 为空字符串。scope_type = bureau 时,scope_bureau_id 来自创建请求的 user_token.bureau_id。

权限

操作OwnerAdminMember
读取 Organization 和成员✓✓✓
修改名称✓✓
审批 Join Request✓✓
移除 Member✓✓
移除 Admin✓
任命或撤销 Admin✓
转移 Owner✓
归档✓
主动退出转移后✓✓

Action

MethodAction权限说明
GETmyUser列出当前用户可见的 Organization
GETgetMember读取 Organization 与当前 Membership
POSTcreateUser创建 Organization 并成为 Owner
POSTupdateOwner/Admin修改名称
POSTarchiveOwner归档 Organization
GETmembership/getMember读取当前 Membership
GETmembers/listMember列出 active Membership
POSTmembers/roleOwner设置 Admin 或 Member
POSTmembers/removeOwner/Admin移除可管理的成员
POSTmembers/leaveAdmin/Member主动退出
POSTowner/transferOwner转移唯一 Owner
POSTjoin-requests/createUser申请加入
POSTjoin-requests/cancelApplicant取消 pending 申请
GETjoin-requests/listOwner/Admin列出 pending 申请
POSTjoin-requests/decideOwner/Admin批准或拒绝申请

Organization Action

GET my

GET /v1/organizations/my

默认只返回 active Organization。包含归档记录:

GET /v1/organizations/my?include_archived=true

返回 { "items": UserOrganization[] }。Federation Organization 在任意 Token Bureau 可见;Bureau Organization 只在当前 Token Bureau 匹配时可见。

GET get

GET /v1/organizations/get?organization_id=org_01J...

要求 active Membership,返回 { organization, membership }。成员可以读取 archived Organization,但不能继续治理写入。

POST create

创建全局 Organization:

{
  "name": "Genesis Research",
  "scope_type": "federation"
}

创建当前 Bureau Organization:

{
  "name": "Genesis Research",
  "scope_type": "bureau"
}

Service 返回 { organization, membership },Membership 是唯一 Owner。名称去除首尾空白后必须为 1–120 个字符。

POST update

{
  "organization_id": "org_01J...",
  "name": "New Name"
}

Owner/Admin 可修改名称。Organization 作用域创建后不能修改。

POST archive

{ "organization_id": "org_01J..." }

Owner 可执行。归档不可恢复,会停止治理写入并释放 Owner 额度。Membership 和 Join Request 历史保留。

Membership Action

GET membership/get

GET /v1/organizations/membership/get?organization_id=org_01J...

返回 { organization, membership }。Bureau 可以携带用户提交的同一个 user_token 调用此接口。被移除的用户返回 403 NOT_AN_ORGANIZATION_MEMBER。

GET members/list

GET /v1/organizations/members/list?organization_id=org_01J...

返回 { "items": Membership[] },只包含 active Membership。

POST members/role

{
  "organization_id": "org_01J...",
  "membership_id": "mem_01J...",
  "role": "admin"
}

Owner 可将非 Owner 成员设置为 admin 或 member。转移 Owner 使用 owner/transfer。

POST members/remove

{
  "organization_id": "org_01J...",
  "membership_id": "mem_01J..."
}

Owner 可以移除 Admin 或 Member;Admin 只能移除 Member。唯一 Owner 不能被移除。

POST members/leave

{ "organization_id": "org_01J..." }

Admin 和 Member 可以退出。Owner 必须先转移所有权。

POST owner/transfer

{
  "organization_id": "org_01J...",
  "membership_id": "mem_new_owner"
}

目标必须是 active Member,并且还有 Owner 额度。原 Owner 变为 Admin。

Join Request Action

POST join-requests/create

{ "organization_id": "org_01J..." }

用户通过已知 ID 申请加入。重复申请返回同一个 pending 记录。已有 active Membership 时返回 { state: "joined", organization, membership }。

POST join-requests/cancel

{ "request_id": "join_01J..." }

申请人可以取消自己的 pending 申请。

GET join-requests/list

GET /v1/organizations/join-requests/list?organization_id=org_01J...

Owner/Admin 调用,返回 pending Join Request。

POST join-requests/decide

{
  "request_id": "join_01J...",
  "decision": "approved"
}

decision 接受 approved 或 rejected。批准时,Service 在同一事务中创建新的 Member Membership。

错误

HTTPCode含义
400ORGANIZATION_INPUT_INVALID名称、ID、角色或决策无效
400ORGANIZATION_SCOPE_INVALIDscope_type 无效
401AUTH_REQUIRED缺少有效用户身份
403ORGANIZATION_BUREAU_MISMATCHToken Bureau 不能访问该 Bureau Organization
403NOT_AN_ORGANIZATION_MEMBER当前用户没有 active Membership
403ORGANIZATION_ROLE_DENIED治理角色不允许操作
404ORGANIZATION_NOT_FOUNDOrganization 不存在
404ORGANIZATION_MEMBERSHIP_NOT_FOUNDMembership 不存在或已失效
404JOIN_REQUEST_NOT_FOUNDJoin Request 不存在或不可操作
409ORGANIZATION_LIMIT_REACHEDOwner 额度已满
409OWNER_TRANSFER_REQUIRED必须先转移 Owner
410ORGANIZATION_ARCHIVEDOrganization 已归档

客户端应按 error.code 分支,不要依赖错误文本。