feat(auth): /initialize auto-creates default workspace + owner membership
initialize_admin now seeds a 1-person workspace immediately after the admin user is created: WorkspaceRepository.create(name, slug, owner_id) + WorkspaceMembershipRepository.add(role='owner') + writes the new workspace id back to users.default_workspace_id. The session JWT is re-issued with wid + role='owner' so subsequent requests pass the T4.7 workspace gate. Mechanical pieces: - SQLiteUserRepository row<->user mapping now includes default_workspace_id (sql update_user too) so the column persists. - workspace.sql.SLUG_BLACKLIST is now public (was _SLUG_BLACKLIST) and the registration helper treats blacklisted slugs as "taken" so the walker steps past reserved names like "admin" instead of crashing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,7 @@ _SLUG_MAX_LEN = 32
|
||||
|
||||
# slug 黑名单(应用层校验,不写 DB constraint)。包含 ADR-007 §4 保留 slug
|
||||
# + 路径 + Next.js 保留 + 业务保留词。
|
||||
_SLUG_BLACKLIST = frozenset(
|
||||
SLUG_BLACKLIST = frozenset(
|
||||
{
|
||||
"admin",
|
||||
"api",
|
||||
@@ -77,7 +77,7 @@ def _validate_slug(slug: str) -> None:
|
||||
raise WorkspaceValidationError(f"slug length must be between {_SLUG_MIN_LEN} and {_SLUG_MAX_LEN}, got {len(slug)}")
|
||||
if not _SLUG_PATTERN.fullmatch(slug):
|
||||
raise WorkspaceValidationError(f"slug {slug!r} does not match required pattern ^[a-z0-9](-?[a-z0-9])*$")
|
||||
if slug in _SLUG_BLACKLIST:
|
||||
if slug in SLUG_BLACKLIST:
|
||||
raise WorkspaceValidationError(f"slug {slug!r} is reserved")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user