feat: scaffold supabase multi-tenant backend

This commit is contained in:
Codex
2026-06-21 21:54:43 +08:00
commit c9c767c7bd
99 changed files with 36660 additions and 0 deletions

12
packages/domain/package-lock.json generated Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "@tiku-saas/domain",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@tiku-saas/domain",
"version": "0.1.0"
}
}
}

View File

@@ -0,0 +1,8 @@
{
"name": "@tiku-saas/domain",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts"
}

View File

@@ -0,0 +1,37 @@
export const TENANT_ROLES = [
'platform_admin',
'tenant_owner',
'tenant_admin',
'tenant_operator',
'teacher',
'sales',
'agent',
'student',
];
export const QUESTION_STATUSES = ['draft', 'published', 'archived'];
export const ORDER_STATUSES = ['pending', 'paid', 'failed', 'closed', 'refunded'];
export const ENTITLEMENT_SCOPE_TYPES = ['tenant', 'region', 'module', 'subject', 'question_bank'];
export function normalizeTenantRole(role) {
const value = String(role || '').toLowerCase();
if (value === 'superadmin')
return 'platform_admin';
if (value === 'admin')
return 'tenant_admin';
if (value === 'operator')
return 'tenant_operator';
if (TENANT_ROLES.includes(value))
return value;
return 'student';
}
export function normalizeOrderStatus(status) {
const value = String(status || '').toLowerCase();
if (value === 'paid' || value === 'success')
return 'paid';
if (value === 'failed' || value === 'fail')
return 'failed';
if (value === 'refunded' || value === 'refund')
return 'refunded';
if (value === 'closed' || value === 'cancelled' || value === 'canceled')
return 'closed';
return 'pending';
}

View File

@@ -0,0 +1,39 @@
export const TENANT_ROLES = [
'platform_admin',
'tenant_owner',
'tenant_admin',
'tenant_operator',
'teacher',
'sales',
'agent',
'student',
] as const;
export type TenantRole = (typeof TENANT_ROLES)[number];
export const QUESTION_STATUSES = ['draft', 'published', 'archived'] as const;
export type QuestionStatus = (typeof QUESTION_STATUSES)[number];
export const ORDER_STATUSES = ['pending', 'paid', 'failed', 'closed', 'refunded'] as const;
export type OrderStatus = (typeof ORDER_STATUSES)[number];
export const ENTITLEMENT_SCOPE_TYPES = ['tenant', 'region', 'module', 'subject', 'question_bank'] as const;
export type EntitlementScopeType = (typeof ENTITLEMENT_SCOPE_TYPES)[number];
export function normalizeTenantRole(role: unknown): TenantRole {
const value = String(role || '').toLowerCase();
if (value === 'superadmin') return 'platform_admin';
if (value === 'admin') return 'tenant_admin';
if (value === 'operator') return 'tenant_operator';
if (TENANT_ROLES.includes(value as TenantRole)) return value as TenantRole;
return 'student';
}
export function normalizeOrderStatus(status: unknown): OrderStatus {
const value = String(status || '').toLowerCase();
if (value === 'paid' || value === 'success') return 'paid';
if (value === 'failed' || value === 'fail') return 'failed';
if (value === 'refunded' || value === 'refund') return 'refunded';
if (value === 'closed' || value === 'cancelled' || value === 'canceled') return 'closed';
return 'pending';
}