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.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.organization": "yao/models/organization.mod.yao",
|
||||||
|
"__yao.organization_user": "yao/models/organization_user.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.user_role": "yao/models/user_role.mod.yao",
|
||||||
"__yao.user_type": "yao/models/user_type.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.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.organization": "yao/models/organization.mod.yao",
|
||||||
|
"__yao.organization_user": "yao/models/organization_user.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.user_role": "yao/models/user_role.mod.yao",
|
||||||
"__yao.user_type": "yao/models/user_type.mod.yao",
|
"__yao.user_type": "yao/models/user_type.mod.yao",
|
||||||
|
|
|
||||||
|
|
@ -453,6 +453,21 @@
|
||||||
"model": "__yao.user_type",
|
"model": "__yao.user_type",
|
||||||
"key": "type_id",
|
"key": "type_id",
|
||||||
"foreign": "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": [],
|
"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",
|
"model": "__yao.user_type",
|
||||||
"key": "type_id",
|
"key": "type_id",
|
||||||
"foreign": "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": [],
|
"values": [],
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue