Commit Graph

36 Commits

Author SHA1 Message Date
Pine 076f96af74 feat(tasks): 阶段A后端核心 —— 多模式任务字段 + 接单资格判定 + 各模式限额守卫 + 公开广场/详情can_accept
- Task 增扩展列:publisher_role/visibility/c_visible/park_public/assign_type/assign_park_id/assign_opc_id/park_id/park_released/bid_quota/win_quota/eligibility(JSON)/settle_mode(默认operator_escrow)
- TaskRepository._to_dict/create/update 同步新字段;迁移 0020_task_multi_mode
- TaskService.can_accept(task,user):仅被指派/园区专属/指派园区未发单 + eligibility(证书/地域/性别/工时/领域/专长/案例) 判定,返回 ok/reasons
- 抢单(grab)与投标(bid)接入 can_accept 守卫;bid 加报名上限与重复报名校验
- /opc/tasks 公开广场改为 published+c_visible;/opc/tasks/{id} 详情同;登录后附带 can_accept/accept_reasons(经 optional_current_user)
2026-08-27 19:05:18 +08:00
Pine 89bd7e8390 feat(content): 发布体系 大/小图 + 公开 + 园区端发布
- 迁移0018:content_items 加 card_mode/is_public/source/tenant_id
- ContentRepository:_to_dict/create/update 含新字段;list 加 public_only/tenant_id 过滤
- /opc/content 仅 published+公开;/opc/content/{id} 非公开→404
- 园区端 POST /park/api/content:发布人强制=园区名、source=carrier、tenant=本园、is_public 默认false(仅大屏)、card_mode默认small
- 园区端 GET /park/api/content:本园区内容(含未公开)供大屏
- schemas 补 card_mode/is_public

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 15:42:39 +08:00
Pine a60f0ed180 feat(content): 资讯详情 阅读数 + 留言
- 迁移0017:content_items.read_count + content_comments 表
- ContentRepository:_to_dict 加 read_count;incr_read_count/content_comments/add_content_comment
- rbac_opc:GET /opc/content/{id} 自增阅读数;GET/POST /opc/content/{id}/comments(发布需 opc_member,带昵称/头像)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 15:28:27 +08:00
Pine 71b1f03bca feat(content): 资讯富编辑(封面/图集/视频/外链/发布人) + 媒体上传
- 迁移0016:content_items 加 cover/images_json/video/video_cover/link/publisher_name/publisher_avatar
- ContentRepository:_to_dict/create/update 支持富字段;images(list)↔images_json;update 白名单含 publisher_id
- schemas:ContentCreate/UpdateRequest 加富字段
- rbac_operator:POST /content 注入发布人(actor 昵称/头像快照);新增 POST /admin/upload(媒体上传)
- app/services/media_upload.py:统一上传(serverdata/uploads + abs_url),与 /api/upload 同契约

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 14:35:32 +08:00
Pine 7ec9b8fd8a fix(db): 每请求独立 AsyncSession(根除并发 500)
- get_db 由「返回 app.state.db 单例」改为「每请求各建一个 Database 并在结束关闭」
- Database.__init__ 复用按 url 缓存的共享异步引擎(_shared_engine),避免每请求重建引擎
- 修复 GET /auth/me、/admin/* 并发时 sqlalchemy.exc.InvalidRequestError: concurrent operations are not permitted(同一 AsyncSession 被并发请求复用)
- 对齐 park 子应用 _carrier_db 的每请求 Database 模式

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 14:17:55 +08:00
Pine 873a70a095 feat(content): 资讯增删改 + C端资讯中心(类别)端点
- ContentRepository:+update(部分字段)/get/delete
- schemas.operator:+ContentUpdateRequest(全可选)
- rbac_operator:+PUT/DELETE /admin/content/{id}(action:content.manage+审计)
- rbac_opc:+GET /opc/content?type=policy|news|skill|dynamic(仅published)、/opc/content/{id}(详情)
- 类别字典 policy/news/skill/dynamic

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 14:05:38 +08:00
Pine 8697119aaa feat(park-company): 园区企业→成员 + 企业算力(折扣%/配额,只增不减) 后端
- 迁移0015:park_companies 加 compute_discount/compute_quota/compute_quota_used/engine_group/owner_user_id;users 加 park_company_id(成员归属一家企业)
- tenants.py:company_members/get/add/remove(写 users.park_company_id)、available_members(候选)、set_company_compute(折扣%/配额 单调非降,越界 ValueError)、sync_company_engine(引擎组倍率同步,best-effort)
- park/routers.py:carrier 端点 company-members GET/POST/DELETE、company-pool、companies/{cid}/compute(monotonic+引擎同步);鉴权 _carrier_user+_my_park 隔离本园区
- compute_client.py:set_user_group_by_username、set_group_group_ratio(组倍率=1-discount%)、grant_user_quota_by_username(解析引擎id后 add_quota)
- rbac_admin.py:平台兜底 GET /park/tenants/{tid}/companies、PUT .../companies/{cid}/compute(monotonic+audit)
- _user_to_dict 暴露 park_company_id
- 单调校验服务端强判:折扣降/配额负增 → 400

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-26 19:57:37 +08:00
Pine ac2df72b21 refactor(auth): 去多身份/多端口——账号单一角色,删 user_identities/select-identity/多端口路由
- 删 UserIdentity 模型/IdentityRepository/db.identities,账号统一单一角色(users.role)
- auth.py 去 select-identity/_identity_summaries,登录恒返回 identities=[];_login_response_for_user 按单角色签发
- 删多端口路由 rbac_government/investor/developer 及其 main 挂载
- seed 去多身份回填(_migrate_identities/_ensure_port_agents/多端身份/端口标签映射)
- dependencies: require_port 去端口隔离(单角色放宽)、optional_current_user 修 identity_id 多余参数
- user_admin_service create_user 不再建端口身份;schemas 去 SelectIdentityRequest
- 新增迁移 0014_drop_user_identities(drop user_identities 表)
- 测试改写为单角色契约(登录空 identities、无 select-identity、账号级智能体)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-26 19:15:51 +08:00
Pine 745ba678bd feat(auth): 统一鉴权收口,账号单一角色+权限码,去多身份
- dependencies._resolve_identity 收敛为单角色(users.role),不再读身份分支
- auth.login/select_identity 单角色发token、identities 恒空,Pine=operator(运营方)
- repositories.to_profile 按 role 计算 account_type(修复身份标签显示"服务方")
- seed 重构 PERMISSIONS/ROLE_PERMISSIONS:operator 平台全 menu、carrier 园区 menu:park_*,删多端口冗余
- account_types 归一 operator/carrier/opc_member/service

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-26 19:02:54 +08:00
Pine 30f0baf074 feat(opc): OPC认证/园区转园 数据层 — OpcCertification/ParkTransfer 模型 + 三个 repo + schemas
- models.py: ParkTenant 加 operator_user_id(园区归属载体账号);新增 OpcCertification/ParkTransfer 两 ORM 类
- repositories.py: OpcCertificationRepository/ParkTransferRepository/ParkAdmissionRepository + Database 挂载
- schemas/opc.py: OpcCertApplyRequest/ParkTransferApplyRequest
- schemas/admin.py: OpcCertReviewRequest/ParkAdmissionReviewRequest/ParkTransferReviewRequest
2026-08-26 15:43:34 +08:00
Pine 00f43976b3 feat(auth): 账号类型收敛为四种 + 对外下发中文标签(文本)
- account_type(role)→operator/carrier/opc_member/service; 非运营非OPC一律service; sub_role置None
- 登录/me/资料统一返回 account_type + account_type_label(运营方/载体方/OPC/服务方); 前端直接渲染文本
- 权限按账号类型解析(service→provider基座), 逻辑集中在 app/domain/account_types.py
2026-08-26 13:09:02 +08:00
Pine 53521b9438 feat(auth): 支持通过小程序码「绑定小程序」到当前账号
- WxQrSessionStore 支持 bind_user_id(绑定态)+message; bind_user() 访问器
- POST /auth/mp-qr/bind-start(当前账号发起,返小程序码); confirm 检测绑定态: 把openid绑到目标账号(若该微信属另一账号则按手机号/微信合并)
- poll 返回 message(bound); repositories 加 set_wx_mini_openid
2026-08-26 12:47:55 +08:00
Pine f697fdad37 feat(auth): 统一账号绑定/解绑 + 按手机号自动合并(同一账号不新建)
- merge_accounts(keeper,absorbed): 身份字段继承、user_identities改挂、audit_logs/任务归属改指keeper、absorbed级联删除(防FK阻断)
- POST /auth/bind-phone(验证码,手机号被占用→按手机号合并成keeper并返新令牌); POST /auth/unbind(至少要留一种登录方式); wx-phone 改走合并
- profile 加 wxBound/wxMiniBound; schemas BindPhoneRequest/UnbindRequest
2026-08-26 12:15:22 +08:00
Pine cbe0d03357 feat(admission): 园区入驻申请 —— park_admissions表+训练子应用端点+上传放宽
- 模型迁移0012 park_admissions(tenant/user/form_json/docs_json/status)
- app/training: GET /api/park/tenants(公开) / POST /api/park-admission / mine / 运营列表+review
- /api/upload 放宽到 图片/pdf/doc,20MB
2026-08-26 11:59:54 +08:00
Pine c2f4c13ab3 feat(auth): 账号唯一性+清理多余账号 —— 迁移0011加phone/微信openid非空部分唯一索引
- users.phone/wx_openid/wx_mini_openid/wx_unionid 各自唯一(非空部分唯一索引)
- 创建账号必生成ID(create用new_id);find_by_phone/find_by_wx 唯一校验
- cleanup_accounts.py 清理旧accounts已被users接管的重复账号;seed不再重复造账号、迁移后删旧行
2026-08-25 22:47:27 +08:00
Pine 9d60e0afc6 feat(auth): 平台成唯一账号源——小程序微信登录进 users + OPC 报名资料字段
统一用户账号体系(阶段1,非破坏):
- UserRepository 新增 get_by_wx_mini_openid。
- /auth/wx-login:小程序登录(X-Client=miniprogram)按 wx_mini_openid 建/复用
  users 账号(role=opc_member, source=mini_program, auth_type=wx_openid),
  并带 nickName/avatarUrl;非小程序仍走 wx_openid。
- /auth/me + 登录响应补齐小程序契约字段 name/phone/phoneBound。
- users 增 opc_status/topics 列(alembic 0010);desktop/web profile 也输出
  name/phone/phoneBound/status/topics,且 update-profile 支持 name/status/topics 映射。
- scripts/db/seed.py 增 accounts→users 幂等迁移:旧小程序账号并入全局 users
  (wx_mini_openid/phone 关联 + opc_member 身份),由用户执行 migrate+seed。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 19:59:34 +08:00
Pine ea904d3a50 feat(task): 完善任务系统 —— 分类字典/字段/四种接单方式/独占限额/交付时限
- Task 加 published_at/delivery_days/headcount/exclusive/publisher_id/category_id;新增 TaskCategory 分类字典表(35 类)。
- mode 归一 grab/bid/assign/recommend(旧 designated→assign、dispatch→recommend);TaskService 加 assign/recommend/select_recommend,claim 支持独占/限额、published+claimed 均可抢(多人)。
- TaskClaim 支持 source=assign/recommend、status=assigned/recommended/withdrawn + count_active_by_task;TaskCategoryRepository;Database 装配 task_categories。
- 端口:operator GET /admin/task-categories + POST tasks/{id}/assign|recommend|select;opc 同;park /api/tasks 返回 mode/deadline/delivery_days/headcount/exclusive/publisher_name。
- 迁移 0009(tasks 加列+task_categories)已应用+stamp;seed 35 分类字典 + task 新字段(含独占/推荐演示) + 补种已初始化库。
- 测试 test_task_system.py(独占/限额/指派/推荐/list_published/publish/category)+补齐 test_task_claim 语义, 15 passed。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 19:30:16 +08:00
Pine b9b5e2e2ff feat(task): 任务中心扫码接单(多端) —— 服务端任务状态机/端口/迁移
- Task 加 task_code/tags/display_priority/claimed_by/claimed_at/doing_at;新增 TaskClaim 流水表。
- TaskService 加 claimed/doing/completed 状态机(claim/start_doing/complete),grab 并入 claim。
- TaskRepository 加 list_published/get_by_code/update/claim/set_doing + TaskClaimRepository;挂 Database。
- 端口:
  · opc  /tasks/grab-by-code、/tasks/{id}/doing、/tasks/{id}/complete
  · operator POST /tasks(auto task_code) + PATCH /tasks/:id
  · park  /park/api/tasks(大屏展示,含 scan_payload 二维码载荷)
  · training /api/tasks/claim-by-code、/api/tasks/my(小程序 C 端账号→OPC 身份 find-or-create 领单)
- 迁移 0008(tasks 加列 + task_claims)已应用+stamp;seed 补 task_code/tags/grab demo。
- tests/test_task_claim.py(自包含内存库, 状态机+流水+list_published), 直接 async 校验通过。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 18:40:35 +08:00
Pine 0039a809ac feat(user): 用户认证状态/所属/账号类型 分类字段
- users 增: certification_status(uncertified|pending|certified|rejected)+certification_time, affiliation(independent|park)+park_id/park_name, account_type(opc_default|park_staff|platform_staff|provider|enterprise); alembic 0007
- repo: set_classification; _user_to_dict 含全部新字段; profile 返回认证/所属/账号类型
- admin: POST /admin/users/{id}/classification(认证/分类设置, action:user.manage) + UserClassificationRequest schema
- 迁移已应用, 导入通过
2026-08-25 16:24:19 +08:00
Pine 879396b532 feat(user): 全局用户准确来源 + 丰富跨端字段(全端口兼容)
- users 增: wx_unionid/wx_mini_openid(微信绑定), source(来源枚举), auth_type, register_ip, last_login_ip/at, email, gender, birthday, compute_provisioned/username/quota/used_quota(算力镜像); alembic 0006
- 来源: register/phone-login/wx-login(读 X-Client 头,回退 body.source,再回退按 auth_type 推断)、admin 创建=admin、seed=seed
- auth: 登录(签发令牌)记 last_login; profile 返回 source/auth_type/compute; email/gender/birthday 可编辑
- 对账 sync-users 回写 compute_* 镜像到平台用户
- _user_to_dict 含全部新字段; 迁移已应用, 导入/零依赖校验通过(dict 含 source/算力)
2026-08-25 16:21:20 +08:00
Pine 5f0acfa79e feat(park): 视频识别剥离,per-tenant 配置接入 park-vision 独立服务
- 删除 vision_yolo/vision_llm 及路由 /api/vision/frame|llm(保留遥测 event),去除 ultralytics 依赖
- 视频识别改为每园区(per-tenant)配置,经 park_settings(kv) 键 vision_api:<tid> 存取
- /park/api/vision/config GET/PUT(园区端读写本园区识别地址,可局域网);bind 下发含 vision_api
- 新增 alembic 0004(tenant_id 可空) / 0005(park_settings 表),迁移脚本执行
2026-08-25 01:52:23 +08:00
Pine 6de1b5a31b refactor(training): 培训数据层并入唯一总库 app.db(非运行态建表/种子,全列可空)
- 训练 ORM 模型改名回旧表名(accounts/events/bookings/tests/courses/policy_logs/plan_logs/survey_logs)
  并全列可空(兼容按部分字段插入);alembic 0003 丢弃重建并入唯一总库。
- training/db.py 指向 app.db、移除运行时 init_db;main.py lifespan 移除 init_db。
- seed.py 增培训种子(超管账号/排期/在线课程, 幂等)。
- 验证(真实库 migrate+seed+TestClient):auth/me、admin/*、park/*、training /api/health|events|courses 全 200。
2026-08-24 20:31:57 +08:00
Pine a9d14cb20e fix(db): 种子智能体彻底幂等 — INSERT OR IGNORE(复合唯一) + port 默认 ''
-add_agent 改用 SQLite on_conflict_do_nothing((id,user_id,port)),杜绝运行时/重跑 UNIQUE;
port 无端口身份默认 ''(agents.port NOT NULL)。真实库 migrate+seed 连续 3 次均成功。
2026-08-24 20:19:02 +08:00
Pine b6315f69b0 feat(park): 大屏设备绑定流 — 永久设备ID+连接码+园区端绑定+MQTT下发设备token
- park_screens 加 status/code/code_expires/bound_at、tenant_id 可空(alembic 0002)。
- auth 加 create/parse_device_token {tenant_id,device_id}。
- tenants 加 ensures_device/set_device_code/find_device_by_code/bind_device/unbind_device。
- 端点:/park/api/devices/register、/park/api/devices/{device_id}/code(8位码TTL10min)、
  /park/tenants/{tid}/screens/bind-by-code(校验码→绑定→MQTT opc/display/bind/<dev> 下发 token)、
  /park/api/devices/{device_id}/unbind。_resolve_tenant 支持设备 token。
- 验证(TestClient):register→code→建园区→绑码(bound/命名)→设备token取数据返回绑定园区。
2026-08-24 20:10:46 +08:00
Pine c723675414 fix(db): AGENT_SEED 全局固定 id 种子冲突 — 智能体幂等播种
新增 _add_agent(按 (id,user_id,port) 已存在则跳过),base 路径/_ensure_extra_demo_users/
_ensure_port_agents 三处统一调用;修复多用户/多端口复用固定 agent id 触发唯一冲突。
验证:临时库 migrate+seed 完整通过且重跑幂等(pine 已灌入)。
2026-08-24 19:35:18 +08:00
Pine 75caab4d39 feat(db): P2 摘除运行时种子 + 脚本化迁移/种子(migrate.py/seed.py)
- Database.initialize() 不再 create_all/seed_data:运行时仅做库连通检查(不建表不灌种子)。
- 新增 scripts/db/migrate.py(封装 alembic upgrade/downgrade)、scripts/db/seed.py(非运行态灌平台种子)。
- 新增 serverdata/seed/(README) 存放种子 JSON。
- 迁移/种子流程:uv run python scripts/db/migrate.py + scripts/db/seed.py,再启动应用。
- 已知待修:seed 内 AGENT_SEED 全局固定 id 唯一冲突(既有缺陷, 待 P2 后续修);pine/角色已能灌入。
2026-08-24 19:32:41 +08:00
Pine 8b0bca36a1 feat(db): P1 Alembic+模型整合 — 唯一总库基线迁移 + 培训/园区 ORM 模型
- 新增 alembic(ini/env async/script.mako/versions/0001_initial)。
- models.py 并入培训表(training_accounts/events/bookings/tests/courses/policy/plan/survey_logs)
  与园区表(park_tenants/companies/kb_docs/screens),与平台同库、命名加域前缀避免撞名。
- baseline 迁移用 create_all(幂等):既有平台表保留,新增培训/园区表被建。
- 验证:对临时库 uv run alembic upgrade head 建出全部新表。
2026-08-24 19:28:18 +08:00
Pine c4fb4fb498 fix(server-core): 种子容错 + 智能体种子幂等 — 修复 lifespan 建库被种子唯一冲突拖垮(全500)
根因:AGENT_SEED 用全局固定 agent id,demo 用户补种时对多个用户复用同一 id → (id,user_id,port)
唯一冲突 → seed_data 抛 IntegrityError → 平台 lifespan 建库失败 → app.state.db 未设置 → 全 500。
- repositories.initialize:种子包 try/except + rollback(记 warn),种子失败不再拖垮 lifespan 建库。
- seed._ensure_port_agents:改为按 agent.id 逐条判断已存在,避免重复插入幂等。
验证:登录/me/users/courses/roles 全 200。
2026-08-24 19:15:20 +08:00
Pine 83e542c2c2 feat(平台端): 完整用户管理 — 新增 修改(PUT /admin/users/{id}) + 删除(DELETE /admin/users/{id})
UserRepository.delete(硬删);UpdateUserRequest(昵称/角色/子角色/组织/区域);update_user 调 update_profile+set_role,
delete_user 调 delete;走 action:user.manage + write_audit。TestClient:create/update/delete 均 200。
2026-08-24 18:40:59 +08:00
Pine b90539a013 feat(server): 统一登录+算力打通(port 阶段0-1)落地四层架构
- 登录:/auth/send-code·phone-login·wx-login·wx-phone(复用 RBAC 签发)
- 算力:services/compute_client(loopback :3000)+ /admin/compute/ping·provision
- /v1 relay 改走 compute-engine(前端不直连引擎)
- 模型:User 补 wx_openid/phone;仓储 async create+新方法
- 契约:api/schemas(auth/compute)Pydantic
2026-08-24 14:16:34 +08:00
Pine 01ef3c9637 refactor: schemas 抽取(DTO 从 models.py 与路由内联迁至 api/schemas/)
- 新建 api/schemas/:auth/agents/admin/ecosystem/investor/opc/operator/org/portals
- models.py 移除 15 个 Pydantic DTO(保留 ORM 数据模型层)
- 13 个路由内联 DTO 全部迁出,路由瘦身仅剩处理逻辑
- 全量 66 测试通过
2026-08-24 09:51:52 +08:00
Pine 681067f84b fix: 修正 OrgRepository/OrgMember 新增方法(类作用域,修复 _to_dict_org NameError)
- FinanceRepository.create / OrgRepository.all+list_by_ids / OrgMember.list_for_user+get 精准插入
- 移除误插入 Config/Region 的冗余方法
- 31 受影响测试 + 全量 66 全绿
2026-08-24 02:14:22 +08:00
Pine c82f430986 feat: 业务层 services 继续抽取(路演/机构)
- RoadshowService:路演发布审核规则(operator 免审/政务范围免审/其余需审)
- OrgService:my_orgs 批量查消除 N+1、成员管理(admin 校验)
- 新增 Repository:Org.list_by_ids、OrgMember.list_for_user/get
- rbac_investor/rbac_org 接线,路由瘦身
2026-08-24 01:58:26 +08:00
Pine 413bd29390 feat: 业务层 services 抽取(财务/结算/补贴)
- FinanceService:opc_add_finance 直写 ORM 改为走 Repository.create(修复四层依赖违规)
- SettlementService:结算佣金(5%)/电子合同幂等/争议联动/投资撮合评分
- SubsidyService:政务三级审批状态机(区县→市→省→发放)
- rbac_ecosystem/rbac_government/rbac_opc 接线,路由瘦身
2026-08-24 01:54:04 +08:00
Pine a869b2934a test: 平台测试套件适配异步四层,66 全绿
- conftest 改为 monkeypatch DATABASE_URL + lifespan 建库(解决异步引擎跨事件循环)
- 修复 seed_data 辅助函数 await、_to_dict 链式 await、get_current_user await
- 修复 Database.initialize 建表于本实例引擎
- 平台 19 路由全部经异步接口回归通过
2026-08-24 00:34:28 +08:00
Pine 980a2db6d9 refactor: 平台应用异步四层架构(接口/业务/领域/基础设施)
- 基础设施层 async:SQLAlchemy 异步引擎/会话、33 Repository async 化、models/security/seed 迁入 infrastructure、新增 cache.py(redis.asyncio) 与 oss.py(aioboto3)
- 接口层:routers 迁 api/routers 并全 async,dependencies 迁 api/dependencies(get_db/get_current_user async)
- 依赖:sqlalchemy[asyncio]/aiosqlite/asyncmy/redis/aioboto3;config 异步 URL + Redis/OSS 配置
- 删除废弃:旧同步 db/dependencies/repositories/storage
- 验证:平台 19 路由 + 培训 48 路由全注册;/health /auth/login /auth/me /admin/tasks /notifications 等接口 async 可用
2026-08-23 23:52:58 +08:00