feat: scope workspace routes by organization slug

This commit is contained in:
2026-07-02 20:11:57 -07:00
parent fae97a7046
commit 3ab0e3e034
48 changed files with 565 additions and 96 deletions

View File

@@ -27,6 +27,7 @@ import type {
PublicAccount,
Session,
} from "@/modules/core/types";
import { RESERVED_WORKSPACE_SLUGS } from "@/modules/shared/lib/workspace-routing";
const SESSION_COOKIE = "teatea_session";
const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24 * 7;
@@ -154,7 +155,8 @@ function createSlug(name: string): string {
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "");
return base.length > 0 ? base : `org-${Date.now()}`;
const slug = base.length > 0 ? base : `org-${Date.now()}`;
return RESERVED_WORKSPACE_SLUGS.has(slug) ? `org-${slug}` : slug;
}
export async function setSessionCookie(sessionId: string): Promise<void> {

View File

@@ -1,7 +1,7 @@
import { and, eq, inArray, isNull, or } from "drizzle-orm";
import { getDatabase } from "@/modules/core/server/db";
import { permissions, rolePermissions, roles } from "@/modules/core/server/schema";
import { organizations, permissions, rolePermissions, roles } from "@/modules/core/server/schema";
import { ensureSystemSettings } from "@/modules/core/server/system-settings";
import type { Permission, RoleDefinition, RoleId } from "@/modules/core/types";
import { PERMISSIONS, ROLE_LABELS } from "@/modules/core/types";
@@ -126,9 +126,21 @@ export const SYSTEM_ROLE_DEFINITIONS: SeedRole[] = [
{
key: "viewer",
scope: "organization",
description: "只读访客,查看老人、床位和入住信息。",
description: "普通用户,只读查看老人、床位和入住信息。",
permissions: ["facility:read", "admission:read", "elder:read"],
},
{
key: "family",
scope: "organization",
description: "亲属账号,预留给家属端与授权老人动态访问。",
permissions: [],
},
{
key: "resident",
scope: "organization",
description: "本人账号,预留给老人本人查看个人服务与健康信息。",
permissions: [],
},
];
export async function ensureSystemDefaults(): Promise<void> {
@@ -181,6 +193,9 @@ export async function ensureSystemDefaults(): Promise<void> {
if (inserts.length > 0) {
await database.insert(rolePermissions).values(inserts).onConflictDoNothing();
}
const organizationRows = await database.select({ id: organizations.id }).from(organizations);
await Promise.all(organizationRows.map((organization) => seedOrganizationRoles(organization.id)));
}
export async function seedOrganizationRoles(organizationId: string): Promise<void> {

View File

@@ -9,6 +9,8 @@ export const ROLE_IDS = [
"manager",
"caregiver",
"viewer",
"family",
"resident",
] as const;
export type RoleId = (typeof ROLE_IDS)[number];
@@ -20,7 +22,9 @@ export const ROLE_LABELS: Record<RoleId, string> = {
org_admin: "机构管理员",
manager: "运营主管",
caregiver: "照护人员",
viewer: "只读访客",
viewer: "普通用户",
family: "亲属",
resident: "本人",
};
export const PERMISSIONS = [