Files
descrybe/docs/full-app-qa-report.md
T
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

14 KiB

Full app QA report (Descrybe v2)

Date: 2026-08-04
Repo: f:/laragon/www/_MY/descrybe-v2
Wave: 20 parallel agents (credits, analytics, Stripe, tutorial, SEO copy, Woo, E2E, Free tier, settings, products, catalog, admin/API, security, dashboard, processing, exports, nav) + final reconcile
Build gates (reconcile): go build ./...PASS · npm run check (apps/web) → 0 errors / 0 warnings


Executive summary

The 20-agent QA wave is complete. Descrybe v2 is green to demo locally: credits and analytics now read the live wallet (no more stale cycle inflation), Stripe Checkout works in mock (STRIPE_MOCK=true) and is ready for real keys, the in-app tutorial is forced-on-actions but skippable, Woo has a seed path without a live shop, and both catalog and marketing E2E suites passed.

Local Demo Co is back on Enterprise after mock Stripe checkout temporarily assigned a paid self-serve plan — restored to ~1M AI credits / Unlimited packaging for continued demo use.

You want… Status
Demo the product end-to-end Ready — login below
Buy a plan in prod Set Stripe env (see § Stripe)
Connect a real Woo store UI /woocommerce or WOO_* env (see § Woo)
Try Woo audiences without WP make seed-woo / seed-woo-demo

Still not production-cutover: FTP feed sync, daily credit ledger, live Stripe/Woo untested in this wave, and cutover gates in cutover.md.


Demo login (use this)

Email demo@descrybe.local (alias demo@descrybe.test also works)
Password DemoPass123!
Company Local Demo Co (ee246275-dec0-4446-9e83-58d0c16c258a)
Plan Enterprise · ~1,000,000 AI credits · can_use_ai=true (restored after mock Stripe)
Platform admin yes
Web http://127.0.0.1:5174/login
API http://127.0.0.1:8080
Docs http://127.0.0.1:5174/docs
Demo API key dk_demo_local_descrybe_test_key_v1

Do not use this account or key in production. Details: demo-user.md.


Executive matrix

Area Verdict Evidence doc
Credits / billing PASS (bugs fixed) billing-credits-audit.md
Analytics / usage PASS (bugs fixed) analytics-audit.md
Stripe Checkout / portal / webhooks PASS (mock + real path; demo Enterprise restored after mock) stripe-setup.md
Free tier gates PASS free-tier-verify.md · free-tier.md
Tutorial (forced + skippable) PASS tutorial.md
SEO / marketing copy PASS sibling SEO pass + /pricing polish
WooCommerce PASS (seed path; live optional) woocommerce-demo.md
E2E feeds → process → export PASS e2e-feeds-process-export.md
E2E marketing (brand/SEO/campaign/email) PASS e2e-marketing.md
Processing UI PASS e2e-processing.md
Admin / health / public API PASS 20/20 api-surface-smoke.md
Security (Stripe webhook / SSRF) PASS (hardened) security-notes.md
Settings / API keys / invites PASS sibling settings QA
Products / categories / attributes PASS (UX fixes) siblings
Export public URLs PASS sibling export QA
AI (Green Chat LAN) PASS when :8767 open ai-full-smoke.md · green-chat-smoke.md

1. Credits & billing

Verdict: Demo Enterprise wallet and Billing UI agree: 1,000,000 remaining / 0 used. Free grants 0 AI credits.

What was wrong

  1. /api/billing/usage preferred stale billing_cycles rows → showed e.g. 22 credits used while wallet was 1M/0.
  2. Campaign AI swallowed ConsumeCredits errors (silent free AI).
  3. SEO AI only checked CanUseAI (true on paid with empty wallet).
  4. Billing page fake date-range + false “Out of credits” on Free.

Fixes

  • UsageSummary always uses live credit_balances for credits; range filters products/tokens only.
  • AssignPlan closes open cycles and opens a fresh cycle; ConsumeCredits updates only open cycles.
  • Campaign/SEO require RemainingCredits ≥ 1; debit after AI; map insufficient → 402.
  • Billing UI: real ?range=, Free info banner, used/total + Enterprise “Unlimited” label.

Smoke

CREDITS plan=Enterprise total=1000000 used=0 rem=1000000
USAGE   matches /auth/me
AFTER_FREE → rem=0 can_use_ai=false
AFTER_ENT  → rem=1000000

Full write-up: billing-credits-audit.md.


2. Analytics & usage

Verdict: Tenant + admin meters match live Postgres for Local Demo Co.

Meter API DB
Wallet used / total 0 / 1_000_000 match
Products (all) ~4326 match
Input / export feeds 12 / 5 match
Plan cycle Aug → Sep 2026 company_plans

Admin analytics now includes feed counts and real ai_provider_mode rollups (after API rebuild). Details: analytics-audit.md.


3. Stripe (purchase path)

Verdict: Checkout + Customer Portal + signed webhooks implemented. Local works in mock without a Stripe account.

Configure for real

  1. Set in root .env (never commit secrets; placeholders in .env.example):
Variable Purpose
STRIPE_SECRET_KEY sk_test_… / sk_live_…
STRIPE_WEBHOOK_SECRET whsec_…
STRIPE_MOCK false for live
STRIPE_PRICE_STARTER_MONTHLY / _YEARLY Price IDs
STRIPE_PRICE_GROWTH_MONTHLY / _YEARLY Price IDs
STRIPE_PRICE_BUSINESS_MONTHLY / _YEARLY Price IDs
WEB_ORIGIN e.g. https://app.example.com (Checkout return URLs)
  1. Stripe Dashboard: Products + Prices for Starter / Growth / Business; enable Customer Portal.
  2. Webhook → https://<api-host>/api/webhooks/stripe
    Events: checkout.session.completed, customer.subscription.created|updated|deleted.
  3. Local: stripe listen --forward-to localhost:8080/api/webhooks/stripe → paste whsec_….
  4. Apply migration 016_stripe_billing.sql (pwsh -File scripts/migrate.ps1), restart API.

Mock local QA

STRIPE_MOCK=truePOST /api/billing/checkout assigns plan + credits and returns mock:true. Empty secret alone no longer free-upgrades (security harden).

Note: Mock checkout on Local Demo Co temporarily moved the tenant off Enterprise (e.g. to Starter). Enterprise was restored afterward so demo stays on ~1M credits / Unlimited. Re-run go run ./cmd/seed-demo (or admin AssignPlan Enterprise) if mock Checkout is used again on the demo company.

Enterprise stays sales-led (no self-serve price). UI: /plans, /billing. Full guide: stripe-setup.md.


4. WooCommerce

Verdict: Product push + orders/reviews pull + campaign audiences work. Live shop optional; seed path covers demo without WordPress.

Configure for real

  1. WooCommerce → Settings → Advanced → REST API → Read/Write key.
  2. Descrybe /woocommerce → enable sync → Store URL + ck_… / cs_… → Save → Test Connection.
  3. Queue product sync, then Orders / Reviews; keep worker running.
  4. Optional env (or UI only): WOO_STORE_URL, WOO_CONSUMER_KEY, WOO_CONSUMER_SECRET
    (aliases WOOCOMMERCE_* also work). Encrypt at rest needs CREDENTIALS_ENCRYPTION_KEY.
  5. SSRF: http allowed only for localhost/loopback; remote shops need https (or tunnel).

No live shop?

cd apps/api
$env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable"
go run ./cmd/seed-woo-demo -postgres $env:DATABASE_URL -company "Local Demo Co"
# or: make seed-woo

Seeds Demo Electronics products, 4 orders, 3 reviews, draft “purchased” campaign. Details: woocommerce-demo.md.


5. Tutorial

Verdict: Forced action tour with Skip / Pause / Resume / Restart. No free Continue on action steps.

  • Progress: localStorage key descrybe.tutorial.v2
  • 15 steps: welcome → standard fields → feeds map/auto-map/save/sync-sample → products → export → campaigns → done
  • Advance only on real clicks (data-tour) or successful tutorial.reportAction(…)
  • Header + dashboard: Start / Resume / Restart

Manual checklist: tutorial.md.


6. E2E results

Feeds → map → process → export — PASS

Check Result
12 input feeds mapped PASS
Process job 5/5 steps PASS (worker required)
Export XML/CSV generate PASS (~4322 products)
Public token downloads PASS
Mapping PUT nested {key,mapping} Fixed this wave

FTP/FTPS supplier sync still 400 (not supported). Migrated data already present so process/export work without re-sync. Details: e2e-feeds-process-export.md.

Marketing (brand / SEO / campaign / email / calendar) — PASS (14/14)

Against Green Chat overloaded-local @ 192.168.50.181:8767:

Step Result
Brand kit PUT/GET + tips PASS
SEO mode=ai PASS (~1s, brand terms, credits charged)
Campaign mode=ai + template PASS
Email / campaign dry_run PASS
Calendar prepare Black Friday PASS (path fix: /api/marketing/calendar/prepare)

Details: e2e-marketing.md.

Processing UI — PASS

Create → cancel (steps marked cancelled) → enhance_only via Green Chat (~1s). /tasks → 307 /processing. Details: e2e-processing.md.

Free tier (while demo is Enterprise) — PASS

New register → Free / 0 credits / can_use_ai=false; AI-only jobs → 402; normalize/full still runs with AI/EPREL skipped. Demo remains Enterprise. Details: free-tier-verify.md.

Admin / health / public API — PASS 20/20

Platform admin routes, /healthz /readyz, RapiDoc docs, OpenAPI, v1 CRUD smoke + 401 without key. Details: api-surface-smoke.md.


7. Other sibling fixes (this wave)

Area Outcome
Security Stripe webhook always verified when STRIPE_WEBHOOK_SECRET set; mock purchases need explicit STRIPE_MOCK; generic webhook errors; SSRF notes in security-notes.md
Billing / Plans UI Enterprise shows Unlimited; Checkout CTAs; no false Free out-of-credits banner
Dashboard Clear CTAs (tutorial / process / feeds / BF); clickable credit widgets; dead upload section removed
SEO / copy Plain ecommerce voice; SeoHead on privacy/terms/features; clearer empty states
Products Search includes processed/raw names; CSV ingest via Feeds only; server-side sort
Categories / attributes Attributes default roots=1; formula 404 UX fixed
Settings API keys CRUD, invites, email link; Copy Key no longer copies useless prefix
Export feeds Public routes mounted before session auth (401→404/405); absolute public URLs in UI
Nav / a11y / tutorial targets data-tour preserved for tour

8. Known gaps

Gap Notes
No daily credit ledger Usage range filters products/tokens only; credit burn is wallet-level
FTP/FTPS feed sync Not supported; sync returns 400 for those supplier URLs
Stripe live untested in this wave Mock + unit/integration coverage; real Checkout needs keys above
Live Woo optional Seed covers audiences; live sync needs a real store + worker
Email delivery Prefer force_dry_run / EMAIL_DRY_RUN; stub SMTP test fails without a real listener
Cutover / production Staging data OK; production cutover still blocked — see cutover.md · go-live-checklist.md
Migrated tenants May hold legacy wallets; entitlements treat empty plan as Free-with-leftover-credits
Campaign/SEO charge after LLM Wallet gated first; mid-flight race can still burn tokens then fail debit
Structured-descriptions / vector-categories UI shells exist; backend still partial (status-and-gaps.md)
CI Makefile + unit tests; no GitHub Actions yet

9. How to re-verify locally

# Postgres
cd f:\laragon\www\_MY\descrybe-v2
docker compose up -d   # :5433

# Build gates
cd apps\api; go build ./...
cd ..\web; npm run check

# Runtime (separate terminals)
# scripts\run-api.ps1   → API :8080
# make worker / go run ./cmd/worker
# make web              → :5174

# Login
# demo@descrybe.local / DemoPass123!

Spot-check:

  1. /billing → 1M remaining, usage matches wallet
  2. /plans → Upgrade (mock Checkout if STRIPE_MOCK=true)
  3. Start tutorial → action steps have no Continue
  4. /feeds → map → /processing/export-feeds generate
  5. /campaigns + /seo AI (needs Green Chat + OPENAI_*)
  6. /woocommerce or make seed-woo → orders/reviews + audience

Doc Topic
billing-credits-audit.md Credits correctness
analytics-audit.md Usage / admin analytics
stripe-setup.md Stripe real + mock
woocommerce-demo.md Woo live + seed
tutorial.md Guided tour
e2e-feeds-process-export.md Catalog pipeline E2E
e2e-marketing.md Marketing AI E2E
e2e-processing.md Background tasks
free-tier-verify.md Free vs Enterprise proof
api-surface-smoke.md Admin / docs / v1
demo-user.md Credentials
security-notes.md AuthZ / webhooks / SSRF
status-and-gaps.md Broader product gaps
ai-full-smoke.md Green Chat AI matrix