实验室:按用户开关的实验功能基座 - #117
Merged
Merged
实验室:按用户开关的实验功能基座#117
Conversation
Labs is a card on the settings page: features still being tried out,
off by default, switch stored server-side per user.
- sr_user_lab_feature (user_id, feature, enabled, created_at, updated_at);
no row means off. Migration adds the table and its two indexes.
- LabRepo: listByUser / isEnabled / upsert on the Postgres client.
- LabService: registry is an overridable method (empty here so a
self-hosted build sees no change); status active reads the switch,
graduated is on for everyone, retired is off for everyone.
assertUrlAllowed() throws LAB_FEATURE_DISABLED when a URL needs a
feature the user has not turned on; gatedFeatureForUrl() is the hook a
hosted backend overrides to say which URLs are gated.
- LAB_FEATURE_DISABLED (400) carries the feature's display name in the
localized message (zh / en / es), so clients show it as-is.
- GET /v1/user/labs returns { features: [{ key, status, enabled, enabled_at }] }.
- POST /v1/user/setting/enable|disable with key "lab:<feature>" flips
the switch; UserService takes LabService.
- Regenerated router and DI.
Claude-Session: https://claude.ai/code/session_01Xg119Pyy2B2UQQddrxw5Dv
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Sep 8, 2026
DGuang21
approved these changes
Sep 9, 2026
DGuang21
added a commit
that referenced
this pull request
Sep 9, 2026
* feat: export saved links with account-scoped pagination * 🧪 per-user switches for Labs features (#117) Labs is a card on the settings page: features still being tried out, off by default, switch stored server-side per user. - sr_user_lab_feature (user_id, feature, enabled, created_at, updated_at); no row means off. Migration adds the table and its two indexes. - LabRepo: listByUser / isEnabled / upsert on the Postgres client. - LabService: registry is an overridable method (empty here so a self-hosted build sees no change); status active reads the switch, graduated is on for everyone, retired is off for everyone. assertUrlAllowed() throws LAB_FEATURE_DISABLED when a URL needs a feature the user has not turned on; gatedFeatureForUrl() is the hook a hosted backend overrides to say which URLs are gated. - LAB_FEATURE_DISABLED (400) carries the feature's display name in the localized message (zh / en / es), so clients show it as-is. - GET /v1/user/labs returns { features: [{ key, status, enabled, enabled_at }] }. - POST /v1/user/setting/enable|disable with key "lab:<feature>" flips the switch; UserService takes LabService. - Regenerated router and DI. Claude-Session: https://claude.ai/code/session_01Xg119Pyy2B2UQQddrxw5Dv Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: daguang <28806852+DGuang21@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
实验室是设置页的一张卡片:实验功能按用户开关,默认关,开关存服务端。这个 PR 是开源基座,注册表为空,自托管看不到任何变化;托管后端用同名子类注册具体功能。
sr_user_lab_feature(user_id, feature, enabled, created_at, updated_at),一人一功能一行,没有行就是关。迁移建表和两个索引。LabRepo:listByUser / isEnabled / upsert。LabService:注册表是可覆盖的方法。三种状态:active读用户开关,graduated对所有人开,retired对所有人关。assertUrlAllowed()在保存前拦截需要实验功能的链接,gatedFeatureForUrl()是托管端覆盖的钩子,这里返回 null。LAB_FEATURE_DISABLED(400),三语文案带功能名,客户端可以原样显示。GET /v1/user/labs返回{ features: [{ key, status, enabled, enabled_at }] };POST /v1/user/setting/enable|disable的 key 以lab:开头时写开关。UserService多一个LabService参数。验证:vitest 6 个文件 29 条通过(新增 13 条);tsc 没有新增错误。
基于 #116(导出)的分支,那个合并后这个会自动改成对 main。
关联 PR: