Database migration — license, entitlement, activation, product_tier tables #617

Open
opened 2026-06-12 07:57:18 +00:00 by jmiller · 0 comments
Owner

Phase 1.1 — Database Schema

Parent: #616 | Depends on: none | Blocks: #618, #619, #620

New Gitea migration file

Add models/migrations/vXXX.go with 4 new tables:

// Table 1: license
type License struct {
    ID         int64     `xorm:"pk autoincr"`
    UserID     int64     `xorm:"INDEX NOT NULL"`
    DLID       string    `xorm:"VARCHAR(36) UNIQUE NOT NULL"`
    Tier       string    `xorm:"VARCHAR(30) NOT NULL DEFAULT 'base'"`
    MaxDomains int       `xorm:"NOT NULL DEFAULT 1"`
    Status     string    `xorm:"VARCHAR(20) NOT NULL DEFAULT 'active'"` // active, expired, revoked, suspended
    ExpiresAt  time.Time `xorm:"INDEX"`
    Notes      string    `xorm:"TEXT"`
    CreatedAt  time.Time `xorm:"created"`
    UpdatedAt  time.Time `xorm:"updated"`
}

// Table 2: license_entitlement
type LicenseEntitlement struct {
    ID          int64  `xorm:"pk autoincr"`
    LicenseID   int64  `xorm:"INDEX NOT NULL"`
    ProductCode string `xorm:"VARCHAR(30) NOT NULL"` // "crm", "pos", "restaurant", etc.
    RepoOwner   string `xorm:"VARCHAR(100) NOT NULL DEFAULT 'MokoConsulting'"`
    RepoName    string `xorm:"VARCHAR(100) NOT NULL"` // "MokoSuiteCRM", "MokoSuitePOS"
    // UNIQUE(license_id, product_code)
}

// Table 3: license_activation
type LicenseActivation struct {
    ID          int64     `xorm:"pk autoincr"`
    LicenseID   int64     `xorm:"INDEX NOT NULL"`
    Domain      string    `xorm:"VARCHAR(255) NOT NULL"`
    IPAddress   string    `xorm:"VARCHAR(64)"`
    JoomlaVer   string    `xorm:"VARCHAR(20)"`
    ActivatedAt time.Time `xorm:"created"`
    LastSeenAt  time.Time
    // UNIQUE(license_id, domain)
}

// Table 4: product_tier
type ProductTier struct {
    ID       int64  `xorm:"pk autoincr"`
    TierKey  string `xorm:"VARCHAR(30) UNIQUE NOT NULL"` // "pos", "shop", "enterprise"
    TierName string `xorm:"VARCHAR(100) NOT NULL"`
    Repos    string `xorm:"JSON"` // ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuitePOS"]
    MaxDomains int  `xorm:"NOT NULL DEFAULT 1"`
    SortOrder  int  `xorm:"NOT NULL DEFAULT 0"`
}

Seed data for product_tier

tier_key tier_name repos max_domains
base MokoSuite Base ["MokoSuite"] 1
crm MokoSuite CRM ["MokoSuite","MokoSuiteCRM"] 3
erp MokoSuite ERP ["MokoSuite","MokoSuiteCRM","MokoSuiteERP"] 3
child MokoSuite Child ["MokoSuite","MokoSuiteCRM","MokoSuiteChild"] 3
create MokoSuite Create ["MokoSuite","MokoSuiteCRM","MokoSuiteCreate"] 3
npo MokoSuite NPO ["MokoSuite","MokoSuiteCRM","MokoSuiteNPO"] 3
pos MokoSuite POS ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuitePOS"] 5
shop MokoSuite Shop ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuiteShop"] 5
hrm MokoSuite HRM ["MokoSuite","MokoSuiteCRM","MokoSuiteHRM"] 3
mrp MokoSuite MRP ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuiteMRP"] 3
restaurant MokoSuite Restaurant ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuitePOS","MokoSuiteRestaurant"] 5
suite MokoSuite Suite (all repos) 10
enterprise MokoSuite Enterprise (all repos) unlimited

Acceptance criteria

  • Migration runs cleanly on fresh + existing Gitea databases
  • Seed tiers are created on migration
  • Indexes on DLID, user_id, license_id, product_code, domain
  • Foreign key from license.user_id to user.id
