Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
9.6 KiB
Migrate descrybe_new.sql → v2 Postgres (A1 only)
Date: 2026-08-08 (local reseed from descrybe_new (1).sql)
Status: PASS
Scope: Single tenant A1 Slovenija only (all other dump tenants skipped / cleaned)
Secrets are masked below. Do not commit .env, MySQL passwords, artifacts/, or invite tokens.
What “a1” resolved to
| Field | Value |
|---|---|
| MySQL company name | A1 Slovenija |
MySQL / legacy company_id |
97e1a309-3d23-4aa2-b518-8e8d7afdfec7 |
| Match used | companies.name LIKE %A1% → exact row above (only A1 hit) |
| Postgres after migrate + demo | A1 Slovenija (dump name kept) |
Postgres companies.id |
604f23a8-b66e-4b21-8b45-0d72b68f4790 (stable via artifacts/descrybe-new-a1/id-map.json) |
legacy_company_id |
97e1a309-3d23-4aa2-b518-8e8d7afdfec7 |
Company naming: Keep dump name A1 Slovenija. Do not rename to “Local Demo Co”. Wallet/plan come from MySQL credit_balances / plan A1 (2500 total / 163 used / 2337 remaining on 2026-08-08 dump) — not a fake 1M demo pack.
Inputs
| Item | Value |
|---|---|
| Dump | C:\Users\Green Eclipse\Downloads\descrybe_new (1).sql (~549 MB Adminer MySQL 8 dump) |
| Temp MySQL DB | Laragon descrybe_new (left intact; did not overwrite descrybe_v2) |
| Postgres | Docker descrybe-v2-postgres host port 5433 |
| Postgres DSN (local default) | postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable |
| Migrator | apps/api/cmd/migrator |
| Maps / report | artifacts/descrybe-new-a1/ (gitignored); copy docs/migration-reports/migration-report-a1-latest.json |
Commands run
1. Wipe v2 Postgres only (keep Docker volume)
docker exec descrybe-v2-postgres psql -U descrybe -d postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'descrybe' AND pid <> pg_backend_pid();"
docker exec descrybe-v2-postgres psql -U descrybe -d postgres -c "DROP DATABASE IF EXISTS descrybe;"
docker exec descrybe-v2-postgres psql -U descrybe -d postgres -c "CREATE DATABASE descrybe OWNER descrybe;"
2. Goose migrations (001–024)
cd f:\laragon\www\_MY\descrybe-v2\apps\api
$env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable"
go run github.com/pressly/goose/v3/cmd/goose@v3.24.3 -dir sql/schema postgres $env:DATABASE_URL up
Note: 024_ai_prompts.sql had a UTF-8 BOM (\ufeff); stripped so goose could parse (same class of fix as earlier 006_feed_sync.sql).
3. Import dump into temp MySQL (streamed; ~2 min)
# create empty DB, then stream file into mysql client (do not load 862MB into PowerShell)
mysql -uroot -p**** -e "DROP DATABASE IF EXISTS descrybe_new; CREATE DATABASE descrybe_new CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# stdin stream of descrybe_new.sql → descrybe_new
Dump-wide MySQL counts (before filter): companies 31, categories 8465, attributes 198319, xml_feeds 33, raw_products 159070, processed_products 7953, export_feeds 11.
4. A1-only migrator
cd f:\laragon\www\_MY\descrybe-v2\apps\api
$env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable"
$env:MIGRATE_MYSQL_DSN = "root:****@tcp(localhost:3306)/descrybe_new?parseTime=true"
$maps = "f:\laragon\www\_MY\descrybe-v2\artifacts\descrybe-new-a1"
$a1 = "97e1a309-3d23-4aa2-b518-8e8d7afdfec7"
go build -o $env:TEMP\descrybe-migrator.exe ./cmd/migrator
# dry-run then live (filter at migrate time)
& $env:TEMP\descrybe-migrator.exe -mysql $env:MIGRATE_MYSQL_DSN -postgres $env:DATABASE_URL `
-company $a1 -dry-run -maps-dir $maps -report-dir $maps -resume=false
& $env:TEMP\descrybe-migrator.exe -mysql $env:MIGRATE_MYSQL_DSN -postgres $env:DATABASE_URL `
-company $a1 -maps-dir $maps -report-dir $maps -resume `
-ensure-demo -demo-email demo@descrybe.local -demo-password 'DemoPass123!' `
-skip-post-import
Live elapsed ≈ 32s. Validation: mode: live ok=true, orphan checks 17/17 PASS.
5. Seed demo (Enterprise + API key + .test alias)
go run ./cmd/seed-demo -postgres $env:DATABASE_URL `
-email demo@descrybe.local -password 'DemoPass123!'
6. Post-cleanup (junk from global user import)
Migrator still upserts all MySQL profile→user rows even with -company (memberships are filtered). Removed users with no membership (kept demo emails):
DELETE FROM users u
WHERE NOT EXISTS (SELECT 1 FROM memberships m WHERE m.user_id = u.id)
AND lower(u.email) NOT IN ('demo@descrybe.local','demo@descrybe.test');
-- deleted 22 orphan users
6b. Import A1 job history (optional follow-up)
Job history was skipped in the initial cutover. Re-run with domain jobs (rows tagged ai_provider_mode=migrated so 30-day retention does not purge them):
& $env:TEMP\descrybe-migrator.exe -mysql $env:MIGRATE_MYSQL_DSN -postgres $env:DATABASE_URL `
-company $a1 -domains jobs -maps-dir $maps -report-dir $maps -resume -skip-post-import
Local/dev (outdated — do not follow): demo no longer owns A1; use Platform Demo + a1-primary@ per safe-test-fixtures.md. Historical logins:
| Role | Password | |
|---|---|---|
| Demo admin | demo@descrybe.local (alias .test) |
DemoPass123! |
| Primary A1 | a1-primary@descrybe.local |
DemoPass123! |
Primary maps to Clerk user_30AqqJ8uepxvPUzDSqy81U5w6Ll. Other A1 MySQL profiles were removed after migrate (jobs reassigned to primary). To reset the primary password:
go run ./cmd/migrator -postgres $env:DATABASE_URL `
-set-password 'a1-primary@descrybe.local:DemoPass123!'
6c. Local Demo Co user cleanup (2026-08-05)
MySQL A1 (97e1a309-…) had 5 profiles.user_id values. Preference: keep demo + primary only.
| Action | Detail |
|---|---|
| Kept | demo@descrybe.local, demo@descrybe.test, a1-primary@descrybe.local (user_30AqqJ…) |
| Deleted (4) | user_2tJxu…, user_2yaUP…, user_2zzh…, user_3005r… (@legacy.local) |
| Reassigned | 3 processing_jobs.user_id → primary (280 jobs on primary; 51 still null) |
| Catalog | Unchanged — 4378 processed products, 331 jobs |
Do not restore those four @legacy.local members. A later agent re-inserted them for switcher labeling; they were deleted again. Local Demo Co stays at 3 users / 3 memberships. UserSwitcher labels: Demo admin (.local + .test) and A1 · …81U5w6Ll (is_primary_a1).
Row counts — kept vs skipped
Migrator written (A1 filter)
| Entity | Written / kept | Notes |
|---|---|---|
| companies | 1 | Only A1; renamed → Local Demo Co |
| memberships | 5 → 3 after cleanup | A1 primary + 2 demo admins |
| users (after cleanup) | 3 | demo .local + demo .test + a1-primary@descrybe.local |
| plans | seed + migrated catalog | Global plan rows OK for local billing |
| company_plans | 1 → Enterprise via seed-demo | Other tenants’ plans skipped |
| credit_balances | 1 | 1M Enterprise credits after seed |
| categories | 119 | |
| attributes | 303 | |
| category_attributes | 307 | |
| custom_variables | 3 | |
| input_feeds (xml) | 12 | |
| feed_mappings | 11 | ComTrade has 0 mappings in source too |
| raw_products | 23748 | MySQL A1 had 56132; GTIN-deduped under (company_id, gtin) |
| processed_products | 4330 | |
| export_feeds | 2 | |
| files | 0 | Dump had 1 file metadata row for another context / skipped |
| processing_jobs | 179 | via -domains jobs (ai_provider_mode=migrated) |
Skipped (other tenants / noise)
| Item | Approx. skipped |
|---|---|
| Other companies | 30 of 31 |
| Non-A1 categories / attributes / feeds / products / exports | Rest of dump (see MySQL totals above) |
| Orphan users after cleanup | 22 |
company_plans for non-A1 |
4 skipped in migrator log |
credit_balances for non-A1 |
7 skipped |
| API keys / Clerk passwords / job history | Never imported |
Final Postgres snapshot (A1 Slovenija — 2026-08-08)
| Metric | Count |
|---|---|
| companies | 1 (+ __platform_settings__) |
| users | 3 (demo.local, demo.test, a1-primary) |
| memberships | 3 |
| categories | 119 (108 with AI prompts overlay) |
| attributes | 303 |
| category_attributes | 307 |
| input_feeds | 12 |
| feed_mappings | 11 |
| raw_products | 23748 |
| processed_products | 4330 |
| export_feeds | 2 |
| processing_jobs | 179 |
| custom_variables | 3 |
| wallet | 2500 / 163 used / 2337 remaining |
Demo admin (local only)
| Field | Value |
|---|---|
demo@descrybe.local (alias demo@descrybe.test) |
|
| Password | DemoPass123! (already documented in docs/demo-user.md) |
| Role | Platform admin + company admin on Local Demo Co |
| Plan | Enterprise — 1_000_000 AI credits, unlimited SKUs |
| API key | dk_demo_local_descrybe_test_key_v1 (hash only in DB) |
Web: http://localhost:5174/login · API: http://localhost:8080
Verification (this run)
| Check | Result |
|---|---|
GET /healthz |
ok |
GET /readyz |
database ok |
POST /api/auth/login (CSRF cookie + Origin) |
200 → company Local Demo Co |
GET /api/v1/products?limit=1 (demo API key) |
200, meta.total=4378 |
GET /api/v1/feeds |
200, 12 feeds |
Related docs
- portable-mysql-pg-migration.md — migrator flags / domains
- demo-user.md — demo credentials & Enterprise wallet
- migration-run-log.md — prior full-tenant rehearsal
- Report: migration-reports/migration-report-a1-latest.json