12 Commits

Author SHA1 Message Date
GuoQing Zhang c8f9ebac9b scripts: change scripts dir 2026-06-08 17:02:32 +08:00
dolphin cee2207f5b refactor: update architecture documentation, clean up local dev environment, and consolidate coding rules 2026-06-07 14:26:14 +08:00
GuoQing Zhang 3b1cb3307e feat(dm): unified MySQL->DaMeng data migration across bisheng/gateway/openfga
Add scripts/migrate_mysql_to_dm.py + .sh wrapper + example config: a single
data-only migration tool covering all three databases. Schema is owned by each
app's own DM path (create_all/init_dm.sql/openfga migrate); the script copies
rows with IDENTITY_INSERT, trigger/FK disabling, identity reseed, JSON->CLOB
conversion, --verify and --resume-from.

Remove src/backend/scripts/mysql_to_dm_migrate.py: bisheng-only and superseded
by the unified script (which also handles IDENTITY_INSERT and update_time
trigger disabling that the old script lacked).
2026-06-05 19:42:49 +08:00
GuoQing Zhang ad2526b951 fix(approval): activate PENDING channel membership on subscribe approval
find_membership defaulted to ACTIVE-only for channels, so the approval
activation flow could not locate the applicant's PENDING membership and
on_approved silently returned missing_membership — outbox/instance reported
success while the membership stayed PENDING and no ReBAC grant was written,
so the channel never appeared in the user's subscription list.

- find_membership: add include_inactive flag (default keeps ACTIVE-only)
- approval activation paths pass include_inactive=True
- on_approved now raises on missing membership instead of faking success
- add regression tests + repair script for stuck instances 248/250/251/252
2026-06-03 20:58:30 +08:00
dolphin 991d5f7cb7 feat: improve conversation export robustness by adding async PDF rendering, emoji sanitization for office compatibility, and refined markdown parsing. 2026-06-01 19:30:42 +08:00
dolphin 606d08cd49 refactor:update export font configurations for Linux environment compatibility 2026-06-01 17:51:13 +08:00
dolphin c7d6d25d18 feat: F028 backend — workstation conversation export & import-to-knowledge
Backend implementation for F028 conversation export feature
(spec features/v2.6.0/028-conversation-export-import/).

What ships:
- SDD docs: spec.md + tasks.md (both reviewed); release-contract +
  v2.6.0 README index updated
- DTOs in workstation/domain/schemas/conversation_export.py
- Errcodes 12060-12069 in common/errcode/workstation.py
- ConversationExportService: load + turn build, 4 renderers
  (md/txt + pypandoc-docx + LibreOffice-pdf), image preprocessing
  with httpx + data: URL inline decode, filename resolver,
  import-to-knowledge with dedup rename + race-retry
- 3 endpoints: POST /api/v1/chat/messages/export,
  POST /api/v1/chat/messages/import-to-knowledge,
  GET /api/v1/knowledge/space/uploadable
- ChatMessageDao.aget_messages_by_ids (anti-IDOR (user_id, chat_id)
  compound predicate)
- KnowledgeSpaceService.list_uploadable_spaces (OpenFGA can_edit list +
  creator-owned union; admin path → tenant-scoped scan)
- libreoffice_converter: add convert_docx_to_pdf + timeout param
- 79 backend tests passing (load+turn 17, renderers 23, import 15,
  uploadable service 9, export+import API 12, uploadable API 3)
2026-05-31 11:33:03 +08:00
LineWalker ef5c3d11b4 fix(F008): migrate KnowledgeDao + FlowDao permission filtering to ReBAC
F008 在 v2.5.0 把 service 层迁到 ReBAC,但漏掉了 2 个 DAO 层的权限过滤路径
(spec 措辞只点了 judge_role_access,遗漏 find_role_access 系列 + get_role_access
列表型)。这两处的实际后果是:F007 授权 UI 写入的 ReBAC 元组对它们无效,
管理员配了等于没配;多租户场景下 Root 通过 FGA shared_with 共享给 Child 的资源
也走不通这条消费路径。

KnowledgeDao.judge_knowledge_permission / ajudge_knowledge_permission
(被客户端日常模式 orgKbs 检索 + 工作流通用 KB 节点 user_auth=True 消费)
和 FlowDao.get_user_access_online_flows(被 Assistant.get_auto_flow_info 自动选
技能消费)现在都改走 LoginUser.init_login_user[_sync] + PermissionService
.list_accessible_ids('can_read', ...),admin 短路语义保留,owner / 部门管理员 /
租户管理员的隐式范围由 _finalize_accessible_ids 自动覆盖。

防回归:
- features/v2.5.1/release-contract.md 表 2 新增 INV-T19(DAO/Model 层禁止直读
  RoleAccessDao 做权限过滤),列出 4 类例外白名单
- scripts/arch-guard.sh 加 RULE-8(PostToolUse per-file 钩子)
- scripts/check-rbac-rebac-leak.sh 新增(仓库级 one-shot 守卫,CI/pre-commit 用,
  当前 exit 0 clean)
- features/v2.5.0/008-resource-rebac-adaptation/tasks.md 末尾追加 T12 补丁记录

测试:13 用例全绿(test_knowledge_dao_judge_permission_rebac.py 10 +
test_flow_dao_user_access_rebac.py 3),覆盖 admin 全集 / 普通用户交集 /
无交集 / 空入参 / 用户不存在 5 类边界。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:01:25 +08:00
RUCYancy be8265c8ba feat(2.5.0): Bearer JWT in HTTP middleware, disabled-user kick, login/captcha UX, app share permission, local-dev tooling
- Align get_captcha use_captcha with async settings; exempt get_captcha from token_version checks

