Address two gaps in the first DingTalk-session UI:
- add an explicit admin-only '+ 新增钉钉知识库' action on the data-source
panel; it accepts an alidocs space URL, resolves the live name/root through
the authenticated sidecar, writes the inventory root atomically, upserts a
deterministic source connection, and enqueues its first catalog refresh
- read DingTalk's real QR canvas pixels rather than taking a DOM screenshot;
select by dark-pixel content, composite onto a white quiet zone, and render
at 320x320 so the dialog contains a large complete code, not a page thumbnail
The live refresh path resolves registered roots from the connection locator,
while existing name-based DingTalk sources remain compatible.
DingTalk source scanning depends on a shared browser session whose capture
file had to be replaced by hand whenever it expired (every scan 401s).
- services/dingtalk-login: admin-triggered Playwright sidecar that opens the
space page in a persistent headless Chromium, publishes the QR through
session polling, verifies the first authenticated XHR against the box API,
then writes the capture in place (same inode keeps the worker's ro bind
mount current); tokens never leave the sidecar
- api: POST/GET/DELETE /api/v1/dingtalk-session authenticated relay; QR is a
login artifact, so the whole prefix is admin-only in classifyRole; OpenAPI
contract and proxy/503/hostile-ID tests included
- web: 系统设置 → 数据源配置 钉钉卡片新增扫码刷新会话(仅管理员可见),
QR 弹窗 + 1.5s 轮询 + 成功/过期/失败状态
- compose: sidecar service owns the ONLY rw mount of secrets/; worker keeps ro