openapi: 3.0.3 info: title: Baiyue IAM API / 百悦身份与权限 API description: Tenant, member, role, menu, page, button and API permission management. / 租户、成员、角色、菜单、页面、按钮和 API 权限管理。 version: 1.0.1 servers: - url: / security: - bearerAuth: [] tags: - name: Platform Tenant / 平台租户 description: Enterprise registration and review / 企业注册与审核 - name: Merchant Tenant / 商户企业 description: Current tenant profile and members / 当前企业资料与成员 - name: IAM Resources / IAM 资源 description: Internal users, addresses and qualifications / 内部用户、地址与资质 - name: RBAC description: Platform and merchant role-permission management / 平台端与商户端角色权限管理 paths: /api/platform/v1/iam/tenants: get: tags: [Platform Tenant / 平台租户] summary: 查询企业客户列表 description: 分页查询商户企业客户,需要 `platform:customer:list` 权限。 parameters: - {name: page, in: query, required: false, schema: {type: integer, minimum: 1, default: 1}} - {name: size, in: query, required: false, schema: {type: integer, minimum: 1, maximum: 200, default: 20}} - {name: keyword, in: query, required: false, schema: {type: string}, description: 企业编码、名称、信用代码或联系人关键字} - {name: status, in: query, required: false, schema: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED]}} responses: '200': description: 企业客户分页查询成功 content: application/json: schema: {$ref: '#/components/schemas/TenantPageApiResponse'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '422': {$ref: '#/components/responses/UnprocessableEntity'} post: tags: [Platform Tenant / 平台租户] summary: Register enterprise tenant / 创建企业租户 description: Create a pending enterprise tenant and review task. Platform identity is required. / 创建待审核企业租户及审核任务,要求平台端身份。 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/RegisterRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /api/platform/v1/iam/authorization/permissions: get: tags: [IAM Resources / IAM 资源] summary: 查询当前用户有效权限 description: 返回当前有效平台成员权限编码;只要求有效 PLATFORM JWT,不依赖 `platform:role:list`。 responses: '200': description: 当前平台成员权限查询成功 content: application/json: schema: {$ref: '#/components/schemas/PermissionCodesApiResponse'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} /api/platform/v1/iam/tenants/{tenantId}: parameters: - {$ref: '#/components/parameters/TenantId'} get: tags: [Platform Tenant / 平台租户] summary: 查询企业客户档案 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} put: tags: [Platform Tenant / 平台租户] summary: 编辑企业客户档案 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/UpdateTenantRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /api/platform/v1/iam/tenants/{tenantId}/status: parameters: - {$ref: '#/components/parameters/TenantId'} put: tags: [Platform Tenant / 平台租户] summary: 启停企业客户 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ChangeTenantStatusRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} /api/merchant/v1/iam/authorization/permissions: get: tags: [IAM Resources / IAM 资源] summary: 查询当前用户有效权限 description: 返回当前有效商户成员权限编码。 responses: '200': description: 当前商户成员权限查询成功 content: application/json: schema: {$ref: '#/components/schemas/PermissionCodesApiResponse'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} /api/platform/v1/iam/reviews: get: tags: [Platform Tenant / 平台租户] summary: List pending tenant reviews / 查询待审核企业 description: Return enterprise registrations waiting for a platform decision. / 返回等待平台处理的企业注册审核记录。 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} /api/platform/v1/iam/reviews/{id}/approve: post: tags: [Platform Tenant / 平台租户] summary: Approve enterprise registration / 审核通过企业注册 description: Approve a pending review and activate the tenant. / 通过待审核申请并激活企业租户。 parameters: - {$ref: '#/components/parameters/Id'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ReviewRequest'} responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} /api/platform/v1/iam/reviews/{id}/reject: post: tags: [Platform Tenant / 平台租户] summary: Reject enterprise registration / 驳回企业注册 description: Reject a pending registration and save the review comment. / 驳回待审核注册申请并保存审核意见。 parameters: - {$ref: '#/components/parameters/Id'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ReviewRequest'} responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} /api/platform/v1/iam/internal-users: get: tags: [IAM Resources / IAM 资源] summary: 查询平台内部用户 responses: '200': description: 平台内部用户查询成功,公开主键为 membershipId 并回显 roleIds content: application/json: schema: {$ref: '#/components/schemas/InternalUserListApiResponse'} '403': {$ref: '#/components/responses/Forbidden'} post: tags: [IAM Resources / IAM 资源] summary: 新增平台内部用户 description: 创建完整的 Auth/IAM 平台账号,也兼容通过 authUserId 关联已有账号。 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateInternalUserRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /api/platform/v1/iam/internal-users/{membershipId}: parameters: - {$ref: '#/components/parameters/MembershipId'} put: tags: [IAM Resources / IAM 资源] summary: 编辑平台内部用户 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/UpdateInternalUserRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} /api/platform/v1/iam/internal-users/{membershipId}/status: parameters: - {$ref: '#/components/parameters/MembershipId'} put: tags: [IAM Resources / IAM 资源] summary: 启用或停用平台内部用户 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ChangeInternalUserStatusRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /api/platform/v1/iam/internal-users/{membershipId}/password: parameters: - {$ref: '#/components/parameters/MembershipId'} put: tags: [IAM Resources / IAM 资源] summary: 重置平台内部用户密码 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ResetInternalUserPasswordRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /api/platform/v1/iam/internal-users/{membershipId}/roles: parameters: - {$ref: '#/components/parameters/MembershipId'} put: tags: [IAM 资源] summary: 全量分配平台内部用户角色 description: 仅允许分配平台租户下已启用的平台端角色;空集合表示清空角色。 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/AssignInternalUserRolesRequest'} responses: '200': description: 角色分配成功并返回最新内部用户模型 content: application/json: schema: {$ref: '#/components/schemas/InternalUserApiResponse'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /api/merchant/v1/iam/tenant/profile: get: tags: [Merchant Tenant / 商户企业] summary: Get current tenant profile / 查询当前企业资料 description: Tenant ID comes only from the verified JWT. / 租户 ID 仅取自已验证 JWT。 responses: '200': {$ref: '#/components/responses/Success'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} put: tags: [Merchant Tenant / 商户企业] summary: Update current tenant profile / 更新当前企业资料 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/UpdateProfileRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /api/merchant/v1/iam/members: get: tags: [Merchant Tenant / 商户企业] summary: List enterprise members / 查询企业成员 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} post: tags: [Merchant Tenant / 商户企业] summary: Add enterprise member / 新增企业成员 description: Attach an existing IAM user to the current tenant. / 将已有 IAM 用户加入当前企业。 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateMemberRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /api/merchant/v1/iam/tenant/addresses: get: tags: [IAM Resources / IAM 资源] summary: List tenant addresses / 查询企业地址 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} post: tags: [IAM Resources / IAM 资源] summary: Add tenant address / 新增企业地址 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/AddressRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} /api/merchant/v1/iam/tenant/qualifications: get: tags: [IAM Resources / IAM 资源] summary: List tenant qualifications / 查询企业资质 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} /api/{app}/v1/iam/roles: parameters: - {$ref: '#/components/parameters/App'} get: tags: [RBAC] summary: List roles / 查询角色 description: List roles in the selected application and tenant scope. / 查询指定应用及租户范围内的角色。 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} post: tags: [RBAC] summary: Create role / 新增角色 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateRoleRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /api/{app}/v1/iam/members/roles: put: tags: [RBAC] summary: Assign roles to member / 设置成员角色 description: Replace member role assignments in the same tenant and application. / 在同一租户和应用域内替换成员角色。 parameters: - {$ref: '#/components/parameters/App'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/AssignRolesRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} /api/{app}/v1/iam/permissions: parameters: - {$ref: '#/components/parameters/App'} get: tags: [RBAC] summary: List menu, page, button and API permissions / 查询菜单、页面、按钮和 API 权限 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} post: tags: [RBAC] summary: Create permission / 新增权限 description: Create a MENU, PAGE, BUTTON or API permission node. / 创建 MENU、PAGE、BUTTON 或 API 权限节点。 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreatePermissionRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /api/{app}/v1/iam/roles/permissions: put: tags: [RBAC] summary: Grant permissions to role / 设置角色权限 description: Replace role permissions; cross-tenant and cross-application grants are rejected. / 替换角色权限,拒绝跨租户和跨应用授权。 parameters: - {$ref: '#/components/parameters/App'} requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/GrantPermissionsRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} /api/{app}/v1/iam/permissions/{permissionId}: parameters: - {$ref: '#/components/parameters/App'} - {$ref: '#/components/parameters/PermissionId'} put: tags: [RBAC] summary: 编辑自定义权限资源 description: 权限编码和类型不可变更,系统预置资源不可修改。 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/UpdatePermissionRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} delete: tags: [RBAC] summary: 删除未绑定的自定义权限资源 description: 系统预置资源、存在子资源或已绑定角色的资源不可删除。 responses: '200': {$ref: '#/components/responses/Success'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} /api/{app}/v1/iam/permissions/{permissionId}/status: parameters: - {$ref: '#/components/parameters/App'} - {$ref: '#/components/parameters/PermissionId'} put: tags: [RBAC] summary: 启停自定义权限资源 requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ChangePermissionStatusRequest'} responses: '200': {$ref: '#/components/responses/Success'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT parameters: Id: name: id in: path required: true description: Resource ID / 资源 ID schema: {type: integer, format: int64} example: 190000000000000001 App: name: app in: path required: true description: Application domain / 应用域 schema: {type: string, enum: [platform, merchant]} example: platform MembershipId: name: membershipId in: path required: true description: 平台成员关系 ID schema: {type: integer, format: int64} TenantId: name: tenantId in: path required: true description: 企业客户租户 ID schema: {type: integer, format: int64, minimum: 1} PermissionId: name: permissionId in: path required: true description: 权限资源 ID schema: {type: integer, format: int64} responses: Success: {description: Operation succeeded / 操作成功, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} BadRequest: {description: Invalid request / 请求参数错误, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} Unauthorized: {description: Authentication required / 需要登录, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} Forbidden: {description: Permission or tenant scope rejected / 权限或租户范围不匹配, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} NotFound: {description: Resource not found / 资源不存在, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} Conflict: {description: Resource conflict / 资源冲突, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} UnprocessableEntity: {description: 参数校验失败, content: {application/json: {schema: {$ref: '#/components/schemas/ApiResponse'}}}} schemas: ApiResponse: type: object required: [code, message, timestamp] properties: code: {type: string, example: '00000'} message: {type: string, example: Success} data: {} requestId: {type: string} traceId: {type: string} timestamp: {type: string, format: date-time} PermissionCodesApiResponse: allOf: - {$ref: '#/components/schemas/ApiResponse'} - type: object properties: data: type: array uniqueItems: true items: {type: string} TenantPageApiResponse: allOf: - {$ref: '#/components/schemas/ApiResponse'} - type: object properties: data: type: object required: [records, page, size, total, pages] properties: records: {type: array, items: {$ref: '#/components/schemas/TenantResponse'}} page: {type: integer, format: int64, minimum: 1} size: {type: integer, format: int64, minimum: 1} total: {type: integer, format: int64, minimum: 0} pages: {type: integer, format: int64, minimum: 0} InternalUserListApiResponse: allOf: - {$ref: '#/components/schemas/ApiResponse'} - type: object properties: data: {type: array, items: {$ref: '#/components/schemas/InternalUserResponse'}} InternalUserApiResponse: allOf: - {$ref: '#/components/schemas/ApiResponse'} - type: object properties: data: {$ref: '#/components/schemas/InternalUserResponse'} TenantResponse: type: object required: [id, tenantCode, tenantName, status] properties: id: {type: integer, format: int64} tenantCode: {type: string} tenantName: {type: string} status: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED]} legalName: {type: string} unifiedSocialCreditCode: {type: string} contactName: {type: string} contactPhone: {type: string} contactEmail: {type: string, format: email} RegisterRequest: type: object required: [tenantName, legalName, unifiedSocialCreditCode, contactName, contactPhone] properties: tenantName: {type: string, example: 深圳虫虫出海科技有限公司} legalName: {type: string, example: 张三} unifiedSocialCreditCode: {type: string, pattern: '^[0-9A-Z]{18}$', example: 91440300MA5ABCDE12} contactName: {type: string, example: 李四} contactPhone: {type: string, example: '13800138000'} contactEmail: {type: string, format: email, example: contact@example.com} UpdateProfileRequest: type: object required: [tenantName, legalName, contactName, contactPhone] properties: tenantName: {type: string} legalName: {type: string} contactName: {type: string} contactPhone: {type: string} contactEmail: {type: string, format: email} UpdateTenantRequest: type: object required: [tenantName, legalName, contactName, contactPhone] properties: tenantName: {type: string} legalName: {type: string} contactName: {type: string} contactPhone: {type: string} contactEmail: {type: string, format: email} ChangeTenantStatusRequest: type: object required: [status] properties: status: {type: string, enum: [ACTIVE, DISABLED]} ReviewRequest: type: object properties: comment: {type: string, description: Review comment or rejection reason / 审核意见或驳回原因} CreateInternalUserRequest: type: object required: [displayName] properties: authUserId: {type: integer, format: int64, description: 兼容旧接口;填写后关联已有认证账号} userType: {type: string, enum: [INTERNAL, PLATFORM], description: 兼容旧接口,可省略} username: {type: string, minLength: 4, maxLength: 64} password: {type: string, format: password, minLength: 8, maxLength: 64, writeOnly: true} displayName: {type: string, maxLength: 64} phone: {type: string, maxLength: 32} email: {type: string, format: email, maxLength: 128} memberNo: {type: string, maxLength: 64} roleIds: {type: array, items: {type: integer, format: int64}} UpdateInternalUserRequest: type: object required: [displayName, memberNo, roleIds] properties: displayName: {type: string, maxLength: 64} phone: {type: string, maxLength: 32} email: {type: string, format: email, maxLength: 128} memberNo: {type: string, maxLength: 64} roleIds: {type: array, items: {type: integer, format: int64}} ChangeInternalUserStatusRequest: type: object required: [status] properties: status: {type: string, enum: [ACTIVE, DISABLED]} ResetInternalUserPasswordRequest: type: object required: [newPassword] properties: newPassword: {type: string, format: password, minLength: 8, maxLength: 64, writeOnly: true} AssignInternalUserRolesRequest: type: object required: [roleIds] properties: roleIds: {type: array, items: {type: integer, format: int64}} InternalUserResponse: type: object required: [membershipId, userId, authUserId, username, displayName, memberType, status, roleIds] properties: membershipId: {type: integer, format: int64} userId: {type: integer, format: int64} authUserId: {type: integer, format: int64} username: {type: string} displayName: {type: string} phone: {type: string} email: {type: string, format: email} memberType: {type: string, enum: [EMPLOYEE]} memberNo: {type: string} status: {type: string, enum: [ACTIVE, DISABLED]} roleIds: {type: array, items: {type: integer, format: int64}} CreateMemberRequest: type: object required: [username, password, displayName, memberType] properties: username: {type: string, minLength: 4, maxLength: 64} password: {type: string, format: password, minLength: 8, maxLength: 64} displayName: {type: string, maxLength: 64} phone: {type: string, maxLength: 32} email: {type: string, format: email, maxLength: 128} memberType: {type: string, enum: [OWNER, ADMIN, EMPLOYEE]} memberNo: {type: string} roleIds: {type: array, items: {type: integer, format: int64}} AddressRequest: type: object required: [addressType, detail] properties: addressType: {type: string, enum: [OPERATING, BILLING, RETURN]} countryCode: {type: string, example: CN} province: {type: string} city: {type: string} district: {type: string} detail: {type: string} postalCode: {type: string} isDefault: {type: boolean} CreateRoleRequest: type: object required: [roleCode, roleName] properties: roleCode: {type: string, example: ORDER_OPERATOR} roleName: {type: string, example: 订单操作员} description: {type: string} CreatePermissionRequest: type: object required: [type, code, name] properties: type: {type: string, enum: [MENU, PAGE, BUTTON, API], example: BUTTON} code: {type: string, example: 'order:firstleg:submit'} name: {type: string, example: 提交头程订单} parentId: {type: integer, format: int64, example: 0} routePath: {type: string} httpMethod: {type: string, enum: [GET, POST, PUT, PATCH, DELETE]} sortNo: {type: integer, example: 10} UpdatePermissionRequest: type: object required: [name] properties: name: {type: string} parentId: {type: integer, format: int64} routePath: {type: string} httpMethod: {type: string, enum: [GET, POST, PUT, PATCH, DELETE]} sortNo: {type: integer} ChangePermissionStatusRequest: type: object required: [status] properties: status: {type: string, enum: [ACTIVE, DISABLED]} AssignRolesRequest: type: object required: [membershipId, roleIds] properties: membershipId: {type: integer, format: int64} roleIds: {type: array, items: {type: integer, format: int64}} GrantPermissionsRequest: type: object required: [roleId, permissionIds] properties: roleId: {type: integer, format: int64} permissionIds: {type: array, items: {type: integer, format: int64}}