Adds 开发工具 → 数据库管理台, which exchanges the admin bearer token for a
single-use entry link (POST /api/admin/v1/internal-surfaces/db-studio/session)
and opens it in a new tab. The link sets an HttpOnly session cookie on the
console's own hostname, so it has to be opened by the browser rather than
fetched — the nginx gate in front of the console then re-checks the permission
on every request.
The tab is opened synchronously inside the click handler, before the request
resolves, or the popup blocker kills it; `noopener` is unusable there since it
makes window.open return null, so the opener is detached manually.
Gated on auth:db-studio:access. That key is `auth:`-prefixed rather than
`admin:` on purpose — PermissionSeeder syncs the admin role to every `admin:%`
key, which would grant database-owner SQL access to every admin account.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The store's can()/useCan() helpers existed but were unused. Now:
- src/auth/permissions.ts PERM catalog mirrors backend keys
- every nav item carries a permission; sidebar filter reuses can()
- requirePermission() beforeLoad guard on all child routes (direct URLs
redirect home when the session lacks the key)
- useCan() hides/disables mutation buttons: moderation actions,
retranslate, robot-author edit/pause, category + locale CRUD, and the
reserved-SID assign path (admin:sid:override hint)
- 403 responses toast 无权限执行此操作; can() unit tests added
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>