| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- // Package model 组织域 GORM 领域模型(与 unified/02-data-model/core-model-ddl.sql 逐列对齐)。
- //
- // 设计决策(T1 D1/D2/D3,2026-11-06 用户拍板):
- // - D2 机构/校区主键 = int64 自增(InstitutionID/CampusID,非 ULID;对齐 scope.Scope 作用域字段 int64)。
- // - D1 引用人的外键列(Membership.CanonicalUserID / GuardianLink.GuardianID / StudentID)= string(ULID,size:26)。
- // - D3 关系表(Membership/GuardianLink)主键 = int64 自增。
- // - Role 为平台级字典表(不带作用域),role_code 为主键(字典码,非自增)。
- //
- // GORM 类型映射纪律(架构规格 §3.6,T2 验收"DDL 逐表与 GORM Model 对齐"的硬要求):
- // - **string 必须带 size:N**(GORM 未指定 size 的 string 默认 longtext,T2 对账实证漂移):
- // 每个 string/*string 字段的 size 严格等于 DDL 的 varchar(N) 的 N。
- // - **tinyint(1) 用 bool**:GORM bool → tinyint(1)(t_role.login_allowed / t_membership 无)。
- // - 列名显式 `gorm:"column:xxx"`,不依赖默认命名。
- // - 时间列 CreatedAt/UpdatedAt:GORM 自动管理(GORM v1.31 MySQL 默认 datetime(3),与 DDL 一致)。
- //
- // 多租户作用域(架构规格 §3.5):
- // - Institution/Campus/Membership/GuardianLink 四表均带 institution_id / campus_id 列,
- // Repository 强制 scoping(跨校区越权防线);Role 是平台级字典,Repository 不继承 BaseRepo。
- package model
- import "time"
- // InstitutionStatus 机构/校区状态。
- const (
- StatusActive = "active" // 正常
- StatusDisabled = "disabled" // 停用
- )
- // Institution 机构表 t_institution(多租户根·品牌级)。
- //
- // D2:主键 InstitutionID int64 自增(作用域根,scope.Scope.InstitutionID 引用此值)。
- type Institution struct {
- InstitutionID int64 `gorm:"column:institution_id;primaryKey" json:"institutionId"`
- InstitutionName string `gorm:"column:institution_name;size:128;not null" json:"institutionName"`
- InstitutionCode *string `gorm:"column:institution_code;size:32" json:"institutionCode,omitempty"`
- Address *string `gorm:"column:address;size:255" json:"address,omitempty"`
- Phone *string `gorm:"column:phone;size:20" json:"phone,omitempty"`
- Status string `gorm:"column:status;size:16;not null" json:"status"`
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
- }
- // TableName 指定表名(GORM 默认 Institution → institutions,与 DDL 单数 t_institution 不符)。
- func (Institution) TableName() string { return "t_institution" }
- // Campus 校区表 t_campus(隶属机构)。
- //
- // D2:主键 CampusID int64 自增;InstitutionID int64(→ t_institution,作用域字段)。
- // SelfSupport 为 2026-11-09 academic 域设计 §11.1 拍板 A 的增量列(AC-01 并入):
- // 来源旧库 `yuansiwei.t_school_campus.self_support`,供 academic 域判定活动失效范围
- // (自营 → `campus_id IN (x,0)`,加盟 → `= x`;经 port.CampusReader 只读获取,不跨库)。
- type Campus struct {
- CampusID int64 `gorm:"column:campus_id;primaryKey" json:"campusId"`
- InstitutionID int64 `gorm:"column:institution_id;not null" json:"institutionId"`
- CampusName string `gorm:"column:campus_name;size:128;not null" json:"campusName"`
- CampusCode *string `gorm:"column:campus_code;size:32" json:"campusCode,omitempty"`
- Address *string `gorm:"column:address;size:255" json:"address,omitempty"`
- Phone *string `gorm:"column:phone;size:20" json:"phone,omitempty"`
- Status string `gorm:"column:status;size:16;not null" json:"status"`
- SelfSupport int8 `gorm:"column:self_support;not null;default:1" json:"selfSupport"` // 是否自营校区(1 自营 / 0 加盟)
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
- }
- // TableName 指定表名(GORM 默认 Campus → campuses,与 DDL 单数 t_campus 不符)。
- func (Campus) TableName() string { return "t_campus" }
- // Role 运营角色(7 类,ADR-007 / 2026-11-05 拍板)。
- // role_code 与 Membership.Role 列取值一致(跨包引用时 import 本包常量,避免字符串散落)。
- const (
- RoleSuperAdmin = "super_admin" // 超级管理员(平台级,跨机构)
- RoleAcademic = "academic" // 教务(机构/校区级)
- RoleFinance = "finance" // 财务(机构/校区级)
- RoleTeacher = "teacher" // 老师(校区级)
- RoleStudent = "student" // 学生(业务级)
- RoleParent = "parent" // 家长(业务级,按 GuardianLink 绑定)
- RoleMarket = "market" // 市场(数据保留、登录禁用,login_allowed=0)
- )
- // ScopeLevel 角色权限层级(t_role.scope_level)。
- const (
- ScopeLevelPlatform = "platform" // 平台级(超管,跨机构)
- ScopeLevelInstitution = "institution" // 机构/校区级(教务/财务/市场)
- ScopeLevelCampus = "campus" // 校区级(老师)
- ScopeLevelBusiness = "business" // 业务级(学生/家长,按报名/绑定归属)
- )
- // RoleModel 角色字典表 t_role(平台级元数据·不带作用域)。
- //
- // 主键 RoleCode 为 string(字典码,size:32),非自增——GORM primaryKey tag 标注(string 主键不触发自增)。
- // 种子数据由 core-model-ddl.sql 内置 INSERT IGNORE;Go 侧只读字典,故无 UpdatedAt 列。
- // LoginAllowed 为 bool 对齐 DDL tinyint(1)。
- type RoleModel struct {
- RoleCode string `gorm:"column:role_code;primaryKey;size:32" json:"roleCode"`
- RoleName string `gorm:"column:role_name;size:32;not null" json:"roleName"`
- ScopeLevel string `gorm:"column:scope_level;size:16;not null" json:"scopeLevel"`
- LoginAllowed bool `gorm:"column:login_allowed;not null" json:"loginAllowed"` // tinyint(1) → bool
- Description *string `gorm:"column:description;size:255" json:"description,omitempty"`
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- }
- // TableName 指定表名(GORM 默认 RoleModel → role_models,与 DDL 单数 t_role 不符;
- // 类型名加 Model 后缀避免与常量 Role* 混淆,表名显式锁定 t_role)。
- func (RoleModel) TableName() string { return "t_role" }
- // MembershipStatus 成员关系状态。
- const (
- MembershipStatusActive = "active" // 在籍
- MembershipStatusInactive = "inactive" // 离开(离职/退学/解绑,left_at 填值)
- )
- // Membership 成员关系表 t_membership(人 ↔ 机构/校区 + 角色,多对多,多租户核心,ADR-007)。
- //
- // D3:主键 MembershipID int64 自增;CanonicalUserID string(ULID,size:26,→ t_user)。
- // UNIQUE(canonical_user_id, campus_id, role)——campus 隐含 institution。
- // campus_id=0 表示平台级(如超管,跨机构)。DDL 无 updated_at 列,故 model 不设 UpdatedAt。
- type Membership struct {
- MembershipID int64 `gorm:"column:membership_id;primaryKey" json:"membershipId"`
- CanonicalUserID string `gorm:"column:canonical_user_id;size:26;not null" json:"canonicalUserId"`
- InstitutionID int64 `gorm:"column:institution_id;not null" json:"institutionId"` // 0=平台级
- CampusID int64 `gorm:"column:campus_id;not null" json:"campusId"` // 0=平台级/机构级
- Role string `gorm:"column:role;size:32;not null" json:"role"`
- Status string `gorm:"column:status;size:16;not null" json:"status"`
- JoinedAt *time.Time `gorm:"column:joined_at" json:"joinedAt,omitempty"`
- LeftAt *time.Time `gorm:"column:left_at" json:"leftAt,omitempty"`
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- }
- // TableName 指定表名(GORM 默认 Membership → memberships,与 DDL 单数 t_membership 不符)。
- func (Membership) TableName() string { return "t_membership" }
- // GuardianRelation 家长-学生关系类型(t_guardian_link.relation,可空)。
- const (
- GuardianRelationFather = "father" // 父
- GuardianRelationMother = "mother" // 母
- GuardianRelationGuardian = "guardian" // 监护人
- GuardianRelationOther = "other" // 其他
- )
- // GuardianLink 家长-学生绑定表 t_guardian_link(带作用域,多对多)。
- //
- // D3:主键 LinkID int64 自增;GuardianID / StudentID 均 string(ULID,size:26,→ t_user,D1)。
- // 一个学生多家长、一个家长多学生;家长只能看绑定的学生(跨家长越权防线,§3.5)。
- type GuardianLink struct {
- LinkID int64 `gorm:"column:link_id;primaryKey" json:"linkId"`
- GuardianID string `gorm:"column:guardian_id;size:26;not null" json:"guardianId"`
- StudentID string `gorm:"column:student_id;size:26;not null" json:"studentId"`
- InstitutionID int64 `gorm:"column:institution_id;not null" json:"institutionId"`
- CampusID int64 `gorm:"column:campus_id;not null" json:"campusId"`
- Relation *string `gorm:"column:relation;size:32" json:"relation,omitempty"`
- Status string `gorm:"column:status;size:16;not null" json:"status"`
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
- }
- // TableName 指定表名(GORM 默认 GuardianLink → guardian_links,与 DDL 单数 t_guardian_link 不符)。
- func (GuardianLink) TableName() string { return "t_guardian_link" }
- // PermissionStatus 权限点状态。
- const (
- PermissionStatusActive = "active"
- PermissionStatusDisabled = "disabled" // disabled 不进菜单树/权限集(软下线,不物理删)
- )
- // PermissionType 权限点类型。
- const (
- PermissionTypeMenu = "menu" // 菜单节点:进菜单树(menuTree 下发),叶子必有 path
- PermissionTypeButton = "button" // 按钮节点:不进菜单树,仅供 v-perm 权限码判定
- )
- // Permission 权限点字典表 t_permission(平台级元数据·不带作用域,RBAC 菜单/按钮展示层,T6.5)。
- //
- // 主键 Code 为 string(三段式 `域.资源.动作`,如 org.institution.list;对齐 PC 前端契约
- // MenuNode.code / permissions[],前端按此做菜单显隐 + 按钮 v-perm 联动)。
- // ParentCode 自引用构成菜单树(type=menu 的子树即菜单树;button 挂对应 menu 下,不进树)。
- // 超级管理员**不依赖本表**放行(代码层全量放行,T6.5-d requireRole 中间件),
- // 本表只服务"非超管角色的可见菜单/按钮"。
- type Permission struct {
- Code string `gorm:"column:code;primaryKey;size:64" json:"code"`
- Type string `gorm:"column:type;size:16;not null" json:"type"`
- Name string `gorm:"column:name;size:64;not null" json:"name"`
- ParentCode *string `gorm:"column:parent_code;size:64" json:"parentCode,omitempty"`
- Path *string `gorm:"column:path;size:255" json:"path,omitempty"`
- Icon *string `gorm:"column:icon;size:64" json:"icon,omitempty"`
- Sort int32 `gorm:"column:sort;not null" json:"sort"`
- Status string `gorm:"column:status;size:16;not null" json:"status"`
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
- }
- // TableName 指定表名(GORM 默认 Permission → permissions,与 DDL 单数 t_permission 不符)。
- func (Permission) TableName() string { return "t_permission" }
- // RolePermission 角色-权限点矩阵表 t_role_permission(平台级,D3 主键自增)。
- //
- // UNIQUE(role_code, permission_code);矩阵由超管端点配置(T6.5-e:删旧插新事务),
- // 种子为起步态(core-model-ddl.sql v1.1 内置 INSERT IGNORE)。
- type RolePermission struct {
- ID int64 `gorm:"column:id;primaryKey" json:"id"`
- RoleCode string `gorm:"column:role_code;size:32;not null" json:"roleCode"`
- PermissionCode string `gorm:"column:permission_code;size:64;not null" json:"permissionCode"`
- CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
- }
- // TableName 指定表名(GORM 默认 RolePermission → role_permissions,与 DDL 单数 t_role_permission 不符)。
- func (RolePermission) TableName() string { return "t_role_permission" }
- // AllTables 返回本域全部 model 指针切片(供装配层/集成测试合并后传入 infra/db.Migrate)。
- //
- // 入参:无。
- // 出参:[]any——org 域 7 表(Institution/Campus/Membership/Role/GuardianLink/Permission/RolePermission)。
- // 说明:返回新切片,调用方可安全 append。
- func AllTables() []any {
- return []any{
- &Institution{},
- &Campus{},
- &Membership{},
- &RoleModel{},
- &GuardianLink{},
- &Permission{},
- &RolePermission{},
- }
- }
|