## Phase 1.1 — Database Schema Parent: #616 | Depends on: none | Blocks: #618, #619, #620 ### New Gitea migration file Add `models/migrations/vXXX.go` with 4 new tables: ```go // Table 1: license type License struct { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"INDEX NOT NULL"` DLID string `xorm:"VARCHAR(36) UNIQUE NOT NULL"` Tier string `xorm:"VARCHAR(30) NOT NULL DEFAULT 'base'"` MaxDomains int `xorm:"NOT NULL DEFAULT 1"` Status string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'active'"` // active, expired, revoked, suspended ExpiresAt time.Time `xorm:"INDEX"` Notes string `xorm:"TEXT"` CreatedAt time.Time `xorm:"created"` UpdatedAt time.Time `xorm:"updated"` } // Table 2: license_entitlement type LicenseEntitlement struct { ID int64 `xorm:"pk autoincr"` LicenseID int64 `xorm:"INDEX NOT NULL"` ProductCode string `xorm:"VARCHAR(30) NOT NULL"` // "crm", "pos", "restaurant", etc. RepoOwner string `xorm:"VARCHAR(100) NOT NULL DEFAULT 'MokoConsulting'"` RepoName string `xorm:"VARCHAR(100) NOT NULL"` // "MokoSuiteCRM", "MokoSuitePOS" // UNIQUE(license_id, product_code) } // Table 3: license_activation type LicenseActivation struct { ID int64 `xorm:"pk autoincr"` LicenseID int64 `xorm:"INDEX NOT NULL"` Domain string `xorm:"VARCHAR(255) NOT NULL"` IPAddress string `xorm:"VARCHAR(64)"` JoomlaVer string `xorm:"VARCHAR(20)"` ActivatedAt time.Time `xorm:"created"` LastSeenAt time.Time // UNIQUE(license_id, domain) } // Table 4: product_tier type ProductTier struct { ID int64 `xorm:"pk autoincr"` TierKey string `xorm:"VARCHAR(30) UNIQUE NOT NULL"` // "pos", "shop", "enterprise" TierName string `xorm:"VARCHAR(100) NOT NULL"` Repos string `xorm:"JSON"` // ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuitePOS"] MaxDomains int `xorm:"NOT NULL DEFAULT 1"` SortOrder int `xorm:"NOT NULL DEFAULT 0"` } ``` ### Seed data for product_tier | tier_key | tier_name | repos | max_domains | |----------|-----------|-------|-------------| | base | MokoSuite Base | ["MokoSuite"] | 1 | | crm | MokoSuite CRM | ["MokoSuite","MokoSuiteCRM"] | 3 | | erp | MokoSuite ERP | ["MokoSuite","MokoSuiteCRM","MokoSuiteERP"] | 3 | | child | MokoSuite Child | ["MokoSuite","MokoSuiteCRM","MokoSuiteChild"] | 3 | | create | MokoSuite Create | ["MokoSuite","MokoSuiteCRM","MokoSuiteCreate"] | 3 | | npo | MokoSuite NPO | ["MokoSuite","MokoSuiteCRM","MokoSuiteNPO"] | 3 | | pos | MokoSuite POS | ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuitePOS"] | 5 | | shop | MokoSuite Shop | ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuiteShop"] | 5 | | hrm | MokoSuite HRM | ["MokoSuite","MokoSuiteCRM","MokoSuiteHRM"] | 3 | | mrp | MokoSuite MRP | ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuiteMRP"] | 3 | | restaurant | MokoSuite Restaurant | ["MokoSuite","MokoSuiteCRM","MokoSuiteERP","MokoSuitePOS","MokoSuiteRestaurant"] | 5 | | suite | MokoSuite Suite | (all repos) | 10 | | enterprise | MokoSuite Enterprise | (all repos) | unlimited | ### Acceptance criteria - [ ] Migration runs cleanly on fresh + existing Gitea databases - [ ] Seed tiers are created on migration - [ ] Indexes on DLID, user_id, license_id, product_code, domain - [ ] Foreign key from license.user_id to user.id
Sign in to join this conversation.