# QA — Local Demo Co > **Outdated naming:** `demo@` now lands on **Platform Demo**, not Local Demo Co / A1. Canonical isolation: [safe-test-fixtures.md](safe-test-fixtures.md). Treat checklist counts/company ids below as a historical snapshot. Local smoke checklist for Descrybe v2 after migrate + `seed-demo`. ## Login | | | |---|---| | Web | http://localhost:5174/login | | API | http://localhost:8080 | | Email | `demo@descrybe.local` | | Password | `DemoPass123!` | After login you should land on **Platform Demo** (not A1). For A1 catalog use `a1-primary@descrybe.local`. See [safe-test-fixtures.md](safe-test-fixtures.md). Re-seed: ```powershell cd apps/api $env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable" go run ./cmd/seed-demo -postgres $env:DATABASE_URL ``` ## What should appear | Area | Expect | |------|--------| | **Dashboard** | Welcome / tutorial entry; company = Local Demo Co | | **Products** | Catalog for Local Demo Co (~**4323** processed). If the Processed tab looks empty, switch to **Unprocessed** (or wait for auto-fallback). Raw inventory can show ~**23744** (or ~5640 on a thinner tenant) depending on the query — confirm company id `ee246275-…` | | **Feeds** | ~**12** input feeds with mappings (~**11** mapping rows) | | **Categories / attributes** | Taxonomy present (~120 categories on Local Demo Co; 303 attributes) | | **Export feeds** | ~2 export feeds | | **Uploads (`/files`)** | List of CSV uploads after imports | | **Brand kit (`/brand`)** | Form + **logo file upload** (PNG/JPEG/WebP) and/or logo URL | | **Marketing** | Campaigns, Content Calendar (`/marketing/calendar`), SEO, Reviews (→ Woo reviews tab) | | **Search** | Products accept `q` or `search`; `feed_id` filters work | ## Nav status (local) All primary sidebar routes should return **200** (no 404s): `/dashboard`, `/products`, `/files`, `/categories`, `/attributes`, `/standard-fields`, `/feeds`, `/export-feeds`, `/woocommerce`, `/campaigns`, `/marketing/calendar`, `/seo`, `/brand`, `/processing`, `/billing`, `/settings`, `/integrations/email`, `/admin` (admin only). | Path | Notes | |------|--------| | `/reviews` | **307** → `/woocommerce?tab=reviews` (intentional alias) | | `/processing` | **200** — Background Tasks UI; jobs load client-side from `GET /api/processing/jobs` (empty list is fine) | ## Uploads (verified) | Action | How | |--------|-----| | Product CSV | Dashboard **Upload CSV**, or `/products` upload UI; `POST /api/products/upload` (aliases: `/import`, `/upload-eans`) | | Category CSV | `/categories` upload UI; `POST /api/categories/upload` | | Attribute CSV | `/attributes` upload UI; `POST /api/attributes/upload` | | Upload history | `/files` | | Brand logo | `/brand` → Upload logo; `POST /api/brand/logo` | ## Tips from recent fixes 1. **Empty Products UI** — default Processed tab can look empty while Unprocessed/raw has data. UI now auto-falls back to unprocessed when processed is empty; still use **Unprocessed** if you see zero rows. 2. **API restart** — after marketing/route changes, **rebuild and restart the Go API** or smoke checks can show stale 404s. 3. **Counts** — prefer SQL on company `ee246275-dec0-4446-9e83-58d0c16c258a`. Processed ≈ 4321; raw ≈ 23742. Do not confuse with the empty `Local Demo Co (empty)` shell from `seed-local.ps1`. ## Verify commands ```powershell cd apps/api; go build ./... cd ../web; npm run check ``` ```sql SELECT name, id FROM companies WHERE id = 'ee246275-dec0-4446-9e83-58d0c16c258a'; -- Local Demo Co SELECT (SELECT COUNT(*) FROM processed_products WHERE company_id = 'ee246275-dec0-4446-9e83-58d0c16c258a') AS processed, (SELECT COUNT(*) FROM raw_products WHERE company_id = 'ee246275-dec0-4446-9e83-58d0c16c258a') AS raw, (SELECT COUNT(*) FROM input_feeds WHERE company_id = 'ee246275-dec0-4446-9e83-58d0c16c258a') AS feeds, (SELECT COUNT(*) FROM feed_mappings WHERE company_id = 'ee246275-dec0-4446-9e83-58d0c16c258a') AS mappings; ``` ## Known limits - Free-tier AI / real email blasts gated (demo company is on **Growth** via seed-demo). - Public `/marketing` root is not a page; use `/campaigns`, `/marketing/calendar`, `/seo`, `/brand`. - Stripe self-serve checkout not live; `/plans` is in-app billing UI. - Restart API after backend route changes before trusting smoke 404 results. ## Related - [e2e-feeds-process-export.md](e2e-feeds-process-export.md) — feeds → map → process → export E2E - [demo-user.md](demo-user.md) — credentials + company table - [api-surface-smoke.md](api-surface-smoke.md) — admin, healthz/readyz, /docs, public API v1 - [marketing-suite-user-guide.md](marketing-suite-user-guide.md) — campaigns / brand / SEO paths - [free-tier.md](free-tier.md) — Free vs paid gates - [live-feed-csv.md](live-feed-csv.md) — Add Feed URL + CSV live test