Merge pull request #1144 from trheyi/main
Refactor user and model structures to enhance organization and role m…
This commit is contained in:
commit
c145a14606
14 changed files with 602 additions and 468 deletions
562
data/bindata.go
562
data/bindata.go
File diff suppressed because one or more lines are too long
|
|
@ -20,25 +20,25 @@ import (
|
|||
|
||||
// SystemModels system models
|
||||
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.audit": "yao/models/audit.mod.yao",
|
||||
"__yao.chat": "yao/models/chat.mod.yao",
|
||||
"__yao.config": "yao/models/config.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": "yao/models/job/job.mod.yao",
|
||||
"__yao.job.execution": "yao/models/job/execution.mod.yao",
|
||||
"__yao.job.log": "yao/models/job/log.mod.yao",
|
||||
"__yao.kb.collection": "yao/models/kb/collection.mod.yao",
|
||||
"__yao.kb.document": "yao/models/kb/document.mod.yao",
|
||||
"__yao.organization": "yao/models/organization.mod.yao",
|
||||
"__yao.organization_user": "yao/models/organization_user.mod.yao",
|
||||
"__yao.team": "yao/models/team.mod.yao",
|
||||
"__yao.member": "yao/models/member.mod.yao",
|
||||
"__yao.user": "yao/models/user.mod.yao",
|
||||
"__yao.user_role": "yao/models/user_role.mod.yao",
|
||||
"__yao.user_type": "yao/models/user_type.mod.yao",
|
||||
"__yao.user_oauth_account": "yao/models/user_oauth_account.mod.yao",
|
||||
"__yao.role": "yao/models/role.mod.yao",
|
||||
"__yao.user.type": "yao/models/user/type.mod.yao",
|
||||
"__yao.user.oauth_account": "yao/models/user/oauth_account.mod.yao",
|
||||
}
|
||||
|
||||
// Load load models
|
||||
|
|
|
|||
|
|
@ -217,17 +217,17 @@ func NewDefaultUser(options *DefaultUserOptions) *DefaultUser {
|
|||
|
||||
roleModel := options.RoleModel
|
||||
if roleModel == "" {
|
||||
roleModel = "__yao.user_role"
|
||||
roleModel = "__yao.role"
|
||||
}
|
||||
|
||||
typeModel := options.TypeModel
|
||||
if typeModel == "" {
|
||||
typeModel = "__yao.user_type"
|
||||
typeModel = "__yao.user.type"
|
||||
}
|
||||
|
||||
oauthAccountModel := options.OAuthAccountModel
|
||||
if oauthAccountModel == "" {
|
||||
oauthAccountModel = "__yao.user_oauth_account"
|
||||
oauthAccountModel = "__yao.user.oauth_account"
|
||||
}
|
||||
|
||||
// Set ID generation strategy with defaults
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func cleanupTestData() {
|
|||
|
||||
// Use DestroyWhere (hard delete) to avoid soft delete complications
|
||||
// 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{
|
||||
"%oauth_test%", "%_list_%", "%oauthlist%", "%oautherror%",
|
||||
"%google_%", "%github_%", "%apple_%", "%_delete_%",
|
||||
|
|
@ -113,7 +113,7 @@ func cleanupTestData() {
|
|||
}
|
||||
|
||||
// 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{
|
||||
"test%", "%testrole%", "%listrole%", "%permrole%", "%adminrole%", "%userrole%",
|
||||
"%inactiverole%", "%systemrole%", "%validrole%", "%emptyupdate%", "%emptyperm%",
|
||||
|
|
@ -128,7 +128,7 @@ func cleanupTestData() {
|
|||
}
|
||||
|
||||
// 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{
|
||||
"test%", "%testtype%", "%listtype%", "%configtype%", "%basictype%", "%premiumtype%",
|
||||
"%inactivetype%", "%validtype%", "%emptyupdate%", "%emptyconfig%", "%scopetype%",
|
||||
|
|
|
|||
|
|
@ -36,25 +36,25 @@ var testServer *http.Server = nil
|
|||
|
||||
// SystemModels system models for testing
|
||||
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.audit": "yao/models/audit.mod.yao",
|
||||
"__yao.chat": "yao/models/chat.mod.yao",
|
||||
"__yao.config": "yao/models/config.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": "yao/models/job/job.mod.yao",
|
||||
"__yao.job.execution": "yao/models/job/execution.mod.yao",
|
||||
"__yao.job.log": "yao/models/job/log.mod.yao",
|
||||
"__yao.kb.collection": "yao/models/kb/collection.mod.yao",
|
||||
"__yao.kb.document": "yao/models/kb/document.mod.yao",
|
||||
"__yao.organization": "yao/models/organization.mod.yao",
|
||||
"__yao.organization_user": "yao/models/organization_user.mod.yao",
|
||||
"__yao.team": "yao/models/team.mod.yao",
|
||||
"__yao.member": "yao/models/member.mod.yao",
|
||||
"__yao.user": "yao/models/user.mod.yao",
|
||||
"__yao.user_role": "yao/models/user_role.mod.yao",
|
||||
"__yao.user_type": "yao/models/user_type.mod.yao",
|
||||
"__yao.user_oauth_account": "yao/models/user_oauth_account.mod.yao",
|
||||
"__yao.role": "yao/models/role.mod.yao",
|
||||
"__yao.user.type": "yao/models/user/type.mod.yao",
|
||||
"__yao.user.oauth_account": "yao/models/user/oauth_account.mod.yao",
|
||||
}
|
||||
|
||||
var testSystemStores = map[string]string{
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "assistant",
|
||||
"name": "Assistant",
|
||||
"label": "Assistant",
|
||||
"description": "Assistant table for storing AI assistant configurations and metadata",
|
||||
"tags": ["system"],
|
||||
"tags": ["agent", "system"],
|
||||
"builtin": true,
|
||||
"readonly": true,
|
||||
"sort": 9999,
|
||||
"table": {
|
||||
"name": "assistant",
|
||||
"comment": "Assistant table"
|
||||
"name": "agent_assistant",
|
||||
"comment": "Agent assistant table"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -181,7 +181,27 @@
|
|||
"index": true
|
||||
}
|
||||
],
|
||||
"relations": {},
|
||||
"indexes": [],
|
||||
"relations": {
|
||||
"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 }
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "chat",
|
||||
"name": "Chat",
|
||||
"label": "Chat",
|
||||
"description": "Chat table for storing chat metadata and information",
|
||||
"tags": ["system"],
|
||||
"tags": ["agent", "system"],
|
||||
"builtin": true,
|
||||
"readonly": true,
|
||||
"sort": 9999,
|
||||
"table": {
|
||||
"name": "chat",
|
||||
"comment": "Chat table"
|
||||
"name": "agent_chat",
|
||||
"comment": "Agent chat table"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -62,7 +62,33 @@
|
|||
"index": true
|
||||
}
|
||||
],
|
||||
"relations": {},
|
||||
"indexes": [],
|
||||
"relations": {
|
||||
"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 }
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "history",
|
||||
"name": "History",
|
||||
"label": "Chat History",
|
||||
"description": "Chat history table for storing detailed chat message information",
|
||||
"tags": ["system"],
|
||||
"tags": ["agent", "system"],
|
||||
"builtin": true,
|
||||
"readonly": true,
|
||||
"sort": 9999,
|
||||
"table": {
|
||||
"name": "history",
|
||||
"comment": "Chat history table"
|
||||
"name": "agent_history",
|
||||
"comment": "Agent chat history table"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -124,7 +124,51 @@
|
|||
"index": true
|
||||
}
|
||||
],
|
||||
"relations": {},
|
||||
"indexes": [],
|
||||
"relations": {
|
||||
"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 }
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "Organization User",
|
||||
"label": "Organization User",
|
||||
"description": "Association table for organization members and their roles",
|
||||
"tags": ["organization", "user", "association", "membership", "roles"],
|
||||
"name": "Member",
|
||||
"label": "Member",
|
||||
"description": "Association table for team members and their roles",
|
||||
"tags": ["team", "user", "association", "membership", "roles"],
|
||||
"table": {
|
||||
"name": "organization_user",
|
||||
"comment": "Association table for organization members and their roles"
|
||||
"name": "member",
|
||||
"comment": "Association table for team members and their roles"
|
||||
},
|
||||
"columns": [
|
||||
// ============================================================================
|
||||
|
|
@ -19,10 +19,10 @@
|
|||
"primary": true
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"name": "team_id",
|
||||
"type": "string",
|
||||
"label": "Organization ID",
|
||||
"comment": "Organization identifier (references organization.org_id)",
|
||||
"label": "Team ID",
|
||||
"comment": "Team identifier (references team.team_id)",
|
||||
"length": 255,
|
||||
"nullable": false,
|
||||
"index": true
|
||||
|
|
@ -41,18 +41,13 @@
|
|||
// Role & Permission Fields
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "role",
|
||||
"type": "enum",
|
||||
"label": "Role",
|
||||
"comment": "User role within the organization",
|
||||
"option": [
|
||||
"owner", // Organization owner (full control, billing, delete org)
|
||||
"admin", // Administrator (manage users, settings, but not billing)
|
||||
"member" // Regular member (basic access according to org permissions)
|
||||
],
|
||||
"default": "member",
|
||||
"index": true,
|
||||
"nullable": false
|
||||
"name": "role_id",
|
||||
"type": "string",
|
||||
"label": "Role ID",
|
||||
"comment": "User role within the team (references role.role_id)",
|
||||
"length": 50,
|
||||
"nullable": false,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
|
|
@ -93,7 +88,7 @@
|
|||
"name": "joined_at",
|
||||
"type": "timestamp",
|
||||
"label": "Joined At",
|
||||
"comment": "When the user accepted and joined the organization",
|
||||
"comment": "When the user accepted and joined the team",
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
|
|
@ -122,14 +117,14 @@
|
|||
"name": "permissions",
|
||||
"type": "json",
|
||||
"label": "Permissions",
|
||||
"comment": "Custom permissions override for this user in this organization",
|
||||
"comment": "Custom permissions override for this user in this team",
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
"name": "restrictions",
|
||||
"type": "json",
|
||||
"label": "Restrictions",
|
||||
"comment": "Additional restrictions for this user in this organization",
|
||||
"comment": "Additional restrictions for this user in this team",
|
||||
"nullable": true
|
||||
},
|
||||
|
||||
|
|
@ -140,7 +135,7 @@
|
|||
"name": "last_active_at",
|
||||
"type": "timestamp",
|
||||
"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,
|
||||
"index": true
|
||||
},
|
||||
|
|
@ -148,7 +143,7 @@
|
|||
"name": "login_count",
|
||||
"type": "integer",
|
||||
"label": "Login Count",
|
||||
"comment": "Number of times user has accessed this organization",
|
||||
"comment": "Number of times user has accessed this team",
|
||||
"default": 0,
|
||||
"nullable": true
|
||||
},
|
||||
|
|
@ -173,26 +168,26 @@
|
|||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_org_user_unique",
|
||||
"columns": ["org_id", "user_id"],
|
||||
"name": "idx_team_user_unique",
|
||||
"columns": ["team_id", "user_id"],
|
||||
"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",
|
||||
"columns": ["org_id", "role", "status"],
|
||||
"name": "idx_team_user_role",
|
||||
"columns": ["team_id", "role_id", "status"],
|
||||
"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",
|
||||
"columns": ["user_id", "status", "role"],
|
||||
"name": "idx_user_teams",
|
||||
"columns": ["user_id", "status", "role_id"],
|
||||
"type": "index",
|
||||
"comment": "Index for finding all organizations for a user"
|
||||
"comment": "Index for finding all teams for a user"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_invitations",
|
||||
"columns": ["org_id", "status", "invited_at"],
|
||||
"name": "idx_team_invitations",
|
||||
"columns": ["team_id", "status", "invited_at"],
|
||||
"type": "index",
|
||||
"comment": "Index for managing invitations"
|
||||
},
|
||||
|
|
@ -203,18 +198,18 @@
|
|||
"comment": "Index for invitation token lookup and expiration"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_activity",
|
||||
"columns": ["org_id", "last_active_at"],
|
||||
"name": "idx_team_activity",
|
||||
"columns": ["team_id", "last_active_at"],
|
||||
"type": "index",
|
||||
"comment": "Index for organization activity tracking"
|
||||
"comment": "Index for team activity tracking"
|
||||
}
|
||||
],
|
||||
"relations": {
|
||||
"organization": {
|
||||
"team": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.organization",
|
||||
"key": "org_id",
|
||||
"foreign": "org_id"
|
||||
"model": "__yao.team",
|
||||
"key": "team_id",
|
||||
"foreign": "team_id"
|
||||
},
|
||||
"user": {
|
||||
"type": "hasOne",
|
||||
|
|
@ -227,6 +222,12 @@
|
|||
"model": "__yao.user",
|
||||
"key": "invited_by",
|
||||
"foreign": "user_id"
|
||||
},
|
||||
"role": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.role",
|
||||
"key": "role_id",
|
||||
"foreign": "role_id"
|
||||
}
|
||||
},
|
||||
"values": [],
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "User Role",
|
||||
"label": "User Role",
|
||||
"description": "User role and permission management",
|
||||
"tags": ["user", "role", "permission", "auth"],
|
||||
"name": "Role",
|
||||
"label": "Role",
|
||||
"description": "Role and permission management",
|
||||
"tags": ["role", "permission", "auth", "rbac"],
|
||||
"table": {
|
||||
"name": "user_role",
|
||||
"comment": "User role and permission management"
|
||||
"name": "role",
|
||||
"comment": "Role and permission management"
|
||||
},
|
||||
"columns": [
|
||||
// ============================================================================
|
||||
|
|
@ -187,31 +187,44 @@
|
|||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_user_role_active",
|
||||
"name": "idx_role_active",
|
||||
"columns": ["is_active", "sort_order"],
|
||||
"type": "index",
|
||||
"comment": "Index for active roles with ordering"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_role_hierarchy",
|
||||
"name": "idx_role_hierarchy",
|
||||
"columns": ["parent_role_id", "level"],
|
||||
"type": "index",
|
||||
"comment": "Index for role hierarchy queries"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_role_system",
|
||||
"name": "idx_role_system",
|
||||
"columns": ["is_system", "is_active"],
|
||||
"type": "index",
|
||||
"comment": "Index for system role queries"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_role_default",
|
||||
"name": "idx_role_default",
|
||||
"columns": ["is_default", "is_active"],
|
||||
"type": "index",
|
||||
"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": [],
|
||||
"option": { "timestamps": true, "soft_deletes": true, "permission": true }
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "Organization",
|
||||
"label": "Organization",
|
||||
"description": "Organization structure and information storage",
|
||||
"tags": ["organization", "structure", "business", "verification"],
|
||||
"name": "Team",
|
||||
"label": "Team",
|
||||
"description": "Team structure and information storage",
|
||||
"tags": ["team", "structure", "business", "verification"],
|
||||
"table": {
|
||||
"name": "organization",
|
||||
"comment": "Organization structure and information storage"
|
||||
"name": "team",
|
||||
"comment": "Team structure and information storage"
|
||||
},
|
||||
"columns": [
|
||||
// ============================================================================
|
||||
|
|
@ -19,23 +19,23 @@
|
|||
"primary": true
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"name": "team_id",
|
||||
"type": "string",
|
||||
"label": "Organization ID",
|
||||
"comment": "Global unique organization identifier",
|
||||
"label": "Team ID",
|
||||
"comment": "Global unique team identifier",
|
||||
"length": 255,
|
||||
"unique": true,
|
||||
"index": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Organization Basic Information
|
||||
// Team Basic Information
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"label": "Organization Name",
|
||||
"comment": "Official organization name",
|
||||
"label": "Team Name",
|
||||
"comment": "Official team name",
|
||||
"length": 200,
|
||||
"nullable": false
|
||||
},
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
"name": "display_name",
|
||||
"type": "string",
|
||||
"label": "Display Name",
|
||||
"comment": "Organization display name or brand name",
|
||||
"comment": "Team display name or brand name",
|
||||
"length": 200,
|
||||
"nullable": true
|
||||
},
|
||||
|
|
@ -51,14 +51,14 @@
|
|||
"name": "description",
|
||||
"type": "text",
|
||||
"label": "Description",
|
||||
"comment": "Organization description",
|
||||
"comment": "Team description",
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
"name": "website",
|
||||
"type": "string",
|
||||
"label": "Website",
|
||||
"comment": "Organization website URL",
|
||||
"comment": "Team website URL",
|
||||
"length": 500,
|
||||
"nullable": true
|
||||
},
|
||||
|
|
@ -66,19 +66,19 @@
|
|||
"name": "logo",
|
||||
"type": "string",
|
||||
"label": "Logo",
|
||||
"comment": "Organization logo URL",
|
||||
"comment": "Team logo URL",
|
||||
"length": 500,
|
||||
"nullable": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Organization Ownership
|
||||
// Team Ownership
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "owner_id",
|
||||
"type": "string",
|
||||
"label": "Owner ID",
|
||||
"comment": "Organization owner user identifier (references user.user_id)",
|
||||
"comment": "Team owner user identifier (references user.user_id)",
|
||||
"length": 255,
|
||||
"nullable": false,
|
||||
"index": true
|
||||
|
|
@ -91,7 +91,7 @@
|
|||
"name": "contact_email",
|
||||
"type": "string",
|
||||
"label": "Contact Email",
|
||||
"comment": "Organization contact email address",
|
||||
"comment": "Team contact email address",
|
||||
"length": 255,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -100,20 +100,20 @@
|
|||
"name": "contact_phone",
|
||||
"type": "string",
|
||||
"label": "Contact Phone",
|
||||
"comment": "Organization contact phone number",
|
||||
"comment": "Team contact phone number",
|
||||
"length": 50,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Organization Verification
|
||||
// Team Verification
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "is_verified",
|
||||
"type": "boolean",
|
||||
"label": "Is Verified",
|
||||
"comment": "Whether organization is verified",
|
||||
"comment": "Whether team is verified",
|
||||
"default": false,
|
||||
"index": true
|
||||
},
|
||||
|
|
@ -121,7 +121,7 @@
|
|||
"name": "verified_at",
|
||||
"type": "timestamp",
|
||||
"label": "Verified At",
|
||||
"comment": "When organization was verified",
|
||||
"comment": "When team was verified",
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
|
|
@ -129,29 +129,29 @@
|
|||
"name": "verified_by",
|
||||
"type": "string",
|
||||
"label": "Verified By",
|
||||
"comment": "Who verified this organization",
|
||||
"comment": "Who verified this team",
|
||||
"length": 255,
|
||||
"nullable": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Organization Unique Code & Type
|
||||
// Team Unique Code & Type
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "org_code",
|
||||
"name": "team_code",
|
||||
"type": "string",
|
||||
"label": "Organization Code",
|
||||
"comment": "Unique organization identification code",
|
||||
"label": "Team Code",
|
||||
"comment": "Unique team identification code",
|
||||
"length": 100,
|
||||
"nullable": true,
|
||||
"unique": true,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "org_code_type",
|
||||
"name": "team_code_type",
|
||||
"type": "enum",
|
||||
"label": "Organization Code Type",
|
||||
"comment": "Type of organization identification code",
|
||||
"label": "Team Code Type",
|
||||
"comment": "Type of team identification code",
|
||||
"option": [
|
||||
// ============================================================================
|
||||
// Global Universal Standards (Apple & International Compatible)
|
||||
|
|
@ -252,19 +252,19 @@
|
|||
},
|
||||
|
||||
// ============================================================================
|
||||
// Organization Status & Management
|
||||
// Team Status & Management
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "status",
|
||||
"type": "enum",
|
||||
"label": "Status",
|
||||
"comment": "Organization status",
|
||||
"comment": "Team status",
|
||||
"option": [
|
||||
"pending", // New organization awaiting verification
|
||||
"active", // Active organization with full access
|
||||
"pending", // New team awaiting verification
|
||||
"active", // Active team with full access
|
||||
"inactive", // Temporarily inactive
|
||||
"suspended", // Suspended due to policy violations
|
||||
"archived" // Archived organization
|
||||
"archived" // Archived team
|
||||
],
|
||||
"default": "pending",
|
||||
"index": true,
|
||||
|
|
@ -274,7 +274,7 @@
|
|||
"name": "type_id",
|
||||
"type": "string",
|
||||
"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,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -282,8 +282,8 @@
|
|||
{
|
||||
"name": "type",
|
||||
"type": "enum",
|
||||
"label": "Organization Type",
|
||||
"comment": "Type of organization",
|
||||
"label": "Team Type",
|
||||
"comment": "Type of team",
|
||||
"option": [
|
||||
"corporation",
|
||||
"llc",
|
||||
|
|
@ -305,7 +305,7 @@
|
|||
"name": "address",
|
||||
"type": "json",
|
||||
"label": "Address",
|
||||
"comment": "Organization physical address (structured JSON with full details)",
|
||||
"comment": "Team physical address (structured JSON with full details)",
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
|
|
@ -320,7 +320,7 @@
|
|||
"name": "city",
|
||||
"type": "string",
|
||||
"label": "City",
|
||||
"comment": "Organization city",
|
||||
"comment": "Team city",
|
||||
"length": 100,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -347,7 +347,7 @@
|
|||
"name": "country",
|
||||
"type": "string",
|
||||
"label": "Country",
|
||||
"comment": "Organization country (ISO 3166-1 alpha-2)",
|
||||
"comment": "Team country (ISO 3166-1 alpha-2)",
|
||||
"length": 2,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -373,72 +373,72 @@
|
|||
"name": "zoneinfo",
|
||||
"type": "string",
|
||||
"label": "Zone Info",
|
||||
"comment": "Organization primary timezone (IANA Time Zone Database format)",
|
||||
"comment": "Team primary timezone (IANA Time Zone Database format)",
|
||||
"length": 50,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Organization Settings
|
||||
// Team Settings
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "settings",
|
||||
"type": "json",
|
||||
"label": "Settings",
|
||||
"comment": "Organization configuration settings",
|
||||
"comment": "Team configuration settings",
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
"name": "metadata",
|
||||
"type": "json",
|
||||
"label": "Metadata",
|
||||
"comment": "Extended organization metadata and custom fields",
|
||||
"comment": "Extended team metadata and custom fields",
|
||||
"nullable": true
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_org_owner_status",
|
||||
"name": "idx_team_owner_status",
|
||||
"columns": ["owner_id", "status"],
|
||||
"type": "index",
|
||||
"comment": "Index on owner and status for filtering"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_verification",
|
||||
"name": "idx_team_verification",
|
||||
"columns": ["is_verified", "verified_at"],
|
||||
"type": "index",
|
||||
"comment": "Index on verification status and time"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_code_type",
|
||||
"columns": ["org_code_type", "org_code"],
|
||||
"name": "idx_team_code_type",
|
||||
"columns": ["team_code_type", "team_code"],
|
||||
"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"],
|
||||
"type": "index",
|
||||
"comment": "Index on country, state/province and city for geographic queries"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_region_type",
|
||||
"name": "idx_team_region_type",
|
||||
"columns": ["region", "type"],
|
||||
"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"],
|
||||
"type": "index",
|
||||
"comment": "Index on postal code and zoneinfo for location services"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_type_status",
|
||||
"name": "idx_team_type_status",
|
||||
"columns": ["type_id", "status"],
|
||||
"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": {
|
||||
|
|
@ -450,22 +450,22 @@
|
|||
},
|
||||
"user_type": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.user_type",
|
||||
"model": "__yao.user.type",
|
||||
"key": "type_id",
|
||||
"foreign": "type_id"
|
||||
},
|
||||
"members": {
|
||||
"type": "hasMany",
|
||||
"model": "__yao.organization_user",
|
||||
"key": "org_id",
|
||||
"foreign": "org_id"
|
||||
"model": "__yao.member",
|
||||
"key": "team_id",
|
||||
"foreign": "team_id"
|
||||
},
|
||||
"users": {
|
||||
"type": "hasManyThrough",
|
||||
"model": "__yao.user",
|
||||
"through": "__yao.organization_user",
|
||||
"key": "org_id",
|
||||
"foreign": "org_id",
|
||||
"through": "__yao.member",
|
||||
"key": "team_id",
|
||||
"foreign": "team_id",
|
||||
"throughKey": "user_id",
|
||||
"throughForeign": "user_id"
|
||||
}
|
||||
|
|
@ -243,7 +243,7 @@
|
|||
"name": "role_id",
|
||||
"type": "string",
|
||||
"label": "Role ID",
|
||||
"comment": "User role identifier (references user_role.role_id)",
|
||||
"comment": "User role identifier (references role.role_id)",
|
||||
"length": 50,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
"name": "type_id",
|
||||
"type": "string",
|
||||
"label": "Type ID",
|
||||
"comment": "User type identifier (references user_type.type_id)",
|
||||
"comment": "User type identifier (references user.type.type_id)",
|
||||
"length": 50,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -387,36 +387,42 @@
|
|||
"relations": {
|
||||
"role": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.user_role",
|
||||
"model": "__yao.role",
|
||||
"key": "role_id",
|
||||
"foreign": "role_id"
|
||||
},
|
||||
"type": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.user_type",
|
||||
"model": "__yao.user.type",
|
||||
"key": "type_id",
|
||||
"foreign": "type_id"
|
||||
},
|
||||
"owned_organizations": {
|
||||
"oauth_accounts": {
|
||||
"type": "hasMany",
|
||||
"model": "__yao.organization",
|
||||
"key": "user_id",
|
||||
"foreign": "owner_id"
|
||||
},
|
||||
"organization_memberships": {
|
||||
"type": "hasMany",
|
||||
"model": "__yao.organization_user",
|
||||
"model": "__yao.user.oauth_account",
|
||||
"key": "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",
|
||||
"model": "__yao.organization",
|
||||
"through": "__yao.organization_user",
|
||||
"model": "__yao.team",
|
||||
"through": "__yao.member",
|
||||
"key": "user_id",
|
||||
"foreign": "user_id",
|
||||
"throughKey": "org_id",
|
||||
"throughForeign": "org_id"
|
||||
"throughKey": "team_id",
|
||||
"throughForeign": "team_id"
|
||||
}
|
||||
},
|
||||
"values": [],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "User OAuth Account",
|
||||
"label": "User OAuth Account",
|
||||
"name": "OAuth Account",
|
||||
"label": "OAuth Account",
|
||||
"description": "User's third-party OAuth account information storage",
|
||||
"tags": ["user", "oauth", "social", "external", "provider"],
|
||||
"table": {
|
||||
|
|
@ -225,31 +225,38 @@
|
|||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_user_oauth_user_provider",
|
||||
"name": "idx_oauth_account_user_provider",
|
||||
"columns": ["user_id", "provider"],
|
||||
"type": "unique",
|
||||
"comment": "Unique constraint: one account per provider per user"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_oauth_provider_sub",
|
||||
"name": "idx_oauth_account_provider_sub",
|
||||
"columns": ["provider", "sub"],
|
||||
"type": "unique",
|
||||
"comment": "Unique constraint: one record per provider sub claim"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_oauth_email",
|
||||
"name": "idx_oauth_account_email",
|
||||
"columns": ["provider", "email"],
|
||||
"type": "index",
|
||||
"comment": "Index for email lookups by provider"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_oauth_active",
|
||||
"name": "idx_oauth_account_active",
|
||||
"columns": ["is_active", "last_login_at"],
|
||||
"type": "index",
|
||||
"comment": "Index for active account queries"
|
||||
}
|
||||
],
|
||||
"relations": {},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.user",
|
||||
"key": "user_id",
|
||||
"foreign": "user_id"
|
||||
}
|
||||
},
|
||||
"values": [],
|
||||
"option": { "timestamps": true, "soft_deletes": true, "permission": true }
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "User Type",
|
||||
"label": "User Type",
|
||||
"name": "Type",
|
||||
"label": "Type",
|
||||
"description": "User type classification and configuration",
|
||||
"tags": ["user", "type", "classification", "config"],
|
||||
"table": {
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
"name": "default_role_id",
|
||||
"type": "string",
|
||||
"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,
|
||||
"nullable": true,
|
||||
"index": true
|
||||
|
|
@ -145,19 +145,32 @@
|
|||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_user_type_active",
|
||||
"name": "idx_type_active",
|
||||
"columns": ["is_active", "sort_order"],
|
||||
"type": "index",
|
||||
"comment": "Index for active user types with ordering"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_type_default",
|
||||
"name": "idx_type_default",
|
||||
"columns": ["is_default", "is_active"],
|
||||
"type": "index",
|
||||
"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": [],
|
||||
"option": { "timestamps": true, "soft_deletes": true, "permission": true }
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue