Refactor user and model structures to enhance organization and role management

- Reorganized models by replacing the assistant and chat models with a new agent structure, including assistant, chat, and history models.
- Updated user model relationships to reflect changes in role and type references, ensuring consistency with the new model structure.
- Removed obsolete organization and user role models, streamlining the overall architecture.
- Adjusted system model mappings to incorporate new member and role models, enhancing clarity in user management.
This commit is contained in:
Max 2025-09-16 09:35:18 +08:00
parent 426fec1608
commit 580f3683e2
14 changed files with 602 additions and 468 deletions

File diff suppressed because one or more lines are too long

View file

@ -20,25 +20,25 @@ import (
// SystemModels system models // SystemModels system models
var systemModels = map[string]string{ var systemModels = map[string]string{
"__yao.assistant": "yao/models/assistant.mod.yao", "__yao.agent.assistant": "yao/models/agent/assistant.mod.yao",
"__yao.agent.chat": "yao/models/agent/chat.mod.yao",
"__yao.agent.history": "yao/models/agent/history.mod.yao",
"__yao.attachment": "yao/models/attachment.mod.yao", "__yao.attachment": "yao/models/attachment.mod.yao",
"__yao.audit": "yao/models/audit.mod.yao", "__yao.audit": "yao/models/audit.mod.yao",
"__yao.chat": "yao/models/chat.mod.yao",
"__yao.config": "yao/models/config.mod.yao", "__yao.config": "yao/models/config.mod.yao",
"__yao.dsl": "yao/models/dsl.mod.yao", "__yao.dsl": "yao/models/dsl.mod.yao",
"__yao.history": "yao/models/history.mod.yao",
"__yao.job.category": "yao/models/job/category.mod.yao", "__yao.job.category": "yao/models/job/category.mod.yao",
"__yao.job": "yao/models/job/job.mod.yao", "__yao.job": "yao/models/job/job.mod.yao",
"__yao.job.execution": "yao/models/job/execution.mod.yao", "__yao.job.execution": "yao/models/job/execution.mod.yao",
"__yao.job.log": "yao/models/job/log.mod.yao", "__yao.job.log": "yao/models/job/log.mod.yao",
"__yao.kb.collection": "yao/models/kb/collection.mod.yao", "__yao.kb.collection": "yao/models/kb/collection.mod.yao",
"__yao.kb.document": "yao/models/kb/document.mod.yao", "__yao.kb.document": "yao/models/kb/document.mod.yao",
"__yao.organization": "yao/models/organization.mod.yao", "__yao.team": "yao/models/team.mod.yao",
"__yao.organization_user": "yao/models/organization_user.mod.yao", "__yao.member": "yao/models/member.mod.yao",
"__yao.user": "yao/models/user.mod.yao", "__yao.user": "yao/models/user.mod.yao",
"__yao.user_role": "yao/models/user_role.mod.yao", "__yao.role": "yao/models/role.mod.yao",
"__yao.user_type": "yao/models/user_type.mod.yao", "__yao.user.type": "yao/models/user/type.mod.yao",
"__yao.user_oauth_account": "yao/models/user_oauth_account.mod.yao", "__yao.user.oauth_account": "yao/models/user/oauth_account.mod.yao",
} }
// Load load models // Load load models

View file

@ -217,17 +217,17 @@ func NewDefaultUser(options *DefaultUserOptions) *DefaultUser {
roleModel := options.RoleModel roleModel := options.RoleModel
if roleModel == "" { if roleModel == "" {
roleModel = "__yao.user_role" roleModel = "__yao.role"
} }
typeModel := options.TypeModel typeModel := options.TypeModel
if typeModel == "" { if typeModel == "" {
typeModel = "__yao.user_type" typeModel = "__yao.user.type"
} }
oauthAccountModel := options.OAuthAccountModel oauthAccountModel := options.OAuthAccountModel
if oauthAccountModel == "" { if oauthAccountModel == "" {
oauthAccountModel = "__yao.user_oauth_account" oauthAccountModel = "__yao.user.oauth_account"
} }
// Set ID generation strategy with defaults // Set ID generation strategy with defaults

View file

@ -98,7 +98,7 @@ func cleanupTestData() {
// Use DestroyWhere (hard delete) to avoid soft delete complications // Use DestroyWhere (hard delete) to avoid soft delete complications
// Clean OAuth accounts first (due to foreign key constraints) // Clean OAuth accounts first (due to foreign key constraints)
oauthModel := model.Select("__yao.user_oauth_account") oauthModel := model.Select("__yao.user.oauth_account")
oauthPatterns := []string{ oauthPatterns := []string{
"%oauth_test%", "%_list_%", "%oauthlist%", "%oautherror%", "%oauth_test%", "%_list_%", "%oauthlist%", "%oautherror%",
"%google_%", "%github_%", "%apple_%", "%_delete_%", "%google_%", "%github_%", "%apple_%", "%_delete_%",
@ -113,7 +113,7 @@ func cleanupTestData() {
} }
// Clean roles (should be done before users due to potential role_id references) // Clean roles (should be done before users due to potential role_id references)
roleModel := model.Select("__yao.user_role") roleModel := model.Select("__yao.role")
rolePatterns := []string{ rolePatterns := []string{
"test%", "%testrole%", "%listrole%", "%permrole%", "%adminrole%", "%userrole%", "test%", "%testrole%", "%listrole%", "%permrole%", "%adminrole%", "%userrole%",
"%inactiverole%", "%systemrole%", "%validrole%", "%emptyupdate%", "%emptyperm%", "%inactiverole%", "%systemrole%", "%validrole%", "%emptyupdate%", "%emptyperm%",
@ -128,7 +128,7 @@ func cleanupTestData() {
} }
// Clean types (should be done before users due to potential type_id references) // Clean types (should be done before users due to potential type_id references)
typeModel := model.Select("__yao.user_type") typeModel := model.Select("__yao.user.type")
typePatterns := []string{ typePatterns := []string{
"test%", "%testtype%", "%listtype%", "%configtype%", "%basictype%", "%premiumtype%", "test%", "%testtype%", "%listtype%", "%configtype%", "%basictype%", "%premiumtype%",
"%inactivetype%", "%validtype%", "%emptyupdate%", "%emptyconfig%", "%scopetype%", "%inactivetype%", "%validtype%", "%emptyupdate%", "%emptyconfig%", "%scopetype%",

View file

@ -36,25 +36,25 @@ var testServer *http.Server = nil
// SystemModels system models for testing // SystemModels system models for testing
var testSystemModels = map[string]string{ var testSystemModels = map[string]string{
"__yao.assistant": "yao/models/assistant.mod.yao", "__yao.agent.assistant": "yao/models/agent/assistant.mod.yao",
"__yao.agent.chat": "yao/models/agent/chat.mod.yao",
"__yao.agent.history": "yao/models/agent/history.mod.yao",
"__yao.attachment": "yao/models/attachment.mod.yao", "__yao.attachment": "yao/models/attachment.mod.yao",
"__yao.audit": "yao/models/audit.mod.yao", "__yao.audit": "yao/models/audit.mod.yao",
"__yao.chat": "yao/models/chat.mod.yao",
"__yao.config": "yao/models/config.mod.yao", "__yao.config": "yao/models/config.mod.yao",
"__yao.dsl": "yao/models/dsl.mod.yao", "__yao.dsl": "yao/models/dsl.mod.yao",
"__yao.history": "yao/models/history.mod.yao",
"__yao.job.category": "yao/models/job/category.mod.yao", "__yao.job.category": "yao/models/job/category.mod.yao",
"__yao.job": "yao/models/job/job.mod.yao", "__yao.job": "yao/models/job/job.mod.yao",
"__yao.job.execution": "yao/models/job/execution.mod.yao", "__yao.job.execution": "yao/models/job/execution.mod.yao",
"__yao.job.log": "yao/models/job/log.mod.yao", "__yao.job.log": "yao/models/job/log.mod.yao",
"__yao.kb.collection": "yao/models/kb/collection.mod.yao", "__yao.kb.collection": "yao/models/kb/collection.mod.yao",
"__yao.kb.document": "yao/models/kb/document.mod.yao", "__yao.kb.document": "yao/models/kb/document.mod.yao",
"__yao.organization": "yao/models/organization.mod.yao", "__yao.team": "yao/models/team.mod.yao",
"__yao.organization_user": "yao/models/organization_user.mod.yao", "__yao.member": "yao/models/member.mod.yao",
"__yao.user": "yao/models/user.mod.yao", "__yao.user": "yao/models/user.mod.yao",
"__yao.user_role": "yao/models/user_role.mod.yao", "__yao.role": "yao/models/role.mod.yao",
"__yao.user_type": "yao/models/user_type.mod.yao", "__yao.user.type": "yao/models/user/type.mod.yao",
"__yao.user_oauth_account": "yao/models/user_oauth_account.mod.yao", "__yao.user.oauth_account": "yao/models/user/oauth_account.mod.yao",
} }
var testSystemStores = map[string]string{ var testSystemStores = map[string]string{

View file

@ -1,14 +1,14 @@
{ {
"name": "assistant", "name": "Assistant",
"label": "Assistant", "label": "Assistant",
"description": "Assistant table for storing AI assistant configurations and metadata", "description": "Assistant table for storing AI assistant configurations and metadata",
"tags": ["system"], "tags": ["agent", "system"],
"builtin": true, "builtin": true,
"readonly": true, "readonly": true,
"sort": 9999, "sort": 9999,
"table": { "table": {
"name": "assistant", "name": "agent_assistant",
"comment": "Assistant table" "comment": "Agent assistant table"
}, },
"columns": [ "columns": [
{ {
@ -181,7 +181,27 @@
"index": true "index": true
} }
], ],
"relations": {}, "relations": {
"indexes": [], "chats": {
"type": "hasMany",
"model": "__yao.agent.chat",
"key": "assistant_id",
"foreign": "assistant_id"
}
},
"indexes": [
{
"name": "idx_agent_assistant_type_builtin",
"columns": ["type", "built_in"],
"type": "index",
"comment": "Index for assistant type and built-in status"
},
{
"name": "idx_agent_assistant_sort",
"columns": ["sort", "automated"],
"type": "index",
"comment": "Index for assistant sorting and automation"
}
],
"option": { "timestamps": true, "soft_deletes": false } "option": { "timestamps": true, "soft_deletes": false }
} }

View file

@ -1,14 +1,14 @@
{ {
"name": "chat", "name": "Chat",
"label": "Chat", "label": "Chat",
"description": "Chat table for storing chat metadata and information", "description": "Chat table for storing chat metadata and information",
"tags": ["system"], "tags": ["agent", "system"],
"builtin": true, "builtin": true,
"readonly": true, "readonly": true,
"sort": 9999, "sort": 9999,
"table": { "table": {
"name": "chat", "name": "agent_chat",
"comment": "Chat table" "comment": "Agent chat table"
}, },
"columns": [ "columns": [
{ {
@ -62,7 +62,33 @@
"index": true "index": true
} }
], ],
"relations": {}, "relations": {
"indexes": [], "assistant": {
"type": "hasOne",
"model": "__yao.agent.assistant",
"key": "assistant_id",
"foreign": "assistant_id"
},
"history": {
"type": "hasMany",
"model": "__yao.agent.history",
"key": "chat_id",
"foreign": "cid"
}
},
"indexes": [
{
"name": "idx_agent_chat_session_assistant",
"columns": ["sid", "assistant_id"],
"type": "index",
"comment": "Index for session and assistant queries"
},
{
"name": "idx_agent_chat_silent",
"columns": ["silent", "created_at"],
"type": "index",
"comment": "Index for silent mode filtering"
}
],
"option": { "timestamps": true, "soft_deletes": false } "option": { "timestamps": true, "soft_deletes": false }
} }

View file

@ -1,14 +1,14 @@
{ {
"name": "history", "name": "History",
"label": "Chat History", "label": "Chat History",
"description": "Chat history table for storing detailed chat message information", "description": "Chat history table for storing detailed chat message information",
"tags": ["system"], "tags": ["agent", "system"],
"builtin": true, "builtin": true,
"readonly": true, "readonly": true,
"sort": 9999, "sort": 9999,
"table": { "table": {
"name": "history", "name": "agent_history",
"comment": "Chat history table" "comment": "Agent chat history table"
}, },
"columns": [ "columns": [
{ {
@ -124,7 +124,51 @@
"index": true "index": true
} }
], ],
"relations": {}, "relations": {
"indexes": [], "chat": {
"type": "hasOne",
"model": "__yao.agent.chat",
"key": "cid",
"foreign": "chat_id"
},
"assistant": {
"type": "hasOne",
"model": "__yao.agent.assistant",
"key": "assistant_id",
"foreign": "assistant_id"
},
"user": {
"type": "hasOne",
"model": "__yao.user",
"key": "uid",
"foreign": "user_id"
}
},
"indexes": [
{
"name": "idx_agent_history_session_chat",
"columns": ["sid", "cid"],
"type": "index",
"comment": "Index for session and chat queries"
},
{
"name": "idx_agent_history_user_role",
"columns": ["uid", "role"],
"type": "index",
"comment": "Index for user and role queries"
},
{
"name": "idx_agent_history_assistant",
"columns": ["assistant_id", "created_at"],
"type": "index",
"comment": "Index for assistant history queries"
},
{
"name": "idx_agent_history_expired",
"columns": ["expired_at", "silent"],
"type": "index",
"comment": "Index for expiration and cleanup"
}
],
"option": { "timestamps": true, "soft_deletes": false } "option": { "timestamps": true, "soft_deletes": false }
} }

View file

@ -1,11 +1,11 @@
{ {
"name": "Organization User", "name": "Member",
"label": "Organization User", "label": "Member",
"description": "Association table for organization members and their roles", "description": "Association table for team members and their roles",
"tags": ["organization", "user", "association", "membership", "roles"], "tags": ["team", "user", "association", "membership", "roles"],
"table": { "table": {
"name": "organization_user", "name": "member",
"comment": "Association table for organization members and their roles" "comment": "Association table for team members and their roles"
}, },
"columns": [ "columns": [
// ============================================================================ // ============================================================================
@ -19,10 +19,10 @@
"primary": true "primary": true
}, },
{ {
"name": "org_id", "name": "team_id",
"type": "string", "type": "string",
"label": "Organization ID", "label": "Team ID",
"comment": "Organization identifier (references organization.org_id)", "comment": "Team identifier (references team.team_id)",
"length": 255, "length": 255,
"nullable": false, "nullable": false,
"index": true "index": true
@ -41,18 +41,13 @@
// Role & Permission Fields // Role & Permission Fields
// ============================================================================ // ============================================================================
{ {
"name": "role", "name": "role_id",
"type": "enum", "type": "string",
"label": "Role", "label": "Role ID",
"comment": "User role within the organization", "comment": "User role within the team (references role.role_id)",
"option": [ "length": 50,
"owner", // Organization owner (full control, billing, delete org) "nullable": false,
"admin", // Administrator (manage users, settings, but not billing) "index": true
"member" // Regular member (basic access according to org permissions)
],
"default": "member",
"index": true,
"nullable": false
}, },
{ {
"name": "status", "name": "status",
@ -93,7 +88,7 @@
"name": "joined_at", "name": "joined_at",
"type": "timestamp", "type": "timestamp",
"label": "Joined At", "label": "Joined At",
"comment": "When the user accepted and joined the organization", "comment": "When the user accepted and joined the team",
"nullable": true, "nullable": true,
"index": true "index": true
}, },
@ -122,14 +117,14 @@
"name": "permissions", "name": "permissions",
"type": "json", "type": "json",
"label": "Permissions", "label": "Permissions",
"comment": "Custom permissions override for this user in this organization", "comment": "Custom permissions override for this user in this team",
"nullable": true "nullable": true
}, },
{ {
"name": "restrictions", "name": "restrictions",
"type": "json", "type": "json",
"label": "Restrictions", "label": "Restrictions",
"comment": "Additional restrictions for this user in this organization", "comment": "Additional restrictions for this user in this team",
"nullable": true "nullable": true
}, },
@ -140,7 +135,7 @@
"name": "last_active_at", "name": "last_active_at",
"type": "timestamp", "type": "timestamp",
"label": "Last Active At", "label": "Last Active At",
"comment": "When the user was last active in this organization", "comment": "When the user was last active in this team",
"nullable": true, "nullable": true,
"index": true "index": true
}, },
@ -148,7 +143,7 @@
"name": "login_count", "name": "login_count",
"type": "integer", "type": "integer",
"label": "Login Count", "label": "Login Count",
"comment": "Number of times user has accessed this organization", "comment": "Number of times user has accessed this team",
"default": 0, "default": 0,
"nullable": true "nullable": true
}, },
@ -173,26 +168,26 @@
], ],
"indexes": [ "indexes": [
{ {
"name": "idx_org_user_unique", "name": "idx_team_user_unique",
"columns": ["org_id", "user_id"], "columns": ["team_id", "user_id"],
"type": "unique", "type": "unique",
"comment": "Unique constraint: one user can have only one membership per organization" "comment": "Unique constraint: one user can have only one membership per team"
}, },
{ {
"name": "idx_org_user_role", "name": "idx_team_user_role",
"columns": ["org_id", "role", "status"], "columns": ["team_id", "role_id", "status"],
"type": "index", "type": "index",
"comment": "Index for finding users by role and status within organization" "comment": "Index for finding users by role and status within team"
}, },
{ {
"name": "idx_user_orgs", "name": "idx_user_teams",
"columns": ["user_id", "status", "role"], "columns": ["user_id", "status", "role_id"],
"type": "index", "type": "index",
"comment": "Index for finding all organizations for a user" "comment": "Index for finding all teams for a user"
}, },
{ {
"name": "idx_org_invitations", "name": "idx_team_invitations",
"columns": ["org_id", "status", "invited_at"], "columns": ["team_id", "status", "invited_at"],
"type": "index", "type": "index",
"comment": "Index for managing invitations" "comment": "Index for managing invitations"
}, },
@ -203,18 +198,18 @@
"comment": "Index for invitation token lookup and expiration" "comment": "Index for invitation token lookup and expiration"
}, },
{ {
"name": "idx_org_activity", "name": "idx_team_activity",
"columns": ["org_id", "last_active_at"], "columns": ["team_id", "last_active_at"],
"type": "index", "type": "index",
"comment": "Index for organization activity tracking" "comment": "Index for team activity tracking"
} }
], ],
"relations": { "relations": {
"organization": { "team": {
"type": "hasOne", "type": "hasOne",
"model": "__yao.organization", "model": "__yao.team",
"key": "org_id", "key": "team_id",
"foreign": "org_id" "foreign": "team_id"
}, },
"user": { "user": {
"type": "hasOne", "type": "hasOne",
@ -227,6 +222,12 @@
"model": "__yao.user", "model": "__yao.user",
"key": "invited_by", "key": "invited_by",
"foreign": "user_id" "foreign": "user_id"
},
"role": {
"type": "hasOne",
"model": "__yao.role",
"key": "role_id",
"foreign": "role_id"
} }
}, },
"values": [], "values": [],

View file

@ -1,11 +1,11 @@
{ {
"name": "User Role", "name": "Role",
"label": "User Role", "label": "Role",
"description": "User role and permission management", "description": "Role and permission management",
"tags": ["user", "role", "permission", "auth"], "tags": ["role", "permission", "auth", "rbac"],
"table": { "table": {
"name": "user_role", "name": "role",
"comment": "User role and permission management" "comment": "Role and permission management"
}, },
"columns": [ "columns": [
// ============================================================================ // ============================================================================
@ -187,31 +187,44 @@
], ],
"indexes": [ "indexes": [
{ {
"name": "idx_user_role_active", "name": "idx_role_active",
"columns": ["is_active", "sort_order"], "columns": ["is_active", "sort_order"],
"type": "index", "type": "index",
"comment": "Index for active roles with ordering" "comment": "Index for active roles with ordering"
}, },
{ {
"name": "idx_user_role_hierarchy", "name": "idx_role_hierarchy",
"columns": ["parent_role_id", "level"], "columns": ["parent_role_id", "level"],
"type": "index", "type": "index",
"comment": "Index for role hierarchy queries" "comment": "Index for role hierarchy queries"
}, },
{ {
"name": "idx_user_role_system", "name": "idx_role_system",
"columns": ["is_system", "is_active"], "columns": ["is_system", "is_active"],
"type": "index", "type": "index",
"comment": "Index for system role queries" "comment": "Index for system role queries"
}, },
{ {
"name": "idx_user_role_default", "name": "idx_role_default",
"columns": ["is_default", "is_active"], "columns": ["is_default", "is_active"],
"type": "index", "type": "index",
"comment": "Index for finding default active role" "comment": "Index for finding default active role"
} }
], ],
"relations": {}, "relations": {
"members": {
"type": "hasMany",
"model": "__yao.member",
"key": "role_id",
"foreign": "role_id"
},
"users": {
"type": "hasMany",
"model": "__yao.user",
"key": "role_id",
"foreign": "role_id"
}
},
"values": [], "values": [],
"option": { "timestamps": true, "soft_deletes": true, "permission": true } "option": { "timestamps": true, "soft_deletes": true, "permission": true }
} }

View file

@ -1,11 +1,11 @@
{ {
"name": "Organization", "name": "Team",
"label": "Organization", "label": "Team",
"description": "Organization structure and information storage", "description": "Team structure and information storage",
"tags": ["organization", "structure", "business", "verification"], "tags": ["team", "structure", "business", "verification"],
"table": { "table": {
"name": "organization", "name": "team",
"comment": "Organization structure and information storage" "comment": "Team structure and information storage"
}, },
"columns": [ "columns": [
// ============================================================================ // ============================================================================
@ -19,23 +19,23 @@
"primary": true "primary": true
}, },
{ {
"name": "org_id", "name": "team_id",
"type": "string", "type": "string",
"label": "Organization ID", "label": "Team ID",
"comment": "Global unique organization identifier", "comment": "Global unique team identifier",
"length": 255, "length": 255,
"unique": true, "unique": true,
"index": true "index": true
}, },
// ============================================================================ // ============================================================================
// Organization Basic Information // Team Basic Information
// ============================================================================ // ============================================================================
{ {
"name": "name", "name": "name",
"type": "string", "type": "string",
"label": "Organization Name", "label": "Team Name",
"comment": "Official organization name", "comment": "Official team name",
"length": 200, "length": 200,
"nullable": false "nullable": false
}, },
@ -43,7 +43,7 @@
"name": "display_name", "name": "display_name",
"type": "string", "type": "string",
"label": "Display Name", "label": "Display Name",
"comment": "Organization display name or brand name", "comment": "Team display name or brand name",
"length": 200, "length": 200,
"nullable": true "nullable": true
}, },
@ -51,14 +51,14 @@
"name": "description", "name": "description",
"type": "text", "type": "text",
"label": "Description", "label": "Description",
"comment": "Organization description", "comment": "Team description",
"nullable": true "nullable": true
}, },
{ {
"name": "website", "name": "website",
"type": "string", "type": "string",
"label": "Website", "label": "Website",
"comment": "Organization website URL", "comment": "Team website URL",
"length": 500, "length": 500,
"nullable": true "nullable": true
}, },
@ -66,19 +66,19 @@
"name": "logo", "name": "logo",
"type": "string", "type": "string",
"label": "Logo", "label": "Logo",
"comment": "Organization logo URL", "comment": "Team logo URL",
"length": 500, "length": 500,
"nullable": true "nullable": true
}, },
// ============================================================================ // ============================================================================
// Organization Ownership // Team Ownership
// ============================================================================ // ============================================================================
{ {
"name": "owner_id", "name": "owner_id",
"type": "string", "type": "string",
"label": "Owner ID", "label": "Owner ID",
"comment": "Organization owner user identifier (references user.user_id)", "comment": "Team owner user identifier (references user.user_id)",
"length": 255, "length": 255,
"nullable": false, "nullable": false,
"index": true "index": true
@ -91,7 +91,7 @@
"name": "contact_email", "name": "contact_email",
"type": "string", "type": "string",
"label": "Contact Email", "label": "Contact Email",
"comment": "Organization contact email address", "comment": "Team contact email address",
"length": 255, "length": 255,
"nullable": true, "nullable": true,
"index": true "index": true
@ -100,20 +100,20 @@
"name": "contact_phone", "name": "contact_phone",
"type": "string", "type": "string",
"label": "Contact Phone", "label": "Contact Phone",
"comment": "Organization contact phone number", "comment": "Team contact phone number",
"length": 50, "length": 50,
"nullable": true, "nullable": true,
"index": true "index": true
}, },
// ============================================================================ // ============================================================================
// Organization Verification // Team Verification
// ============================================================================ // ============================================================================
{ {
"name": "is_verified", "name": "is_verified",
"type": "boolean", "type": "boolean",
"label": "Is Verified", "label": "Is Verified",
"comment": "Whether organization is verified", "comment": "Whether team is verified",
"default": false, "default": false,
"index": true "index": true
}, },
@ -121,7 +121,7 @@
"name": "verified_at", "name": "verified_at",
"type": "timestamp", "type": "timestamp",
"label": "Verified At", "label": "Verified At",
"comment": "When organization was verified", "comment": "When team was verified",
"nullable": true, "nullable": true,
"index": true "index": true
}, },
@ -129,29 +129,29 @@
"name": "verified_by", "name": "verified_by",
"type": "string", "type": "string",
"label": "Verified By", "label": "Verified By",
"comment": "Who verified this organization", "comment": "Who verified this team",
"length": 255, "length": 255,
"nullable": true "nullable": true
}, },
// ============================================================================ // ============================================================================
// Organization Unique Code & Type // Team Unique Code & Type
// ============================================================================ // ============================================================================
{ {
"name": "org_code", "name": "team_code",
"type": "string", "type": "string",
"label": "Organization Code", "label": "Team Code",
"comment": "Unique organization identification code", "comment": "Unique team identification code",
"length": 100, "length": 100,
"nullable": true, "nullable": true,
"unique": true, "unique": true,
"index": true "index": true
}, },
{ {
"name": "org_code_type", "name": "team_code_type",
"type": "enum", "type": "enum",
"label": "Organization Code Type", "label": "Team Code Type",
"comment": "Type of organization identification code", "comment": "Type of team identification code",
"option": [ "option": [
// ============================================================================ // ============================================================================
// Global Universal Standards (Apple & International Compatible) // Global Universal Standards (Apple & International Compatible)
@ -252,19 +252,19 @@
}, },
// ============================================================================ // ============================================================================
// Organization Status & Management // Team Status & Management
// ============================================================================ // ============================================================================
{ {
"name": "status", "name": "status",
"type": "enum", "type": "enum",
"label": "Status", "label": "Status",
"comment": "Organization status", "comment": "Team status",
"option": [ "option": [
"pending", // New organization awaiting verification "pending", // New team awaiting verification
"active", // Active organization with full access "active", // Active team with full access
"inactive", // Temporarily inactive "inactive", // Temporarily inactive
"suspended", // Suspended due to policy violations "suspended", // Suspended due to policy violations
"archived" // Archived organization "archived" // Archived team
], ],
"default": "pending", "default": "pending",
"index": true, "index": true,
@ -274,7 +274,7 @@
"name": "type_id", "name": "type_id",
"type": "string", "type": "string",
"label": "Type ID", "label": "Type ID",
"comment": "Organization type identifier for limits and permissions (references user_type.type_id)", "comment": "Team type identifier for limits and permissions (references user.type.type_id)",
"length": 50, "length": 50,
"nullable": true, "nullable": true,
"index": true "index": true
@ -282,8 +282,8 @@
{ {
"name": "type", "name": "type",
"type": "enum", "type": "enum",
"label": "Organization Type", "label": "Team Type",
"comment": "Type of organization", "comment": "Type of team",
"option": [ "option": [
"corporation", "corporation",
"llc", "llc",
@ -305,7 +305,7 @@
"name": "address", "name": "address",
"type": "json", "type": "json",
"label": "Address", "label": "Address",
"comment": "Organization physical address (structured JSON with full details)", "comment": "Team physical address (structured JSON with full details)",
"nullable": true "nullable": true
}, },
{ {
@ -320,7 +320,7 @@
"name": "city", "name": "city",
"type": "string", "type": "string",
"label": "City", "label": "City",
"comment": "Organization city", "comment": "Team city",
"length": 100, "length": 100,
"nullable": true, "nullable": true,
"index": true "index": true
@ -347,7 +347,7 @@
"name": "country", "name": "country",
"type": "string", "type": "string",
"label": "Country", "label": "Country",
"comment": "Organization country (ISO 3166-1 alpha-2)", "comment": "Team country (ISO 3166-1 alpha-2)",
"length": 2, "length": 2,
"nullable": true, "nullable": true,
"index": true "index": true
@ -373,72 +373,72 @@
"name": "zoneinfo", "name": "zoneinfo",
"type": "string", "type": "string",
"label": "Zone Info", "label": "Zone Info",
"comment": "Organization primary timezone (IANA Time Zone Database format)", "comment": "Team primary timezone (IANA Time Zone Database format)",
"length": 50, "length": 50,
"nullable": true, "nullable": true,
"index": true "index": true
}, },
// ============================================================================ // ============================================================================
// Organization Settings // Team Settings
// ============================================================================ // ============================================================================
{ {
"name": "settings", "name": "settings",
"type": "json", "type": "json",
"label": "Settings", "label": "Settings",
"comment": "Organization configuration settings", "comment": "Team configuration settings",
"nullable": true "nullable": true
}, },
{ {
"name": "metadata", "name": "metadata",
"type": "json", "type": "json",
"label": "Metadata", "label": "Metadata",
"comment": "Extended organization metadata and custom fields", "comment": "Extended team metadata and custom fields",
"nullable": true "nullable": true
} }
], ],
"indexes": [ "indexes": [
{ {
"name": "idx_org_owner_status", "name": "idx_team_owner_status",
"columns": ["owner_id", "status"], "columns": ["owner_id", "status"],
"type": "index", "type": "index",
"comment": "Index on owner and status for filtering" "comment": "Index on owner and status for filtering"
}, },
{ {
"name": "idx_org_verification", "name": "idx_team_verification",
"columns": ["is_verified", "verified_at"], "columns": ["is_verified", "verified_at"],
"type": "index", "type": "index",
"comment": "Index on verification status and time" "comment": "Index on verification status and time"
}, },
{ {
"name": "idx_org_code_type", "name": "idx_team_code_type",
"columns": ["org_code_type", "org_code"], "columns": ["team_code_type", "team_code"],
"type": "index", "type": "index",
"comment": "Index on organization code type and code" "comment": "Index on team code type and code"
}, },
{ {
"name": "idx_org_location", "name": "idx_team_location",
"columns": ["country", "state_province", "city"], "columns": ["country", "state_province", "city"],
"type": "index", "type": "index",
"comment": "Index on country, state/province and city for geographic queries" "comment": "Index on country, state/province and city for geographic queries"
}, },
{ {
"name": "idx_org_region_type", "name": "idx_team_region_type",
"columns": ["region", "type"], "columns": ["region", "type"],
"type": "index", "type": "index",
"comment": "Index on geographic region and organization type" "comment": "Index on geographic region and team type"
}, },
{ {
"name": "idx_org_postal_zoneinfo", "name": "idx_team_postal_zoneinfo",
"columns": ["postal_code", "zoneinfo"], "columns": ["postal_code", "zoneinfo"],
"type": "index", "type": "index",
"comment": "Index on postal code and zoneinfo for location services" "comment": "Index on postal code and zoneinfo for location services"
}, },
{ {
"name": "idx_org_type_status", "name": "idx_team_type_status",
"columns": ["type_id", "status"], "columns": ["type_id", "status"],
"type": "index", "type": "index",
"comment": "Index on organization type and status for limits and permissions" "comment": "Index on team type and status for limits and permissions"
} }
], ],
"relations": { "relations": {
@ -450,22 +450,22 @@
}, },
"user_type": { "user_type": {
"type": "hasOne", "type": "hasOne",
"model": "__yao.user_type", "model": "__yao.user.type",
"key": "type_id", "key": "type_id",
"foreign": "type_id" "foreign": "type_id"
}, },
"members": { "members": {
"type": "hasMany", "type": "hasMany",
"model": "__yao.organization_user", "model": "__yao.member",
"key": "org_id", "key": "team_id",
"foreign": "org_id" "foreign": "team_id"
}, },
"users": { "users": {
"type": "hasManyThrough", "type": "hasManyThrough",
"model": "__yao.user", "model": "__yao.user",
"through": "__yao.organization_user", "through": "__yao.member",
"key": "org_id", "key": "team_id",
"foreign": "org_id", "foreign": "team_id",
"throughKey": "user_id", "throughKey": "user_id",
"throughForeign": "user_id" "throughForeign": "user_id"
} }

View file

@ -243,7 +243,7 @@
"name": "role_id", "name": "role_id",
"type": "string", "type": "string",
"label": "Role ID", "label": "Role ID",
"comment": "User role identifier (references user_role.role_id)", "comment": "User role identifier (references role.role_id)",
"length": 50, "length": 50,
"nullable": true, "nullable": true,
"index": true "index": true
@ -252,7 +252,7 @@
"name": "type_id", "name": "type_id",
"type": "string", "type": "string",
"label": "Type ID", "label": "Type ID",
"comment": "User type identifier (references user_type.type_id)", "comment": "User type identifier (references user.type.type_id)",
"length": 50, "length": 50,
"nullable": true, "nullable": true,
"index": true "index": true
@ -387,36 +387,42 @@
"relations": { "relations": {
"role": { "role": {
"type": "hasOne", "type": "hasOne",
"model": "__yao.user_role", "model": "__yao.role",
"key": "role_id", "key": "role_id",
"foreign": "role_id" "foreign": "role_id"
}, },
"type": { "type": {
"type": "hasOne", "type": "hasOne",
"model": "__yao.user_type", "model": "__yao.user.type",
"key": "type_id", "key": "type_id",
"foreign": "type_id" "foreign": "type_id"
}, },
"owned_organizations": { "oauth_accounts": {
"type": "hasMany", "type": "hasMany",
"model": "__yao.organization", "model": "__yao.user.oauth_account",
"key": "user_id",
"foreign": "owner_id"
},
"organization_memberships": {
"type": "hasMany",
"model": "__yao.organization_user",
"key": "user_id", "key": "user_id",
"foreign": "user_id" "foreign": "user_id"
}, },
"organizations": { "owned_teams": {
"type": "hasMany",
"model": "__yao.team",
"key": "user_id",
"foreign": "owner_id"
},
"team_memberships": {
"type": "hasMany",
"model": "__yao.member",
"key": "user_id",
"foreign": "user_id"
},
"teams": {
"type": "hasManyThrough", "type": "hasManyThrough",
"model": "__yao.organization", "model": "__yao.team",
"through": "__yao.organization_user", "through": "__yao.member",
"key": "user_id", "key": "user_id",
"foreign": "user_id", "foreign": "user_id",
"throughKey": "org_id", "throughKey": "team_id",
"throughForeign": "org_id" "throughForeign": "team_id"
} }
}, },
"values": [], "values": [],

View file

@ -1,6 +1,6 @@
{ {
"name": "User OAuth Account", "name": "OAuth Account",
"label": "User OAuth Account", "label": "OAuth Account",
"description": "User's third-party OAuth account information storage", "description": "User's third-party OAuth account information storage",
"tags": ["user", "oauth", "social", "external", "provider"], "tags": ["user", "oauth", "social", "external", "provider"],
"table": { "table": {
@ -225,31 +225,38 @@
], ],
"indexes": [ "indexes": [
{ {
"name": "idx_user_oauth_user_provider", "name": "idx_oauth_account_user_provider",
"columns": ["user_id", "provider"], "columns": ["user_id", "provider"],
"type": "unique", "type": "unique",
"comment": "Unique constraint: one account per provider per user" "comment": "Unique constraint: one account per provider per user"
}, },
{ {
"name": "idx_user_oauth_provider_sub", "name": "idx_oauth_account_provider_sub",
"columns": ["provider", "sub"], "columns": ["provider", "sub"],
"type": "unique", "type": "unique",
"comment": "Unique constraint: one record per provider sub claim" "comment": "Unique constraint: one record per provider sub claim"
}, },
{ {
"name": "idx_user_oauth_email", "name": "idx_oauth_account_email",
"columns": ["provider", "email"], "columns": ["provider", "email"],
"type": "index", "type": "index",
"comment": "Index for email lookups by provider" "comment": "Index for email lookups by provider"
}, },
{ {
"name": "idx_user_oauth_active", "name": "idx_oauth_account_active",
"columns": ["is_active", "last_login_at"], "columns": ["is_active", "last_login_at"],
"type": "index", "type": "index",
"comment": "Index for active account queries" "comment": "Index for active account queries"
} }
], ],
"relations": {}, "relations": {
"user": {
"type": "hasOne",
"model": "__yao.user",
"key": "user_id",
"foreign": "user_id"
}
},
"values": [], "values": [],
"option": { "timestamps": true, "soft_deletes": true, "permission": true } "option": { "timestamps": true, "soft_deletes": true, "permission": true }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "User Type", "name": "Type",
"label": "User Type", "label": "Type",
"description": "User type classification and configuration", "description": "User type classification and configuration",
"tags": ["user", "type", "classification", "config"], "tags": ["user", "type", "classification", "config"],
"table": { "table": {
@ -51,7 +51,7 @@
"name": "default_role_id", "name": "default_role_id",
"type": "string", "type": "string",
"label": "Default Role ID", "label": "Default Role ID",
"comment": "Default role assigned to users of this type", "comment": "Default role assigned to users of this type (references role.role_id)",
"length": 50, "length": 50,
"nullable": true, "nullable": true,
"index": true "index": true
@ -145,19 +145,32 @@
], ],
"indexes": [ "indexes": [
{ {
"name": "idx_user_type_active", "name": "idx_type_active",
"columns": ["is_active", "sort_order"], "columns": ["is_active", "sort_order"],
"type": "index", "type": "index",
"comment": "Index for active user types with ordering" "comment": "Index for active user types with ordering"
}, },
{ {
"name": "idx_user_type_default", "name": "idx_type_default",
"columns": ["is_default", "is_active"], "columns": ["is_default", "is_active"],
"type": "index", "type": "index",
"comment": "Index for finding default active user type" "comment": "Index for finding default active user type"
} }
], ],
"relations": {}, "relations": {
"default_role": {
"type": "hasOne",
"model": "__yao.role",
"key": "default_role_id",
"foreign": "role_id"
},
"users": {
"type": "hasMany",
"model": "__yao.user",
"key": "type_id",
"foreign": "type_id"
}
},
"values": [], "values": [],
"option": { "timestamps": true, "soft_deletes": true, "permission": true } "option": { "timestamps": true, "soft_deletes": true, "permission": true }
} }