Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
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)
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
/api/billing/usagepreferred stalebilling_cyclesrows → showed e.g. 22 credits used while wallet was 1M/0.- Campaign AI swallowed
ConsumeCreditserrors (silent free AI). - SEO AI only checked
CanUseAI(true on paid with empty wallet). - Billing page fake date-range + false “Out of credits” on Free.
Fixes
UsageSummaryalways uses livecredit_balancesfor credits; range filters products/tokens only.AssignPlancloses open cycles and opens a fresh cycle;ConsumeCreditsupdates 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
- 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) |
- Stripe Dashboard: Products + Prices for Starter / Growth / Business; enable Customer Portal.
- Webhook →
https://<api-host>/api/webhooks/stripe
Events:checkout.session.completed,customer.subscription.created|updated|deleted. - Local:
stripe listen --forward-to localhost:8080/api/webhooks/stripe→ pastewhsec_…. - Apply migration
016_stripe_billing.sql(pwsh -File scripts/migrate.ps1), restart API.
Mock local QA
STRIPE_MOCK=true → POST /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
- WooCommerce → Settings → Advanced → REST API → Read/Write key.
- Descrybe
/woocommerce→ enable sync → Store URL +ck_…/cs_…→ Save → Test Connection. - Queue product sync, then Orders / Reviews; keep worker running.
- Optional env (or UI only):
WOO_STORE_URL,WOO_CONSUMER_KEY,WOO_CONSUMER_SECRET
(aliasesWOOCOMMERCE_*also work). Encrypt at rest needsCREDENTIALS_ENCRYPTION_KEY. - SSRF:
httpallowed 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:
localStoragekeydescrybe.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 successfultutorial.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:
/billing→ 1M remaining, usage matches wallet/plans→ Upgrade (mock Checkout ifSTRIPE_MOCK=true)- Start tutorial → action steps have no Continue
/feeds→ map →/processing→/export-feedsgenerate/campaigns+/seoAI (needs Green Chat +OPENAI_*)/woocommerceormake seed-woo→ orders/reviews + audience
10. Related docs index
| 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 |