"""接口级权限配置 定义系统中所有API端点的权限配置,支持细粒度的接口级权限控制。 """ from __future__ import annotations # 接口级权限配置 # 格式: "METHOD:/path": {配置信息} API_ENDPOINT_PERMISSIONS = { # 参与者管理 (subjects) "POST:/subjects": { "module": "subjects", "action": "write", "description": "创建参与者", "default_roles": ["PM", "CRA"], }, "GET:/subjects": { "module": "subjects", "action": "read", "description": "查询参与者列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "GET:/subjects/{id}": { "module": "subjects", "action": "read", "description": "查询参与者详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "PATCH:/subjects/{id}": { "module": "subjects", "action": "write", "description": "更新参与者", "default_roles": ["PM", "CRA"], }, "DELETE:/subjects/{id}": { "module": "subjects", "action": "write", "description": "删除参与者", "default_roles": ["PM"], }, # 访视管理 (visits) "POST:/subjects/{subject_id}/visits": { "module": "subjects", "action": "write", "description": "创建访视", "default_roles": ["PM", "CRA"], }, "GET:/subjects/{subject_id}/visits": { "module": "subjects", "action": "read", "description": "查询访视列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "GET:/subjects/{subject_id}/visits/{visit_id}": { "module": "subjects", "action": "read", "description": "查询访视详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "PATCH:/subjects/{subject_id}/visits/{visit_id}": { "module": "subjects", "action": "write", "description": "更新访视", "default_roles": ["PM", "CRA"], }, # 不良事件 (SAE) "POST:/risk-issues": { "module": "risk_issues", "action": "write", "description": "创建不良事件", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/risk-issues": { "module": "risk_issues", "action": "read", "description": "查询不良事件列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "GET:/risk-issues/{id}": { "module": "risk_issues", "action": "read", "description": "查询不良事件详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "PATCH:/risk-issues/{id}": { "module": "risk_issues", "action": "write", "description": "更新不良事件", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "DELETE:/risk-issues/{id}": { "module": "risk_issues", "action": "write", "description": "删除不良事件", "default_roles": ["PM"], }, # 财务合同管理 (finance_contracts) "POST:/finance/contracts": { "module": "fees", "action": "write", "description": "创建财务合同", "default_roles": ["PM"], }, "GET:/finance/contracts": { "module": "fees", "action": "read", "description": "查询财务合同列表", "default_roles": ["PM", "CRA", "IMP"], }, "GET:/finance/contracts/{id}": { "module": "fees", "action": "read", "description": "查询财务合同详情", "default_roles": ["PM", "CRA", "IMP"], }, "PATCH:/finance/contracts/{id}": { "module": "fees", "action": "write", "description": "更新财务合同", "default_roles": ["PM"], }, "DELETE:/finance/contracts/{id}": { "module": "fees", "action": "write", "description": "删除财务合同", "default_roles": ["PM"], }, # 费用管理 (fees) "POST:/fees/contracts": { "module": "fees", "action": "write", "description": "创建费用合同", "default_roles": ["PM"], }, "GET:/fees/contracts": { "module": "fees", "action": "read", "description": "查询费用合同列表", "default_roles": ["PM", "CRA", "IMP"], }, "GET:/fees/contracts/{id}": { "module": "fees", "action": "read", "description": "查询费用合同详情", "default_roles": ["PM", "CRA", "IMP"], }, "PATCH:/fees/contracts/{id}": { "module": "fees", "action": "write", "description": "更新费用合同", "default_roles": ["PM"], }, "DELETE:/fees/contracts/{id}": { "module": "fees", "action": "write", "description": "删除费用合同", "default_roles": ["PM"], }, "POST:/fees/contracts/{id}/payments": { "module": "fees", "action": "write", "description": "创建费用分期", "default_roles": ["PM"], }, "PATCH:/fees/payments/{id}": { "module": "fees", "action": "write", "description": "更新费用分期", "default_roles": ["PM"], }, "DELETE:/fees/payments/{id}": { "module": "fees", "action": "write", "description": "删除费用分期", "default_roles": ["PM"], }, # 项目成员管理 "POST:/studies/{study_id}/members": { "module": "project_members", "action": "write", "description": "添加项目成员", "default_roles": ["PM"], }, "GET:/studies/{study_id}/members": { "module": "project_members", "action": "read", "description": "查询项目成员列表", "default_roles": ["PM"], }, "GET:/studies/{study_id}/members/candidates": { "module": "project_members", "action": "read", "description": "查询项目成员候选人", "default_roles": ["PM"], }, "PATCH:/studies/{study_id}/members/{member_id}": { "module": "project_members", "action": "write", "description": "更新项目成员", "default_roles": ["PM"], }, "DELETE:/studies/{study_id}/members/{member_id}": { "module": "project_members", "action": "write", "description": "删除项目成员", "default_roles": ["PM"], }, # 中心管理 "POST:/studies/{study_id}/sites": { "module": "sites", "action": "write", "description": "创建中心", "default_roles": ["PM"], }, "GET:/studies/{study_id}/sites": { "module": "sites", "action": "read", "description": "查询中心列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "GET:/studies/{study_id}/sites/{site_id}": { "module": "sites", "action": "read", "description": "查询中心详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "PATCH:/studies/{study_id}/sites/{site_id}": { "module": "sites", "action": "write", "description": "更新中心", "default_roles": ["PM"], }, "DELETE:/studies/{study_id}/sites/{site_id}": { "module": "sites", "action": "write", "description": "删除中心", "default_roles": ["PM"], }, # 启动管理 (startup) - 19个端点 "POST:/studies/{study_id}/startup/ethics": { "module": "startup_ethics", "action": "write", "description": "创建伦理审批", "default_roles": ["PM"], }, "GET:/studies/{study_id}/startup/ethics": { "module": "startup_ethics", "action": "read", "description": "查询伦理审批列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/startup/ethics/{id}": { "module": "startup_ethics", "action": "read", "description": "查询伦理审批详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "PATCH:/studies/{study_id}/startup/ethics/{id}": { "module": "startup_ethics", "action": "write", "description": "更新伦理审批", "default_roles": ["PM"], }, "DELETE:/studies/{study_id}/startup/ethics/{id}": { "module": "startup_ethics", "action": "write", "description": "删除伦理审批", "default_roles": ["PM"], }, "POST:/studies/{study_id}/startup/feasibility": { "module": "startup_ethics", "action": "write", "description": "创建可行性评估", "default_roles": ["PM"], }, "GET:/studies/{study_id}/startup/feasibility": { "module": "startup_ethics", "action": "read", "description": "查询可行性评估列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/startup/feasibility/{id}": { "module": "startup_ethics", "action": "read", "description": "查询可行性评估详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "PATCH:/studies/{study_id}/startup/feasibility/{id}": { "module": "startup_ethics", "action": "write", "description": "更新可行性评估", "default_roles": ["PM"], }, "DELETE:/studies/{study_id}/startup/feasibility/{id}": { "module": "startup_ethics", "action": "write", "description": "删除可行性评估", "default_roles": ["PM"], }, "POST:/studies/{study_id}/startup/budget": { "module": "startup_auth", "action": "write", "description": "创建预算评估", "default_roles": ["PM"], }, "GET:/studies/{study_id}/startup/budget": { "module": "startup_auth", "action": "read", "description": "查询预算评估列表", "default_roles": ["PM", "CRA", "IMP"], }, "GET:/studies/{study_id}/startup/budget/{id}": { "module": "startup_auth", "action": "read", "description": "查询预算评估详情", "default_roles": ["PM", "CRA", "IMP"], }, "PATCH:/studies/{study_id}/startup/budget/{id}": { "module": "startup_auth", "action": "write", "description": "更新预算评估", "default_roles": ["PM"], }, "DELETE:/studies/{study_id}/startup/budget/{id}": { "module": "startup_auth", "action": "write", "description": "删除预算评估", "default_roles": ["PM"], }, "POST:/studies/{study_id}/startup/timeline": { "module": "startup_auth", "action": "write", "description": "创建时间表", "default_roles": ["PM"], }, "GET:/studies/{study_id}/startup/timeline": { "module": "startup_auth", "action": "read", "description": "查询时间表列表", "default_roles": ["PM", "CRA", "PV"], }, "GET:/studies/{study_id}/startup/timeline/{id}": { "module": "startup_auth", "action": "read", "description": "查询时间表详情", "default_roles": ["PM", "CRA", "PV"], }, "PATCH:/studies/{study_id}/startup/timeline/{id}": { "module": "startup_auth", "action": "write", "description": "更新时间表", "default_roles": ["PM"], }, "DELETE:/studies/{study_id}/startup/timeline/{id}": { "module": "startup_auth", "action": "write", "description": "删除时间表", "default_roles": ["PM"], }, # 项目权限管理 (project_permissions) - 2个端点 "GET:/studies/{study_id}/permissions": { "module": "project_members", "action": "read", "description": "查询项目权限矩阵", "default_roles": ["PM"], }, "PUT:/studies/{study_id}/permissions": { "module": "project_members", "action": "write", "description": "更新项目权限矩阵", "default_roles": ["PM"], }, # 项目概览 (overview) - 1个端点 "GET:/studies/{study_id}/overview": { "module": "project_overview", "action": "read", "description": "查询项目概览", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, # 监查问题 (monitoring_visit_issues) - 7个端点 "POST:/studies/{study_id}/monitoring-visits/{visit_id}/issues": { "module": "monitoring_audit", "action": "write", "description": "创建监查问题", "default_roles": ["PM", "CRA"], }, "GET:/studies/{study_id}/monitoring-visits/{visit_id}/issues": { "module": "monitoring_audit", "action": "read", "description": "查询监查问题列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}": { "module": "monitoring_audit", "action": "read", "description": "查询监查问题详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "PATCH:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}": { "module": "monitoring_audit", "action": "write", "description": "更新监查问题", "default_roles": ["PM", "CRA"], }, "DELETE:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}": { "module": "monitoring_audit", "action": "write", "description": "删除监查问题", "default_roles": ["PM"], }, "POST:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}/close": { "module": "monitoring_audit", "action": "write", "description": "关闭监查问题", "default_roles": ["PM", "CRA"], }, "GET:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}/history": { "module": "monitoring_audit", "action": "read", "description": "查询监查问题历史", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, # 药物发货 (drug_shipments) - 5个端点 "POST:/studies/{study_id}/drug-shipments": { "module": "materials", "action": "write", "description": "创建药物发货", "default_roles": ["PM", "IMP"], }, "GET:/studies/{study_id}/drug-shipments": { "module": "materials", "action": "read", "description": "查询药物发货列表", "default_roles": ["PM", "CRA", "IMP", "QA"], }, "GET:/studies/{study_id}/drug-shipments/{id}": { "module": "materials", "action": "read", "description": "查询药物发货详情", "default_roles": ["PM", "CRA", "IMP", "QA"], }, "PATCH:/studies/{study_id}/drug-shipments/{id}": { "module": "materials", "action": "write", "description": "更新药物发货", "default_roles": ["PM", "IMP"], }, "DELETE:/studies/{study_id}/drug-shipments/{id}": { "module": "materials", "action": "write", "description": "删除药物发货", "default_roles": ["PM"], }, # 物资管理 (material_equipments) - 5个端点 "POST:/studies/{study_id}/materials": { "module": "materials", "action": "write", "description": "创建物资", "default_roles": ["PM", "IMP"], }, "GET:/studies/{study_id}/materials": { "module": "materials", "action": "read", "description": "查询物资列表", "default_roles": ["PM", "CRA", "IMP", "QA"], }, "GET:/studies/{study_id}/materials/{id}": { "module": "materials", "action": "read", "description": "查询物资详情", "default_roles": ["PM", "CRA", "IMP", "QA"], }, "PATCH:/studies/{study_id}/materials/{id}": { "module": "materials", "action": "write", "description": "更新物资", "default_roles": ["PM", "IMP"], }, "DELETE:/studies/{study_id}/materials/{id}": { "module": "materials", "action": "write", "description": "删除物资", "default_roles": ["PM"], }, # 参与者PDS (subject_pds) - 4个端点 "POST:/studies/{study_id}/subjects/{subject_id}/pds": { "module": "subjects", "action": "write", "description": "创建参与者PDS", "default_roles": ["PM", "CRA"], }, "GET:/studies/{study_id}/subjects/{subject_id}/pds": { "module": "subjects", "action": "read", "description": "查询参与者PDS列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/subjects/{subject_id}/pds/{id}": { "module": "subjects", "action": "read", "description": "查询参与者PDS详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "PATCH:/studies/{study_id}/subjects/{subject_id}/pds/{id}": { "module": "subjects", "action": "write", "description": "更新参与者PDS", "default_roles": ["PM", "CRA"], }, # 审计日志 (audit_logs) - 3个端点 "GET:/studies/{study_id}/audit-logs": { "module": "audit_export", "action": "read", "description": "查询审计日志列表", "default_roles": ["PM", "QA"], }, "GET:/studies/{study_id}/audit-logs/{id}": { "module": "audit_export", "action": "read", "description": "查询审计日志详情", "default_roles": ["PM", "QA"], }, "POST:/studies/{study_id}/audit-logs/export": { "module": "audit_export", "action": "read", "description": "导出审计日志", "default_roles": ["PM", "QA"], }, # 访视管理 (visits) - 5个端点 "POST:/studies/{study_id}/visits": { "module": "subjects", "action": "write", "description": "创建访视", "default_roles": ["PM", "CRA", "PV"], }, "GET:/studies/{study_id}/visits": { "module": "subjects", "action": "read", "description": "查询访视列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/visits/{id}": { "module": "subjects", "action": "read", "description": "查询访视详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "PATCH:/studies/{study_id}/visits/{id}": { "module": "subjects", "action": "write", "description": "更新访视", "default_roles": ["PM", "CRA", "PV"], }, "DELETE:/studies/{study_id}/visits/{id}": { "module": "subjects", "action": "write", "description": "删除访视", "default_roles": ["PM"], }, # 知识库笔记 (knowledge_notes) - 5个端点 "POST:/studies/{study_id}/knowledge-notes": { "module": "shared_library", "action": "write", "description": "创建知识库笔记", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/knowledge-notes": { "module": "shared_library", "action": "read", "description": "查询知识库笔记列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "GET:/studies/{study_id}/knowledge-notes/{id}": { "module": "shared_library", "action": "read", "description": "查询知识库笔记详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "PATCH:/studies/{study_id}/knowledge-notes/{id}": { "module": "shared_library", "action": "write", "description": "更新知识库笔记", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "DELETE:/studies/{study_id}/knowledge-notes/{id}": { "module": "shared_library", "action": "write", "description": "删除知识库笔记", "default_roles": ["PM"], }, # 参与者历史 (subject_histories) - 5个端点 "GET:/studies/{study_id}/subjects/{subject_id}/history": { "module": "subjects", "action": "read", "description": "查询参与者历史列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/subjects/{subject_id}/history/{id}": { "module": "subjects", "action": "read", "description": "查询参与者历史详情", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/subjects/{subject_id}/history/timeline": { "module": "subjects", "action": "read", "description": "查询参与者历史时间线", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, "GET:/studies/{study_id}/subjects/{subject_id}/history/export": { "module": "subjects", "action": "read", "description": "导出参与者历史", "default_roles": ["PM", "CRA"], }, "POST:/studies/{study_id}/subjects/{subject_id}/history/search": { "module": "subjects", "action": "read", "description": "搜索参与者历史", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW"], }, # 项目里程碑 (project_milestones) - 2个端点 "GET:/studies/{study_id}/milestones": { "module": "project_milestones", "action": "read", "description": "查询项目里程碑列表", "default_roles": ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"], }, "PATCH:/studies/{study_id}/milestones/{id}": { "module": "project_milestones", "action": "write", "description": "更新项目里程碑", "default_roles": ["PM"], }, } # 向后兼容:模块级权限到接口级权限的映射 # 用于在接口级权限未配置时,回退到模块级权限 MODULE_TO_ENDPOINTS: dict[str, dict[str, list[str]]] = { "subjects": { "read": [ "GET:/subjects", "GET:/subjects/{id}", "GET:/subjects/{subject_id}/visits", "GET:/subjects/{subject_id}/visits/{visit_id}", ], "write": [ "POST:/subjects", "PATCH:/subjects/{id}", "DELETE:/subjects/{id}", "POST:/subjects/{subject_id}/visits", "PATCH:/subjects/{subject_id}/visits/{visit_id}", ], }, "risk_issues": { "read": [ "GET:/risk-issues", "GET:/risk-issues/{id}", ], "write": [ "POST:/risk-issues", "PATCH:/risk-issues/{id}", "DELETE:/risk-issues/{id}", ], }, "fees": { "read": [ "GET:/fees/contracts", "GET:/fees/contracts/{id}", "GET:/finance/contracts", "GET:/finance/contracts/{id}", ], "write": [ "POST:/fees/contracts", "PATCH:/fees/contracts/{id}", "DELETE:/fees/contracts/{id}", "POST:/fees/contracts/{id}/payments", "PATCH:/fees/payments/{id}", "DELETE:/fees/payments/{id}", "POST:/finance/contracts", "PATCH:/finance/contracts/{id}", "DELETE:/finance/contracts/{id}", ], }, "project_members": { "read": [ "GET:/studies/{study_id}/members", "GET:/studies/{study_id}/members/candidates", ], "write": [ "POST:/studies/{study_id}/members", "PATCH:/studies/{study_id}/members/{member_id}", "DELETE:/studies/{study_id}/members/{member_id}", ], }, "sites": { "read": [ "GET:/studies/{study_id}/sites", "GET:/studies/{study_id}/sites/{site_id}", ], "write": [ "POST:/studies/{study_id}/sites", "PATCH:/studies/{study_id}/sites/{site_id}", "DELETE:/studies/{study_id}/sites/{site_id}", ], }, "startup_ethics": { "read": [ "GET:/studies/{study_id}/startup/ethics", "GET:/studies/{study_id}/startup/ethics/{id}", "GET:/studies/{study_id}/startup/feasibility", "GET:/studies/{study_id}/startup/feasibility/{id}", ], "write": [ "POST:/studies/{study_id}/startup/ethics", "PATCH:/studies/{study_id}/startup/ethics/{id}", "DELETE:/studies/{study_id}/startup/ethics/{id}", "POST:/studies/{study_id}/startup/feasibility", "PATCH:/studies/{study_id}/startup/feasibility/{id}", "DELETE:/studies/{study_id}/startup/feasibility/{id}", ], }, "startup_auth": { "read": [ "GET:/studies/{study_id}/startup/budget", "GET:/studies/{study_id}/startup/budget/{id}", "GET:/studies/{study_id}/startup/timeline", "GET:/studies/{study_id}/startup/timeline/{id}", ], "write": [ "POST:/studies/{study_id}/startup/budget", "PATCH:/studies/{study_id}/startup/budget/{id}", "DELETE:/studies/{study_id}/startup/budget/{id}", "POST:/studies/{study_id}/startup/timeline", "PATCH:/studies/{study_id}/startup/timeline/{id}", "DELETE:/studies/{study_id}/startup/timeline/{id}", ], }, "project_members": { "read": [ "GET:/studies/{study_id}/permissions", ], "write": [ "PUT:/studies/{study_id}/permissions", ], }, "project_overview": { "read": [ "GET:/studies/{study_id}/overview", ], "write": [], }, "monitoring_audit": { "read": [ "GET:/studies/{study_id}/monitoring-visits/{visit_id}/issues", "GET:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}", "GET:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}/history", ], "write": [ "POST:/studies/{study_id}/monitoring-visits/{visit_id}/issues", "PATCH:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}", "DELETE:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}", "POST:/studies/{study_id}/monitoring-visits/{visit_id}/issues/{issue_id}/close", ], }, "materials": { "read": [ "GET:/studies/{study_id}/drug-shipments", "GET:/studies/{study_id}/drug-shipments/{id}", "GET:/studies/{study_id}/materials", "GET:/studies/{study_id}/materials/{id}", ], "write": [ "POST:/studies/{study_id}/drug-shipments", "PATCH:/studies/{study_id}/drug-shipments/{id}", "DELETE:/studies/{study_id}/drug-shipments/{id}", "POST:/studies/{study_id}/materials", "PATCH:/studies/{study_id}/materials/{id}", "DELETE:/studies/{study_id}/materials/{id}", ], }, "audit_export": { "read": [ "GET:/studies/{study_id}/audit-logs", "GET:/studies/{study_id}/audit-logs/{id}", "POST:/studies/{study_id}/audit-logs/export", ], "write": [], }, "shared_library": { "read": [ "GET:/studies/{study_id}/knowledge-notes", "GET:/studies/{study_id}/knowledge-notes/{id}", ], "write": [ "POST:/studies/{study_id}/knowledge-notes", "PATCH:/studies/{study_id}/knowledge-notes/{id}", "DELETE:/studies/{study_id}/knowledge-notes/{id}", ], }, "project_milestones": { "read": [ "GET:/studies/{study_id}/milestones", ], "write": [ "PATCH:/studies/{study_id}/milestones/{id}", ], }, }