refactor(tenant): drop legacy plugin_installations, migrate monitoring to desktop_clients
Hard cutover from the browser-extension plugin flow to desktop clients: remove plugin_installations/plugin_sessions tables and related service, handler, router, and generated model code; migrate monitoring quotas and collector types to desktop_clients (UUID primary_client_id); recreate platform_access_snapshots keyed by client_id; update dev-seed and callback types accordingly; mark legacy design docs as historical. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+53
-45
@@ -11,31 +11,31 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
sharedauth "github.com/geo-platform/tenant-api/internal/shared/auth"
|
||||
"github.com/geo-platform/tenant-api/internal/shared/config"
|
||||
"github.com/geo-platform/tenant-api/internal/tenant/prompts"
|
||||
"github.com/geo-platform/tenant-api/internal/tenant/repository"
|
||||
)
|
||||
|
||||
type seedState struct {
|
||||
TenantID int64
|
||||
UserID int64
|
||||
WorkspaceID int64
|
||||
TestTenantID int64
|
||||
TestUserID int64
|
||||
PlanID int64
|
||||
BrandID int64
|
||||
KeywordPrimaryID int64
|
||||
KeywordSecondaryID int64
|
||||
QuestionPrimaryID int64
|
||||
QuestionSecondaryID int64
|
||||
QuestionTertiaryID int64
|
||||
ArticleID int64
|
||||
PluginInstallationID int64
|
||||
TenantID int64
|
||||
UserID int64
|
||||
WorkspaceID int64
|
||||
TestTenantID int64
|
||||
TestUserID int64
|
||||
PlanID int64
|
||||
BrandID int64
|
||||
KeywordPrimaryID int64
|
||||
KeywordSecondaryID int64
|
||||
QuestionPrimaryID int64
|
||||
QuestionSecondaryID int64
|
||||
QuestionTertiaryID int64
|
||||
ArticleID int64
|
||||
DesktopClientID uuid.UUID
|
||||
}
|
||||
|
||||
type monitoringRunSeed struct {
|
||||
@@ -137,7 +137,7 @@ func main() {
|
||||
fmt.Printf(" Test User ID: %d (test@geo.local / Test@123)\n", state.TestUserID)
|
||||
fmt.Printf(" Plan ID: %d (free)\n", state.PlanID)
|
||||
fmt.Printf(" Brand ID: %d (轻氧口腔)\n", state.BrandID)
|
||||
fmt.Printf(" Plugin Installation ID: %d\n", state.PluginInstallationID)
|
||||
fmt.Printf(" Desktop Client ID: %s\n", state.DesktopClientID.String())
|
||||
fmt.Println(" Templates: 4 platform presets")
|
||||
fmt.Println(" Monitoring: brand daily snapshots + question runs + citation facts")
|
||||
}
|
||||
@@ -241,7 +241,7 @@ func seedBusinessData(ctx context.Context, pool *pgxpool.Pool, membershipCfg con
|
||||
return nil, err
|
||||
}
|
||||
|
||||
state.PluginInstallationID, err = ensurePluginInstallation(ctx, tx, state.TenantID, state.UserID)
|
||||
state.DesktopClientID, err = ensureDesktopClient(ctx, tx, state.TenantID, state.WorkspaceID, state.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -641,47 +641,55 @@ func ensureArticle(ctx context.Context, tx pgx.Tx, tenantID int64) (int64, error
|
||||
return articleID, nil
|
||||
}
|
||||
|
||||
func ensurePluginInstallation(ctx context.Context, tx pgx.Tx, tenantID, userID int64) (int64, error) {
|
||||
installationKey := "demo-monitoring-installation"
|
||||
tokenHash := sharedauth.HashToken("demo-monitoring-installation-token")
|
||||
func ensureDesktopClient(ctx context.Context, tx pgx.Tx, tenantID, workspaceID, userID int64) (uuid.UUID, error) {
|
||||
clientID := uuid.NewSHA1(uuid.NameSpaceOID, []byte("geo-rankly-demo-monitoring-client"))
|
||||
tokenHash := sha256.Sum256([]byte("demo-monitoring-client-token"))
|
||||
|
||||
var installationID int64
|
||||
var ensuredID uuid.UUID
|
||||
err := tx.QueryRow(ctx, `
|
||||
WITH ensured AS (
|
||||
INSERT INTO plugin_installations (
|
||||
tenant_id, user_id, installation_key, installation_name, browser_name,
|
||||
client_version, installation_token_hash, status, last_seen_at
|
||||
INSERT INTO desktop_clients (
|
||||
id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, last_seen_at
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, 'GEO Monitoring Chrome', 'Chrome',
|
||||
'0.1.0', $4, 'active', NOW()
|
||||
$1, $2, $3, $4, $5, 'GEO Monitoring Desktop', 'macOS', 'arm64', '0.1.0', 'stable', NOW()
|
||||
)
|
||||
ON CONFLICT DO NOTHING
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
SET tenant_id = EXCLUDED.tenant_id,
|
||||
workspace_id = EXCLUDED.workspace_id,
|
||||
user_id = EXCLUDED.user_id,
|
||||
token_hash = EXCLUDED.token_hash,
|
||||
device_name = EXCLUDED.device_name,
|
||||
os = EXCLUDED.os,
|
||||
cpu_arch = EXCLUDED.cpu_arch,
|
||||
client_version = EXCLUDED.client_version,
|
||||
channel = EXCLUDED.channel,
|
||||
last_seen_at = NOW(),
|
||||
revoked_at = NULL
|
||||
RETURNING id
|
||||
)
|
||||
SELECT id FROM ensured
|
||||
UNION ALL
|
||||
SELECT id
|
||||
FROM plugin_installations
|
||||
WHERE tenant_id = $1 AND installation_key = $3 AND deleted_at IS NULL
|
||||
FROM desktop_clients
|
||||
WHERE id = $1
|
||||
LIMIT 1
|
||||
`, tenantID, userID, installationKey, tokenHash).Scan(&installationID)
|
||||
`, clientID, tenantID, workspaceID, userID, tokenHash[:]).Scan(&ensuredID)
|
||||
if err != nil {
|
||||
return 0, wrapSeedErr("insert plugin installation", err)
|
||||
return uuid.Nil, wrapSeedErr("insert desktop client", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, `
|
||||
UPDATE plugin_installations
|
||||
SET status = 'active',
|
||||
installation_token_hash = $2,
|
||||
UPDATE desktop_clients
|
||||
SET token_hash = $2,
|
||||
last_seen_at = NOW(),
|
||||
updated_at = NOW()
|
||||
revoked_at = NULL
|
||||
WHERE id = $1
|
||||
`, installationID, tokenHash)
|
||||
`, ensuredID, tokenHash[:])
|
||||
if err != nil {
|
||||
return 0, wrapSeedErr("touch plugin installation", err)
|
||||
return uuid.Nil, wrapSeedErr("touch desktop client", err)
|
||||
}
|
||||
return installationID, nil
|
||||
return ensuredID, nil
|
||||
}
|
||||
|
||||
func ensureMonitoringQuota(ctx context.Context, tx pgx.Tx, state *seedState) error {
|
||||
@@ -689,20 +697,20 @@ func ensureMonitoringQuota(ctx context.Context, tx pgx.Tx, state *seedState) err
|
||||
_, err := tx.Exec(ctx, `
|
||||
INSERT INTO tenant_monitoring_quotas (
|
||||
tenant_id, workspace_id, max_brands, collection_mode, question_selection_mode, collect_frequency,
|
||||
enabled_platforms, primary_installation_id, task_daily_hard_cap, plan_tier
|
||||
enabled_platforms, primary_client_id, task_daily_hard_cap, plan_tier
|
||||
)
|
||||
VALUES ($1, $2, 1, 'plugin', 'best_effort_all', 'daily', $3::jsonb, $4, 36, 'free')
|
||||
VALUES ($1, $2, 1, 'desktop', 'best_effort_all', 'daily', $3::jsonb, $4, 36, 'free')
|
||||
ON CONFLICT (tenant_id) DO UPDATE
|
||||
SET workspace_id = COALESCE(tenant_monitoring_quotas.workspace_id, EXCLUDED.workspace_id),
|
||||
SET workspace_id = EXCLUDED.workspace_id,
|
||||
collection_mode = EXCLUDED.collection_mode,
|
||||
question_selection_mode = EXCLUDED.question_selection_mode,
|
||||
collect_frequency = EXCLUDED.collect_frequency,
|
||||
enabled_platforms = EXCLUDED.enabled_platforms,
|
||||
primary_installation_id = EXCLUDED.primary_installation_id,
|
||||
primary_client_id = EXCLUDED.primary_client_id,
|
||||
task_daily_hard_cap = EXCLUDED.task_daily_hard_cap,
|
||||
plan_tier = EXCLUDED.plan_tier,
|
||||
updated_at = NOW()
|
||||
`, state.TenantID, state.WorkspaceID, string(enabledPlatforms), state.PluginInstallationID)
|
||||
`, state.TenantID, state.WorkspaceID, string(enabledPlatforms), state.DesktopClientID)
|
||||
return wrapSeedErr("upsert monitoring quota", err)
|
||||
}
|
||||
|
||||
@@ -799,11 +807,11 @@ func insertPlatformAccessSnapshots(ctx context.Context, tx pgx.Tx, state *seedSt
|
||||
for _, item := range entries {
|
||||
if _, err := tx.Exec(ctx, `
|
||||
INSERT INTO monitoring_platform_access_snapshots (
|
||||
tenant_id, installation_id, ai_platform_id, business_date, access_status,
|
||||
tenant_id, client_id, ai_platform_id, business_date, access_status,
|
||||
connected, accessible, detected_at, reason_code, reason_message
|
||||
)
|
||||
VALUES ($1, $2, $3, $4::date, $5, $6, $7, NOW(), $8, $9)
|
||||
`, state.TenantID, state.PluginInstallationID, item.PlatformID, businessDate, item.AccessStatus, item.Connected, item.Accessible, item.ReasonCode, item.ReasonMessage); err != nil {
|
||||
`, state.TenantID, state.DesktopClientID, item.PlatformID, businessDate, item.AccessStatus, item.Connected, item.Accessible, item.ReasonCode, item.ReasonMessage); err != nil {
|
||||
return wrapSeedErr("insert platform access snapshot", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user