- Platform: 401 redirect to root when session existed; LDAP/captcha login fixes; i18n and org UI

- Client: can_share and permission UI; gateway dev proxy examples

- Docker: mount http_middleware for backend dev; local-dev middleware scripts

Made-with: Cursor
2026-04-23 20:41:02 +08:00
LineWalker 214080dd74 feat(F015-v2.5.1): 部门定时校对 + SSO 换型 relink + 冲突告警(T01-T15)
- 新建 11 Python 模块:
  - ReconcileConf(core/config)
  - OrgReconcileService(6h 校对核心编排,Redis SETNX 锁,11 步)
  - DepartmentRelinkService(external_id_map / path_plus_name 双策略)
  - RelinkConflictStore(Redis HASH + 7d TTL)
  - RemoteDeptDiffer(F009 reconciler 的 ts-annotated 薄包装 + crosses_tenant 派生)
  - TsConflictReporter(weekly + daily escalation 聚合)
  - 3 Celery tasks:reconcile_all_organizations / report_ts_conflicts_weekly / daily_escalation
  - Pydantic schemas/relink.py
  - API endpoints/relink.py + resolve-conflict
- 扩展 8 模块:
  - errcode/sso_sync.py +5 错误码 19314-19318(MMM=193 与 F014 共享)
  - settings.py 注册 ReconcileConf + 3 beat 条目
  - department.py 加 aget_active_by_source_path_name / aupdate_external_id /
    aget_user_ids_by_department DAO
  - org_sync.py 加 event_type/level/external_id/source_ts 列 + idx_conflict_lookup +
    aget_all_active / acreate_event / acount_recent_conflicts /
    aget_conflicts_since / aget_latest_event
  - http_middleware.py TENANT_CHECK_EXEMPT_PATHS 加 relink 两路径
  - api/router.py 挂载 relink_router
  - conftest.py / table_definitions.py 同步 F015 新字段 + 索引
- Alembic 迁移 v2_5_1_f015_reconcile_log_fields(幂等 upgrade/downgrade)
- 8 测试文件约 60 条用例(SQLite + AsyncMock 模式)覆盖 AC-01..AC-13 + INV-T12/T8/T7/T2
- 文档:tasks.md + ac-verification.md + locust 性能占位(AC-08 发版前跑)

AC-11 关键:同 ts Gateway-upsert + Celery-remove 冲突走 remove-wins 路径,
写 audit_log.action='dept.sync_conflict' + event_type='ts_conflict' 事件行
+ 19317 warn,统一由 DepartmentDeletionHandler(CELERY_RECONCILE) 触发孤儿处理。

本地已通过 py_compile;pytest 待 114 远程或 CI 跑。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 09:09:41 +08:00
LineWalker cc70a33086 Fix F006 Step 4 case sensitivity + add end-to-end verification script
Seeding the live 114 MySQL with realistic mock data and running the full
F006 migration surfaced a second latent bug: SCM_ROLE_MAPPING and
SCM_TYPE_MAPPING use lowercase keys (creator/admin/member, space/channel),
but production MySQL stores the columns as ENUM('SPACE','CHANNEL') and
ENUM('CREATOR','ADMIN','MEMBER') — uppercase. Step 4 was silently dropping
every real space/channel member row (19 rows on 114) because .get(role)
returned None and the code fell into the "skip unknown role" branch.

Test fixtures had masked the issue: the SQLite schema uses VARCHAR(16)
with lowercase test data, so .get(role.lower_value) happened to work in
tests but never in production.

Fix:
- migrate_rbac_to_rebac.py step4_space_channel_members: normalize role
  and biz_type to lower() before mapping lookup
- migrate_rbac_to_rebac.py verify_all: same normalization on scm_set
  (so old-system membership comparison stays case-insensitive)
- test_f006_permission_migration.py: new TestStep4.test_uppercase_enum_values
  guarding against regressions by inserting the exact values production's
  enum would store

Also adds scripts/verify_f006_migration.py — a reusable end-to-end
verification harness that seeds all 9 legacy tables with diverse mock
data (all 10 AccessType values, 6 SCM role/status combinations, 3-level
folder hierarchy, skip-boundary cases for type=99 / role_id=1 /
PENDING / REJECTED / is_delete=1 / flow_type=15 / non-numeric paths),
runs the migration, invokes --verify mode, reconciles 47 must_have and
17 must_not_have tuples against OpenFGA, and cleans up.

Validation on 114 after the fixes:
  Step 1 super_admin:  2   Step 4 SCM:      25  (mock 6 + prod 19)
  Step 2 user_group:  13   Step 5 owners:   96
  Step 3 role_access: 17   Step 6 folder:   14
  Total tuples: 167     --verify regression: 0
  must_have 47/47     must_not_have 17/17     OVERALL: PASS
2026-04-18 00:06:42 +08:00
LineWalker be2aff6ada chore: add Claude Code tooling, SDD features, and PRD docs to version control
- .claude/: rules (dual frontend conventions), settings (arch-guard hook),
  6 skills (code-review, e2e-test, i18n-localizer, react-component-refactor,
  sdd-review, task-review)
- features/: SDD templates, v2.5.0 release contract, F007-F010 spec/tasks
- scripts/arch-guard.sh: architecture violation checker
- CLAUDE.md: add frontend dual-stack conventions section
- docs/PRD: update multi-tenant requirement docs
- .gitignore: exclude .claude/settings.local.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 01:22:29 +08:00