2026-04-01 00:58:42 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
|
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
|
|
|
|
|
|
"github.com/geo-platform/tenant-api/internal/shared/config"
|
2026-04-05 17:14:13 +08:00
|
|
|
"github.com/geo-platform/tenant-api/internal/tenant/prompts"
|
2026-04-01 00:58:42 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
configPath := "configs/config.yaml"
|
|
|
|
|
if p := os.Getenv("CONFIG_PATH"); p != "" {
|
|
|
|
|
configPath = p
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cfg, err := config.Load(configPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("load config: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
pool, err := pgxpool.New(ctx, cfg.Database.DSN())
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("connect db: %v", err)
|
|
|
|
|
}
|
|
|
|
|
defer pool.Close()
|
|
|
|
|
|
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte("Admin@123"), bcrypt.DefaultCost)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("hash password: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tx, err := pool.Begin(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("begin tx: %v", err)
|
|
|
|
|
}
|
|
|
|
|
defer func() {
|
|
|
|
|
_ = tx.Rollback(ctx)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// Tenant
|
|
|
|
|
var tenantID int64
|
|
|
|
|
err = tx.QueryRow(ctx, `
|
2026-04-02 00:31:28 +08:00
|
|
|
WITH ensured AS (
|
|
|
|
|
INSERT INTO tenants (name, status) VALUES ('GEO Demo', 'active')
|
|
|
|
|
ON CONFLICT DO NOTHING
|
|
|
|
|
RETURNING id
|
|
|
|
|
)
|
|
|
|
|
SELECT id FROM ensured
|
|
|
|
|
UNION ALL
|
|
|
|
|
SELECT id FROM tenants WHERE name = 'GEO Demo'
|
|
|
|
|
LIMIT 1
|
2026-04-01 00:58:42 +08:00
|
|
|
`).Scan(&tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("insert tenant: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// User
|
|
|
|
|
var userID int64
|
|
|
|
|
err = tx.QueryRow(ctx, `
|
2026-04-02 00:31:28 +08:00
|
|
|
WITH ensured AS (
|
|
|
|
|
INSERT INTO users (email, password_hash, name, status)
|
|
|
|
|
VALUES ('admin@geo.local', $1, 'Admin', 'active')
|
|
|
|
|
ON CONFLICT DO NOTHING
|
|
|
|
|
RETURNING id
|
|
|
|
|
)
|
|
|
|
|
SELECT id FROM ensured
|
|
|
|
|
UNION ALL
|
|
|
|
|
SELECT id FROM users WHERE email = 'admin@geo.local'
|
|
|
|
|
LIMIT 1
|
2026-04-01 00:58:42 +08:00
|
|
|
`, string(hash)).Scan(&userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("insert user: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Membership
|
|
|
|
|
_, err = tx.Exec(ctx, `
|
|
|
|
|
INSERT INTO tenant_memberships (tenant_id, user_id, tenant_role)
|
|
|
|
|
VALUES ($1, $2, 'tenant_admin')
|
|
|
|
|
ON CONFLICT DO NOTHING
|
|
|
|
|
`, tenantID, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("insert membership: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Plan
|
|
|
|
|
var planID int64
|
|
|
|
|
err = tx.QueryRow(ctx, `
|
2026-04-02 00:31:28 +08:00
|
|
|
WITH ensured AS (
|
|
|
|
|
INSERT INTO plans (plan_code, name, quota_policy_json, status)
|
|
|
|
|
VALUES ('free', 'Free Plan', '{"article_generation": 100}', 'active')
|
|
|
|
|
ON CONFLICT DO NOTHING
|
|
|
|
|
RETURNING id
|
|
|
|
|
)
|
|
|
|
|
SELECT id FROM ensured
|
|
|
|
|
UNION ALL
|
|
|
|
|
SELECT id FROM plans WHERE plan_code = 'free'
|
|
|
|
|
LIMIT 1
|
2026-04-01 00:58:42 +08:00
|
|
|
`).Scan(&planID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("insert plan: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Subscription
|
|
|
|
|
_, err = tx.Exec(ctx, `
|
|
|
|
|
INSERT INTO tenant_plan_subscriptions (tenant_id, plan_id, start_at, end_at, status)
|
2026-04-02 00:31:28 +08:00
|
|
|
SELECT $1, $2, NOW(), NOW() + INTERVAL '1 year', 'active'
|
|
|
|
|
WHERE NOT EXISTS (
|
|
|
|
|
SELECT 1
|
|
|
|
|
FROM tenant_plan_subscriptions
|
|
|
|
|
WHERE tenant_id = $1
|
|
|
|
|
AND plan_id = $2
|
|
|
|
|
AND status = 'active'
|
|
|
|
|
)
|
2026-04-01 00:58:42 +08:00
|
|
|
`, tenantID, planID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("insert subscription: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Quota ledger
|
|
|
|
|
_, err = tx.Exec(ctx, `
|
|
|
|
|
INSERT INTO tenant_quota_ledgers (tenant_id, quota_type, delta, balance_after, reason)
|
2026-04-02 00:31:28 +08:00
|
|
|
SELECT $1, 'article_generation', 100, 100, 'initial_allocation'
|
|
|
|
|
WHERE NOT EXISTS (
|
|
|
|
|
SELECT 1
|
|
|
|
|
FROM tenant_quota_ledgers
|
|
|
|
|
WHERE tenant_id = $1
|
|
|
|
|
AND quota_type = 'article_generation'
|
|
|
|
|
AND reason = 'initial_allocation'
|
|
|
|
|
)
|
2026-04-01 00:58:42 +08:00
|
|
|
`, tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("insert quota: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Platform templates
|
2026-04-05 17:14:13 +08:00
|
|
|
templates := prompts.PlatformTemplateSeeds()
|
2026-04-01 00:58:42 +08:00
|
|
|
|
|
|
|
|
for _, t := range templates {
|
|
|
|
|
_, err = tx.Exec(ctx, `
|
2026-04-02 11:38:08 +08:00
|
|
|
INSERT INTO article_templates (scope, origin_type, template_key, template_name, prompt_template, prompt_visibility, card_config_json, status)
|
|
|
|
|
VALUES ('platform', 'platform', $1, $2, $3, 'visible', $4::jsonb, 'active')
|
2026-04-01 00:58:42 +08:00
|
|
|
ON CONFLICT DO NOTHING
|
2026-04-05 17:14:13 +08:00
|
|
|
`, t.Key, t.Name, t.PromptTemplate, t.CardConfigJSON)
|
2026-04-01 00:58:42 +08:00
|
|
|
if err != nil {
|
2026-04-05 17:14:13 +08:00
|
|
|
log.Fatalf("insert template %s: %v", t.Key, err)
|
2026-04-01 00:58:42 +08:00
|
|
|
}
|
2026-04-02 00:31:28 +08:00
|
|
|
|
|
|
|
|
_, err = tx.Exec(ctx, `
|
|
|
|
|
UPDATE article_templates
|
|
|
|
|
SET template_name = $2,
|
2026-04-02 11:38:08 +08:00
|
|
|
prompt_template = $3,
|
|
|
|
|
card_config_json = $4::jsonb,
|
2026-04-02 00:31:28 +08:00
|
|
|
prompt_visibility = 'visible',
|
|
|
|
|
status = 'active',
|
|
|
|
|
updated_at = NOW()
|
|
|
|
|
WHERE scope = 'platform'
|
|
|
|
|
AND template_key = $1
|
|
|
|
|
AND deleted_at IS NULL
|
2026-04-05 17:14:13 +08:00
|
|
|
`, t.Key, t.Name, t.PromptTemplate, t.CardConfigJSON)
|
2026-04-02 00:31:28 +08:00
|
|
|
if err != nil {
|
2026-04-05 17:14:13 +08:00
|
|
|
log.Fatalf("update template %s: %v", t.Key, err)
|
2026-04-02 00:31:28 +08:00
|
|
|
}
|
2026-04-01 00:58:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := tx.Commit(ctx); err != nil {
|
|
|
|
|
log.Fatalf("commit: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println("Seed data inserted successfully.")
|
|
|
|
|
fmt.Printf(" Tenant ID: %d\n", tenantID)
|
|
|
|
|
fmt.Printf(" User ID: %d (admin@geo.local / Admin@123)\n", userID)
|
|
|
|
|
fmt.Printf(" Plan ID: %d (free)\n", planID)
|
|
|
|
|
fmt.Println(" Templates: 4 platform presets")
|
|
|
|
|
}
|