Merge pull request #1142 from trheyi/main
Add organization_user model and enhance relationships in existing models
This commit is contained in:
commit
82a2e55bd4
6 changed files with 436 additions and 141 deletions
305
data/bindata.go
305
data/bindata.go
File diff suppressed because one or more lines are too long
|
|
@ -34,6 +34,7 @@ var systemModels = map[string]string{
|
|||
"__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.user": "yao/models/user.mod.yao",
|
||||
"__yao.user_role": "yao/models/user_role.mod.yao",
|
||||
"__yao.user_type": "yao/models/user_type.mod.yao",
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ var testSystemModels = map[string]string{
|
|||
"__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.user": "yao/models/user.mod.yao",
|
||||
"__yao.user_role": "yao/models/user_role.mod.yao",
|
||||
"__yao.user_type": "yao/models/user_type.mod.yao",
|
||||
|
|
|
|||
|
|
@ -453,6 +453,21 @@
|
|||
"model": "__yao.user_type",
|
||||
"key": "type_id",
|
||||
"foreign": "type_id"
|
||||
},
|
||||
"members": {
|
||||
"type": "hasMany",
|
||||
"model": "__yao.organization_user",
|
||||
"key": "org_id",
|
||||
"foreign": "org_id"
|
||||
},
|
||||
"users": {
|
||||
"type": "hasManyThrough",
|
||||
"model": "__yao.user",
|
||||
"through": "__yao.organization_user",
|
||||
"key": "org_id",
|
||||
"foreign": "org_id",
|
||||
"throughKey": "user_id",
|
||||
"throughForeign": "user_id"
|
||||
}
|
||||
},
|
||||
"values": [],
|
||||
|
|
|
|||
234
yao/models/organization_user.mod.yao
Normal file
234
yao/models/organization_user.mod.yao
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
{
|
||||
"name": "Organization User",
|
||||
"label": "Organization User",
|
||||
"description": "Association table for organization members and their roles",
|
||||
"tags": ["organization", "user", "association", "membership", "roles"],
|
||||
"table": {
|
||||
"name": "organization_user",
|
||||
"comment": "Association table for organization members and their roles"
|
||||
},
|
||||
"columns": [
|
||||
// ============================================================================
|
||||
// Basic Fields
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "id",
|
||||
"type": "ID",
|
||||
"label": "ID",
|
||||
"comment": "Primary key identifier",
|
||||
"primary": true
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"type": "string",
|
||||
"label": "Organization ID",
|
||||
"comment": "Organization identifier (references organization.org_id)",
|
||||
"length": 255,
|
||||
"nullable": false,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "user_id",
|
||||
"type": "string",
|
||||
"label": "User ID",
|
||||
"comment": "User identifier (references user.user_id)",
|
||||
"length": 255,
|
||||
"nullable": false,
|
||||
"index": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// 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": "status",
|
||||
"type": "enum",
|
||||
"label": "Status",
|
||||
"comment": "Membership status",
|
||||
"option": [
|
||||
"pending", // Invitation sent, not accepted yet
|
||||
"active", // Active member
|
||||
"inactive", // Temporarily inactive
|
||||
"suspended" // Suspended by admin
|
||||
],
|
||||
"default": "pending",
|
||||
"index": true,
|
||||
"nullable": false
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Invitation & Join Information
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "invited_by",
|
||||
"type": "string",
|
||||
"label": "Invited By",
|
||||
"comment": "User ID who sent the invitation",
|
||||
"length": 255,
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
"name": "invited_at",
|
||||
"type": "timestamp",
|
||||
"label": "Invited At",
|
||||
"comment": "When the invitation was sent",
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "joined_at",
|
||||
"type": "timestamp",
|
||||
"label": "Joined At",
|
||||
"comment": "When the user accepted and joined the organization",
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "invitation_token",
|
||||
"type": "string",
|
||||
"label": "Invitation Token",
|
||||
"comment": "Unique token for invitation acceptance",
|
||||
"length": 100,
|
||||
"nullable": true,
|
||||
"unique": true,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "invitation_expires_at",
|
||||
"type": "timestamp",
|
||||
"label": "Invitation Expires At",
|
||||
"comment": "When the invitation expires",
|
||||
"nullable": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Permission Overrides
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "permissions",
|
||||
"type": "json",
|
||||
"label": "Permissions",
|
||||
"comment": "Custom permissions override for this user in this organization",
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
"name": "restrictions",
|
||||
"type": "json",
|
||||
"label": "Restrictions",
|
||||
"comment": "Additional restrictions for this user in this organization",
|
||||
"nullable": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Activity Tracking
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "last_active_at",
|
||||
"type": "timestamp",
|
||||
"label": "Last Active At",
|
||||
"comment": "When the user was last active in this organization",
|
||||
"nullable": true,
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"name": "login_count",
|
||||
"type": "integer",
|
||||
"label": "Login Count",
|
||||
"comment": "Number of times user has accessed this organization",
|
||||
"default": 0,
|
||||
"nullable": true
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Metadata
|
||||
// ============================================================================
|
||||
{
|
||||
"name": "notes",
|
||||
"type": "text",
|
||||
"label": "Notes",
|
||||
"comment": "Internal notes about this membership",
|
||||
"nullable": true
|
||||
},
|
||||
{
|
||||
"name": "metadata",
|
||||
"type": "json",
|
||||
"label": "Metadata",
|
||||
"comment": "Additional metadata for this membership",
|
||||
"nullable": true
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_org_user_unique",
|
||||
"columns": ["org_id", "user_id"],
|
||||
"type": "unique",
|
||||
"comment": "Unique constraint: one user can have only one membership per organization"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_user_role",
|
||||
"columns": ["org_id", "role", "status"],
|
||||
"type": "index",
|
||||
"comment": "Index for finding users by role and status within organization"
|
||||
},
|
||||
{
|
||||
"name": "idx_user_orgs",
|
||||
"columns": ["user_id", "status", "role"],
|
||||
"type": "index",
|
||||
"comment": "Index for finding all organizations for a user"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_invitations",
|
||||
"columns": ["org_id", "status", "invited_at"],
|
||||
"type": "index",
|
||||
"comment": "Index for managing invitations"
|
||||
},
|
||||
{
|
||||
"name": "idx_invitation_token",
|
||||
"columns": ["invitation_token", "invitation_expires_at"],
|
||||
"type": "index",
|
||||
"comment": "Index for invitation token lookup and expiration"
|
||||
},
|
||||
{
|
||||
"name": "idx_org_activity",
|
||||
"columns": ["org_id", "last_active_at"],
|
||||
"type": "index",
|
||||
"comment": "Index for organization activity tracking"
|
||||
}
|
||||
],
|
||||
"relations": {
|
||||
"organization": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.organization",
|
||||
"key": "org_id",
|
||||
"foreign": "org_id"
|
||||
},
|
||||
"user": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.user",
|
||||
"key": "user_id",
|
||||
"foreign": "user_id"
|
||||
},
|
||||
"inviter": {
|
||||
"type": "hasOne",
|
||||
"model": "__yao.user",
|
||||
"key": "invited_by",
|
||||
"foreign": "user_id"
|
||||
}
|
||||
},
|
||||
"values": [],
|
||||
"option": { "timestamps": true, "soft_deletes": true, "permission": true }
|
||||
}
|
||||
|
|
@ -396,6 +396,27 @@
|
|||
"model": "__yao.user_type",
|
||||
"key": "type_id",
|
||||
"foreign": "type_id"
|
||||
},
|
||||
"owned_organizations": {
|
||||
"type": "hasMany",
|
||||
"model": "__yao.organization",
|
||||
"key": "user_id",
|
||||
"foreign": "owner_id"
|
||||
},
|
||||
"organization_memberships": {
|
||||
"type": "hasMany",
|
||||
"model": "__yao.organization_user",
|
||||
"key": "user_id",
|
||||
"foreign": "user_id"
|
||||
},
|
||||
"organizations": {
|
||||
"type": "hasManyThrough",
|
||||
"model": "__yao.organization",
|
||||
"through": "__yao.organization_user",
|
||||
"key": "user_id",
|
||||
"foreign": "user_id",
|
||||
"throughKey": "org_id",
|
||||
"throughForeign": "org_id"
|
||||
}
|
||||
},
|
||||
"values": [],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue