bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
497 lines
27 KiB
Markdown
497 lines
27 KiB
Markdown
# quiXzoom — User Journey Audit
|
||
**Datum:** 2026-06-16
|
||
**Testad av:** Automatiserad subagent — faktiska HTTP-anrop + källkodsläsning
|
||
**Miljö:** Production (api.quixzoom.com, www.quixzoom.com, app.quixzoom.com, S3-buckets)
|
||
|
||
---
|
||
|
||
## Sammanfattning
|
||
|
||
quiXzoom har en fungerande teknisk stomme: landningssidan rankar synligt i sökning, registrerings-API:et fungerar och returnerar token direkt, KYC-pipelinen är byggd, och Stripe Connect-länken existerar. Men **resan från Google till aktiv Zoomer är bruten på minst fyra kritiska punkter:** waitlist-endpointen ger DB-fel och tar inte emot e-poster, `/me`-endpointen (onboarding-guiden) kraschar med ett databaskolumnfel, landningssidans enda CTA ("Register interest") leder aldrig till app-registrering utan till en väntlista, och det saknas fullständigt länk från landningssidan till app.quixzoom.com. Språkblandning (svenska i sökordssnippet, engelska i allt content) skapar dessutom förvirring. Plattformen kan inte ta emot Zoomers på ett funktionellt sätt idag.
|
||
|
||
---
|
||
|
||
## Poäng per steg
|
||
|
||
| Steg | Område | Status | Betyg (1–5) |
|
||
|------|--------|--------|-------------|
|
||
| 1 | Google Discovery | Syns, men på position ~5 för "tjäna pengar foton Sverige". Snippet är bra. | 3/5 |
|
||
| 2 | Landing page (www) | Stark design, tydlig hero. CTA leder bara till väntlista, inte till registrering. Mobilnavbar dold. | 3/5 |
|
||
| 3 | For Organisations | Välgjord, tydlig. Saknar pris-CTA, form oklart var den skickar. | 3/5 |
|
||
| 4 | Registration/join-flödet | **Brutet.** CTA leder till väntlista. Ingen länk till app. /join → /auth redirect finns i appen men saknas på www. | 1/5 |
|
||
| 5 | API — registration endpoint | Fungerar. POST /api/qz/auth/register returnerar token. | 4/5 |
|
||
| 6 | API — `/me` onboarding-status | **Kraschar.** `column u.total_earned does not exist` → 401 med DB-felmeddelande. | 1/5 |
|
||
| 7 | Waitlist-endpoint | **DB-fel.** POST /api/qz/waitlist returnerar `{"error":"Database error","code":"DB_ERROR"}`. | 1/5 |
|
||
| 8 | KYC-flödet | Välbyggt tekniskt (SFace MRZ+biometri+challenge). Men oklar UX — när triggas det? | 3/5 |
|
||
| 9 | Zoomer-appen (app.quixzoom.com) | PWA finns, manifest finns. Men ingen App Store/Google Play-länk. Landningssidan nämner "App Store Coming August 2026" och "Google Play Coming August 2026" men inga faktiska länkarna finns ännu. | 2/5 |
|
||
| 10 | E-postflöde — välkomstmail | Välkomstmail finns i waitlist-koden (AWS SES, nio språk). Men är inaktivt pga DB-felet. Registrerings-API saknar helt välkomstmail. | 2/5 |
|
||
|
||
---
|
||
|
||
## Steg 1 — Google Discovery
|
||
|
||
### Nuläge
|
||
|
||
Sökning "tjäna pengar foton Sverige" (DuckDuckGo/Bing-baserad): quiXzoom dyker upp som **result #5** (organiskt, efter 2 betalda annonser och 2 stockfoto-guider). Titel och snippet ser ut såhär:
|
||
|
||
> **quiXzoom — Tjäna pengar på foton | Bli Zoomer i Sverige**
|
||
> `www.quixzoom.com`
|
||
> *Tjäna pengar på dina smartphonefoton. quiXzoom betalar per uppdrag — fotografera infrastruktur, natur och stadsmiljöer nära dig. Starta gratis, betalt varje måndag.*
|
||
|
||
Sökning "earn money taking photos": quiXzoom dyker **inte upp** i de 8 första resultaten (internationella plattformar som Shutterstock, Foap, Ivueit dominerar).
|
||
|
||
Sökning "quiXzoom" direkt: Visas på position 1. Övrigt innehåll är Wavult Group / Wavult OS — ingen förvirring med videokonferensverktyget Zoom.
|
||
|
||
Sökning "crowdsourced field data collection": quiXzoom dyker **inte upp** alls.
|
||
|
||
### Problem
|
||
|
||
1. **Metadata saknar `<html lang="...">` i appen (app.quixzoom.com)** — `<html>` utan lang-attribut. Kan påverka crawling och accessibility.
|
||
2. **OG-image existerar** (HTTP 200, 17 KB JPEG) — bra. Men `twitter:image` och `og:image` pekar på `https://www.quixzoom.com/og-image.jpg` medan appen pekar på samma. Ingen separat app-OG-bild.
|
||
3. **Ingen hreflang för svenska** på landningssidan — `<html lang="">` och inga `<link rel="alternate" hreflang="sv">`. Google kan inte förstå att sidan är riktad mot Sverige.
|
||
4. **Sökordssnippet säger "betalt varje måndag"** — den texten finns inte i hero-sektionen på sidan ("Payment per approved mission, direct to your bank account"). Diskrepans kan sänka CTR-kvaliteten och trovärdigheten när besökaren landar.
|
||
5. **Ingen backlink-strategi synlig** — quiXzoom nämns inte i de listor och guider ("11 Apps That Pay You to Take Pictures", etc.) som toppar söket. Konkurrenter Ivueit/Foap är väletablerade.
|
||
|
||
### Förslag
|
||
|
||
- Lägg till `<html lang="sv">` (eller `lang="en"` beroende på sidas primärspråk) på www och app.
|
||
- Lägg till `<link rel="alternate" hreflang="sv" href="https://www.quixzoom.com/">` och `hreflang="x-default"`.
|
||
- Synkronisera meta-description med faktisk hero-text — ta bort "betalt varje måndag" om det inte är sant eller lägg in det på sidan.
|
||
- Pitcha till sajter som publicerar "apps that pay you to take photos"-guider (moneypantry.com, financialbinder.com) — enkel backlink-möjlighet med hög relevans.
|
||
- Skapa en landningssida specifikt för sökordet "crowdsourced field data collection" under `/for-organisations/field-data-collection/`.
|
||
|
||
---
|
||
|
||
## Steg 2 — Landing page (www.quixzoom.com)
|
||
|
||
### Nuläge
|
||
|
||
**Hero-text (faktisk HTML-text):**
|
||
> "Capture the world. Earn per mission."
|
||
> "quiXzoom is a platform for field data collection. Photograph infrastructure, roads, coastlines and urban environments near you. Payment per approved mission, direct to your bank account."
|
||
|
||
**Trust-rad under formuläret:**
|
||
`"No signup fee · Payment via Stripe Connect · Identity verification required once"`
|
||
|
||
**Sidtitel (sökmotorvisad):** `quiXzoom — Tjäna pengar på foton | Bli Zoomer i Sverige`
|
||
**OG-titel:** `quiXzoom – Tjäna pengar per uppdrag`
|
||
**Meta-description:** `"Fotografera uppdrag nära dig. Betalt per godkänd bild via Stripe Connect. Ingen plattformsavgift. Lanseras 1 augusti 2026."`
|
||
|
||
**Stat-sektionen visar:**
|
||
- ~30 min — Average mission time
|
||
- 20+ Countries at launch
|
||
- August 2026 — Launch market: Sweden
|
||
- 100% — Paid on approval
|
||
|
||
**Nav-knappen:** `"Register interest"` — scrollar till e-postformulär (väntlista)
|
||
**Hero-CTA:** `"Register interest →"` — ditto
|
||
|
||
### Problem
|
||
|
||
1. **Språkblandning är förvirrande.** Sökordssnippet är på svenska ("Tjäna pengar på foton", "Bli Zoomer"), men hela sidan är på engelska. En svensk som googlar hamnar på engelska content. Det är inte nödvändigtvis fel (internationell plattform), men det skapar ett diskrepanshopp.
|
||
|
||
2. **Mobilnavbar är dold.** CSS säger explicit: `@media(max-width:768px){.nav-links{display:none}.btn-nav{display:none}}` — på mobil saknas navigering helt och "Register interest"-knappen försvinner. Den primära trafikkällan (smartphones) ser en skalad-bort navbar utan CTA.
|
||
|
||
3. **Zoomer-räknaren visar ingenting.** Waitlist-count API returnerar `{"count":0}` och väntelistan är trasig. Landningssidan hämtar count dynamiskt — besökare ser "— Zoomers already signed up" utan siffra, alternativt 0. Det **sänker trovärdigheten drastiskt**.
|
||
|
||
4. **Inga sociala bevis.** Inga testimonials, inga citat från Zoomers, inga logos, ingen pressomtäl. "Be among the first. Launching August 2026." är det närmaste.
|
||
|
||
5. **App Store / Google Play visar "Coming August 2026"** — inga faktiska klickbara länkar. Besökaren förstår inte om det är en app eller en webbapp.
|
||
|
||
6. **Ingen direktlänk till app.quixzoom.com.** Hela landningssidans CTA-flöde leder till väntlista, inte till registrering i appen. Användare som är redo att skapa konto hittar ingen väg dit.
|
||
|
||
7. **Stats-sektionen är statisk och lite sval.** "~30 min Average mission time" och "20+ Countries at launch" är estimat — ingen faktisk data ännu.
|
||
|
||
### Förslag
|
||
|
||
- Fixa mobilnavbaren: ta bort `display:none` för `.btn-nav` på mobil, ersätt med hamburgermeny eller en fast bottom-bar med "Register interest".
|
||
- Lägg till en tydlig länk/knapp i hero: `"Already registered? Open app →"` → `https://app.quixzoom.com`.
|
||
- Fixa waitlist-endpoint (se Steg 7) så räknaren visas.
|
||
- Lägg till en sektion "What Zoomers say" — även om appen är i beta kan ni visa intern feedback.
|
||
- Synkronisera sidans primärspråk: antingen gör en svenska version på `/sv/` eller håll allt på engelska inkl. sökordsrubriken.
|
||
|
||
---
|
||
|
||
## Steg 3 — For Organisations-sidan (/for-organisations/)
|
||
|
||
### Nuläge
|
||
|
||
Sidan har `<link rel="canonical" href="https://www.quixzoom.com/for-organisations/">` och en `hreflang="x-default"`. Det är bra.
|
||
|
||
**Hero-text:**
|
||
> "Field data collection. On demand. At scale."
|
||
> "Commission visual documentation of infrastructure, property and urban environments — verified and delivered. No field team required."
|
||
|
||
**Stats-rad:**
|
||
- 20+ Countries at launch
|
||
- ~30 min Average mission time
|
||
- 100% AI-reviewed before delivery
|
||
- Aug 1 Global launch 2026
|
||
|
||
**Sektioner:** What we deliver, Who uses quiXzoom (Municipality, Property, Insurance, Infrastructure), How it works, Pricing, form.
|
||
|
||
**CTA-knapp i nav:** `"Request access"` → oklart vart (förmodligen till form längre ned på sidan).
|
||
|
||
### Problem
|
||
|
||
1. **Pris är otydligt.** Sidan nämner "Transparent. Per approved submission." men visar prisbanderna för AAMOS B2B-plattform (Seed/Growth/Scale) — det är **inte** rätt prissättning för organisations-kunder som köper uppdrag. Förväxling med SaaS-priset.
|
||
|
||
2. **"Request access"-knappen** saknar `href` i navbar-utgåva — den är en `<button class="btn-nav">` utan klickmål specificerat i det utdrag vi ser. Oklar destination.
|
||
|
||
3. **Inga case studies eller kundlogos** — B2B-köpare behöver socialt bevis. Sidan har bra text men ingen social proof alls.
|
||
|
||
4. **HTML lang saknas** — källan visar ingen `<html lang="en">`.
|
||
|
||
5. **Formuläret** (`form-wrap`-sektionen) finns i CSS men destinationen är oklar — troligen waitlist-API, men detta är en B2B-form som borde gå till ett dedikerat CRM-flöde eller en dedikerad endpoint.
|
||
|
||
### Förslag
|
||
|
||
- Separera zoomer-prissättning från B2B-prissättning tydligt.
|
||
- Lägg till `<html lang="en">`.
|
||
- Lägg till 2–3 fiktiva (eller verkliga beta-) fallstudier med konkret data.
|
||
- Klargör "Request access"-knappens destination — visa en modal eller skrolla till form med synlig `<a href="#contact-form">`.
|
||
|
||
---
|
||
|
||
## Steg 4 — Registration/Join-flödet
|
||
|
||
### Nuläge
|
||
|
||
Det finns **inget direktflöde från www → app** för en användare som vill registrera sig som Zoomer.
|
||
|
||
- Nav-knappen: "Register interest" → scrollar till e-postfält (väntlista)
|
||
- Hero-CTA: "Register interest →" → ditto
|
||
- Footer: "Register interest" → ditto
|
||
- Ingen länk till `https://app.quixzoom.com` finns på landningssidan
|
||
- Appen hanterar `/join` → redirect till `/auth` (se patch-script), men det spelar ingen roll när ingen leder dit
|
||
|
||
**App.quixzoom.com patch-script** (inline JS i index.html):
|
||
```js
|
||
// /join → /auth redirect
|
||
if (window.location.pathname === '/join' || window.location.pathname === '/join/') {
|
||
window.history.replaceState(null, '', '/auth');
|
||
}
|
||
```
|
||
Registrerings-API-anrop i appen:
|
||
```
|
||
POST https://api.quixzoom.com/api/qz/auth/register
|
||
```
|
||
|
||
### Problem
|
||
|
||
1. **Kritisk blocker:** Ingen länk från www till app. Användare som vill registrera sig idag (inte bara intresseanmäla) har ingen väg dit.
|
||
2. **"Register interest" vs "Create account"** är fundamentalt olika handlingar. Nuläget samlar bara väntlista-e-poster, inte faktiska konton.
|
||
3. **Väntliste-endpoint är trasig** (se Steg 7) — även väntlistan fungerar inte.
|
||
4. **Avsaknad av disambiguering:** "Be among the first. Launching August 2026." — oklar om appen är live idag eller ej. app.quixzoom.com är live och accepterar registrering, men detta kommuniceras inte.
|
||
|
||
### Förslag
|
||
|
||
- Lägg till `"Create account →"` som primär CTA som leder till `https://app.quixzoom.com/auth`.
|
||
- Behåll "Register interest" som sekundär CTA för de som inte vill skapa konto än.
|
||
- Sätt tydlig text: "The app is live now. Missions go live August 1, 2026."
|
||
|
||
---
|
||
|
||
## Steg 5 — API — Registration endpoint
|
||
|
||
### Nuläge
|
||
|
||
**Endpoint:** `POST https://api.quixzoom.com/api/qz/auth/register`
|
||
|
||
Testanrop (utfört under audit):
|
||
```json
|
||
Request: {"email":"test-journey-audit@example.com","password":"TestPass123!","name":"Test Zoomer","role":"zoomer"}
|
||
Response HTTP 200:
|
||
{
|
||
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"user": {
|
||
"id": "0a6c1a83-7cad-4434-b27f-52364ef9dd48",
|
||
"email": "test-journey-audit@example.com",
|
||
"name": "Test Zoomer",
|
||
"role": "zoomer",
|
||
"created_at": "2026-06-16T12:04:00.353Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
**RS256 JWT** med `iss: identity.wavult.com`, expires 7 dagar. Bcrypt-hash med cost 12. Wallet skapas automatiskt vid registrering.
|
||
|
||
### Problem
|
||
|
||
1. **Inget välkomstmail skickas.** Koden i `auth.mjs` skickar inga e-poster — varken välkomsthälsning eller e-postbekräftelse. `email_confirmed`-kolumnen finns i databasen och i `/me`-responsen, men det finns ingen endpoint eller logik för att bekräfta e-post.
|
||
|
||
2. **Inget krav på e-postbekräftelse.** Vem som helst kan registrera sig med en fejk-e-post och direkt få ett JWT. Ingen verifieringsbarriär.
|
||
|
||
3. **Ingen onboarding-guide efter registrering.** Registreringen ger token + user. Appen måste självständigt veta att nästa steg är: bekräfta e-post → lägg till telefon → KYC → Stripe Connect. Det finns en `onboarding`-status i `/me`, men `/me` är trasig (se Steg 6).
|
||
|
||
4. **Svag felhantering för `role`:** Om `role` inte skickas defaultar den till `"zoomer"` — OK. Men felmeddelandet om fel roll är på engelska (`"role must be zoomer or orderer"`) — konsistent med resten av API:et.
|
||
|
||
### Förslag
|
||
|
||
- Skicka välkomstmail via SES vid registrering (infrastrukturen finns — se waitlist.mjs som använder SES).
|
||
- Lägg till e-postbekräftelse: generera en `confirm_token`, spara i DB, skicka länk, låt `/auth/confirm?token=...` sätta `email_confirmed=true`.
|
||
- Trigga onboarding-guiden i appen efter svar från `/register`.
|
||
|
||
---
|
||
|
||
## Steg 6 — API — `/me` endpoint (onboarding-status)
|
||
|
||
### Nuläge
|
||
|
||
**Endpoint:** `GET https://api.quixzoom.com/api/qz/auth/me` (Bearer-skyddat)
|
||
|
||
Testanrop med JWT från Steg 5:
|
||
```json
|
||
Response HTTP 401:
|
||
{
|
||
"error": "Ogiltig token",
|
||
"detail": "column u.total_earned does not exist"
|
||
}
|
||
```
|
||
|
||
**Felet:** SQL-queryn i `/me` selekterar `u.total_earned` och `u.missions_completed` direkt från `quixzoom.users`-tabellen, men dessa kolumner finns **inte** på users-tabellen — de tillhör wallets/separata aggregat. Queryn kolliderar med sig själv: på rad 133 gör den `COALESCE(w.total_earned, 0) AS wallet_total_earned` från `quixzoom.wallets`, men försöker även läsa `u.total_earned` på rad 125 (direkt från users). Kolumnen saknas → PostgreSQL-fel → 401.
|
||
|
||
**Vad `/me` borde returnera** (onboarding-statusobjektet):
|
||
```json
|
||
{
|
||
"registered": true,
|
||
"email_confirmed": false,
|
||
"phone_verified": false,
|
||
"identity_verified": false,
|
||
"stripe_connected": false,
|
||
"ready_for_missions": false
|
||
}
|
||
```
|
||
Detta är **kritisk data för appen** — onboarding-guiden kan inte fungera.
|
||
|
||
### Problem
|
||
|
||
1. **`/me` är trasig för alla användare.** Alla Zoomers som försöker hämta sin profil/onboarding-status får 401. Hela onboarding-guiden i appen är ur funktion.
|
||
2. **Felmeddelandet exponerar databasstruktur** (`column u.total_earned does not exist`) — informationsläckage som aldrig bör nå produktion.
|
||
3. **Fix är enkel:** ta bort `u.total_earned, u.missions_completed` ur SELECT (rad 125), de finns redan som `wallet_total_earned` från wallet-joinen.
|
||
|
||
### Förslag
|
||
|
||
**Omedelbar fix — auth.mjs rad 121–134:**
|
||
```sql
|
||
-- Ta bort dessa rader:
|
||
u.credits_balance, u.total_earned, u.missions_completed,
|
||
|
||
-- De är redan tillgängliga via:
|
||
COALESCE(w.balance, 0) AS wallet_balance,
|
||
COALESCE(w.total_earned, 0) AS wallet_total_earned
|
||
```
|
||
Flytta om credits_balance kolumnen existerar i users, annars ta bort den också. Exponera aldrig DB-felmeddelanden i production-svar.
|
||
|
||
---
|
||
|
||
## Steg 7 — Waitlist-endpoint
|
||
|
||
### Nuläge
|
||
|
||
**Endpoint:** `POST https://api.quixzoom.com/api/qz/waitlist`
|
||
|
||
Testanrop:
|
||
```json
|
||
Request: {"email":"test-journey-audit-wl@example.com","lang":"sv"}
|
||
Response HTTP 500:
|
||
{
|
||
"error": "Database error",
|
||
"code": "DB_ERROR"
|
||
}
|
||
```
|
||
|
||
Även `GET /api/qz/waitlist/count` returnerar `{"count":0}` korrekt (enkel COUNT-query fungerar).
|
||
|
||
**Koden** i `waitlist.mjs` ser korrekt ut — INSERT-query med ON CONFLICT och alla nödvändiga fält. Felet uppstår troligen vid **pool-initialiseringen**: koden gör `getPool().catch(...)` vid import och skapar schema/tabell om det inte finns. Antagligen misslyckas DB-anslutningen eller tabellskapandet vid import utan att krascha processen, och sedan misslyckas varje INSERT.
|
||
|
||
Alternativt: SSL-konfigurationsproblemet (se backup-filen `waitlist.mjs.bak-ssl-1781543138`) tyder på att det har funnits SSL-problem med denna DB-anslutning tidigare.
|
||
|
||
**E-postbekräftelse:** Koden skickar bekräftelsemail på 9 språk via AWS SES vid lyckad registrering. Triggas aldrig pga DB-felet.
|
||
|
||
**E-postsändaren:** `"quiXzoom <no-reply@wavult.com>"` — skickas från Wavult-domänen, inte quixzoom.com. Kan se ut som spam.
|
||
|
||
### Problem
|
||
|
||
1. **Waitlist-formuläret på landningssidan är icke-funktionellt.** Användare som fyller i sin e-post får förmodligen ett generiskt felmeddelande. Landningssidans inline-felhantering (koden `Something went wrong. Please try again.`) visas.
|
||
2. **Alla intresseanmälningar försvinner.** Varje person som googlar "tjäna pengar foton", landar på sidan och anmäler sig — registreras inte.
|
||
3. **Bekräftelsemail skickas aldrig** — SES-logiken är aldrig nådd.
|
||
4. **Avsändaradress:** `no-reply@wavult.com` bör vara `no-reply@quixzoom.com` för trovärdighet.
|
||
|
||
### Förslag
|
||
|
||
- Debugga pool-initialiseringen i `waitlist.mjs` — kör `getPool()` med en test-INSERT och logga exakt PostgreSQL-felmeddelande.
|
||
- Kontrollera att WAITLIST_DB_URL env-var är korrekt satt i PM2/systemd-konfig.
|
||
- Byt `Source` i SES-anropet till `quiXzoom <no-reply@quixzoom.com>`.
|
||
- Lägg till `Reply-To: hello@quixzoom.com` (det finns redan — bra).
|
||
- Testa SSL-konfigurationen: kolla `waitlist.mjs.bak-ssl-1781543138` för vad som ändrades.
|
||
|
||
---
|
||
|
||
## Steg 8 — KYC-flödet
|
||
|
||
### Nuläge
|
||
|
||
KYC-systemet är välbyggt:
|
||
- `POST /challenge` — genererar server-sided nonce + action (BLINK_TWICE, TURN_LEFT, TURN_RIGHT, NOD, SMILE) med 45s timeout
|
||
- `POST /upload/:type` — laddar upp `doc_front` eller `selfie` (base64 JSON) till S3 (`platform-kyc-evidence-eu`, AES256)
|
||
- `POST /verify` — startar asynkron verifiering mot SFace-tjänst (port 8765): MRZ-extraktion + ansiktsmatchning
|
||
- `GET /status/:session_id` — poll-endpoint för verifieringsstatus
|
||
- `GET /me` — hämtar `assurance_level` för inloggad användare
|
||
|
||
**Assurance levels:** `photo_low`, `manual_review`, `rejected`
|
||
|
||
**Identity verification är krävt** för `ready_for_missions: true` (via `/me`-endpointen):
|
||
```js
|
||
ready_for_missions: (u.identity_verified && u.stripe_onboarding_complete) || false,
|
||
```
|
||
|
||
### Problem
|
||
|
||
1. **KYC triggas aldrig kommunicerat för användaren.** Det finns inget tydligt i appen (svårt att verifiera utan full app-granskning) som säger "du måste verifiera din identitet för att ta uppdrag". Användare kan skapa konto och sedan mötas av en tyst blockering.
|
||
|
||
2. **Livsliveness-aktioner** (BLINK_TWICE etc.) kräver att appen kan instruera och validera video-response. Det är icke-trivialt UX — kräver en bra in-app guide.
|
||
|
||
3. **KYC_HMAC_KEY och KYC_CHALLENGE_SECRET** — koden har startskydd (`// REQUIRED: set KYC_HMAC_KEY env var`) men ingen tydlig deploy-dokumentation synlig.
|
||
|
||
4. **`assurance_level: 'photo_low'`** — vad innebär det för Zoomern? Kan de ta uppdrag? Oklart från koden.
|
||
|
||
### Förslag
|
||
|
||
- Dokumentera KYC-flödet tydligt i appen: "Step 3 of 4: Verify your identity. Takes 2 minutes. Required once."
|
||
- Definiera vilka assurance-levels som räcker för `ready_for_missions` (bara `photo_low`+? eller krävs godkänd manuell review?).
|
||
- Lägg till `identity_verified` i register-svaret eller ta upp det direkt i onboarding-guiden.
|
||
|
||
---
|
||
|
||
## Steg 9 — Zoomer-appen (app.quixzoom.com)
|
||
|
||
### Nuläge
|
||
|
||
S3-bucket `quixzoom-app-prod` innehåller:
|
||
- `index.html` (18,8 KB) — Vite-byggd PWA
|
||
- `manifest.webmanifest` — PWA-manifest
|
||
- `pwa-192x192.png`, `pwa-512x512.png`, `favicon.png`
|
||
- `sw.js`, `workbox-8c29f6e4.js` — Service Worker (offline-stöd)
|
||
- `registerSW.js`
|
||
|
||
**Meta:**
|
||
```html
|
||
<title>quiXzoom – Tjäna pengar per uppdrag</title>
|
||
<meta name="description" content="Fotografera uppdrag nära dig. Betalt per godkänd bild via Stripe Connect. Ingen plattformsavgift. Lanseras 1 augusti 2026." />
|
||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||
```
|
||
|
||
**App är en PWA** — installationsbar på hem-skärmen. Ingen native App Store-app finns (ännu).
|
||
|
||
**Patch-script v6** (inline JS, senast uppdaterad 2026-06-13):
|
||
- AMOS_BASE → `api.quixzoom.com`
|
||
- `/join` → `/auth` redirect
|
||
- Hanterar login/register via `api.quixzoom.com/api/qz/auth/*`
|
||
|
||
### Problem
|
||
|
||
1. **`<html>` saknar lang-attribut** — SEO- och accessibility-problem.
|
||
2. **Inga App Store-/Google Play-länkarna** existerar idag. Landningssidan visar "App Store Coming August 2026" och "Google Play Coming August 2026" — dessa är *placeholders*, inte klickbara. En besökare som söker "quiXzoom app" hittar inget.
|
||
3. **PWA Install-prompt** — det är oklart om appen uppmanar till installation. Service worker finns, manifest finns — borde funka i Chrome/Android, men iOS kräver manuell "Add to Home Screen" utan Push API.
|
||
4. **`og:image` på app.quixzoom.com** pekar på `https://www.quixzoom.com/og-image.jpg` — okonsekvent (borde peka på app-specifik OG-bild eller rätt domän).
|
||
5. **Inga förklarande routes i index.html** — allt är SPA, vilket är normalt, men onboarding-flödet (register → verify email → KYC → Stripe) måste fungera inom appen.
|
||
|
||
### Förslag
|
||
|
||
- Lägg till `<html lang="sv">` (eller `lang="en"`).
|
||
- Publicera App Store/Google Play-sidor innan lansering — bygg åtminstone landing pages med "Coming soon" med pre-registration.
|
||
- Lägg till en "Install app"-banner på landningssidan som triggar PWA-install på mobilbesök.
|
||
- Kontrollera att onboarding-guiden i appen faktiskt hanterar `/me`-felet (se Steg 6) gracefully — den får en 401 idag och vet inte varför.
|
||
|
||
---
|
||
|
||
## Steg 10 — E-postflödet
|
||
|
||
### Nuläge
|
||
|
||
**Waitlist-mail:** AWS SES, 9 språk (sv, en, de, fr, nl, fi, da, es, it), plain text. Avsändare: `quiXzoom <no-reply@wavult.com>`, Reply-To: `hello@quixzoom.com`. Skickas **inte** (DB-felet blockerar).
|
||
|
||
**Registrerings-välkomstmail:** **Finns inte.** Varken kod eller konfiguration för välkomstmail vid `/register`.
|
||
|
||
**E-postbekräftelse:** **Finns inte.** `email_confirmed`-kolumnen finns i DB och `/me`-responsen, men ingen route för att skicka eller bekräfta.
|
||
|
||
**Mailinnehåll (waitlist-sv):**
|
||
> "Din e-postadress är registrerad på quiXzoom-väntelistan.
|
||
> quiXzoom lanserar i Sverige den 1 augusti 2026. Du kommer att meddelas via denna adress när din region öppnar.
|
||
> Vad är quiXzoom? quiXzoom är en plattform för crowdsourcad fältdatainsamling..."
|
||
|
||
Texten är bra — tydlig, kort, korrekt avsändaradress för svar.
|
||
|
||
### Problem
|
||
|
||
1. **Ingen e-post skickas någonstans** idag (waitlist trasig, register har inget mail).
|
||
2. **Avsändardomänen är wavult.com**, inte quixzoom.com — ser otryggt ut för mottagaren.
|
||
3. **Inga HTML-mail** — bara plain text. Svår att differentiera visuellt, ingen call-to-action-länk.
|
||
4. **Ingen e-postbekräftelse** = ingen spam-barriär, ingen verifiering av e-postadress.
|
||
|
||
### Förslag
|
||
|
||
- Fixa waitlist-DB (se Steg 7) så befintlig SES-logik kan köras.
|
||
- Lägg till välkomstmail vid `/register`: `"Welcome to quiXzoom — here's how to get started"` med länk till app + onboarding-guide.
|
||
- Implementera e-postbekräftelse: skicka länk → `/auth/confirm?token=X` sätter `email_confirmed=true`.
|
||
- Byt avsändardomän till `no-reply@quixzoom.com` (kräver SES-verifiering av quixzoom.com-domänen).
|
||
- Bygg HTML-mail-templat (även enkel — logo + knapp + text).
|
||
|
||
---
|
||
|
||
## Kritiska blockers (måste fixas nu)
|
||
|
||
Dessa problem förhindrar att en enda användare kan gå igenom resan från Google till aktiv Zoomer:
|
||
|
||
1. **`/api/qz/waitlist` — DB-fel (HTTP 500).**
|
||
Alla väntlisteanmälningar försvinner. Landningssidans primära CTA är icke-funktionell. Fix: debugga pool-init i `waitlist.mjs`, verifiera WAITLIST_DB_URL och SSL-konfiguration.
|
||
|
||
2. **`/api/qz/auth/me` — `column u.total_earned does not exist` (HTTP 401).**
|
||
Appens onboarding-guide kan inte hämta status. Ta bort `u.total_earned, u.missions_completed` ur SELECT-queryn på rad 125 i `auth.mjs` — de finns redan via wallet-joinen som `wallet_total_earned`.
|
||
|
||
3. **Ingen länk från www.quixzoom.com till app.quixzoom.com.**
|
||
Användare som vill registrera sig hittar ingen väg till appen. Lägg till `"Create account →"` CTA som pekar på `https://app.quixzoom.com/auth`.
|
||
|
||
4. **Mobilnavbaren är dold (`display:none` vid < 768px).**
|
||
Primär trafikkälla (smartphones) ser ingen navigering och ingen CTA. Fixa med hamburgermeny eller sticky bottom-bar.
|
||
|
||
---
|
||
|
||
## Quick wins (kan fixas direkt)
|
||
|
||
1. **Lägg till `<html lang="en">` på www och app** — 5 min, SEO + accessibility.
|
||
2. **Byt SES-avsändaradress** från `no-reply@wavult.com` till `no-reply@quixzoom.com` — kräver SES-domain verification, 30 min.
|
||
3. **Dölj DB-felmeddelanden** i API-svar — ersätt `detail: e.message` med generiska meddelanden i production, 10 min.
|
||
4. **Lägg till `"Open app →"`-länk i footern** på www.quixzoom.com, 5 min.
|
||
5. **Synkronisera meta-description** med faktisk hero-text (ta bort "betalt varje måndag" om det inte kommuniceras på sidan), 5 min.
|
||
6. **Hreflang för svenska:** `<link rel="alternate" hreflang="sv" href="https://www.quixzoom.com/">`, 5 min.
|
||
|
||
---
|
||
|
||
## Längre åtgärder
|
||
|
||
1. **E-postbekräftelse och välkomstflöde** — ny route `/auth/confirm`, ny `/auth/resend-confirmation`, SES-mall. Estimat: 1 dag.
|
||
2. **Välkomstmail vid registrering** — HTML-baserat, med onboarding-guide-länk. Estimat: 4 timmar.
|
||
3. **PWA/App Install-strategi** — bestäm om native app eller enbart PWA. Om PWA: implementera install-prompt och "Add to Home Screen"-guide. Estimat: 2 dagar.
|
||
4. **Backlink-outreach** — kontakta 5–10 "earn money from photos"-guider för att inkludera quiXzoom. Estimat: 1 vecka löpande.
|
||
5. **Mobilresponsiv nav** — hamburgermeny eller bottom-bar med "Register" och "Log in". Estimat: 1 dag.
|
||
6. **Socialt bevis på landningssidan** — testimonials (beta-Zoomers), reell waitlist-counter. Estimat: löpande.
|
||
7. **B2B-prissida separerad från Zoomer-sida** — tydliga prisspår. Estimat: 2 dagar.
|
||
8. **Internationalisering (i18n)** — bestäm primärspråk per marknad; minst en fullständig svensk version av landningssidan. Estimat: 3–5 dagar.
|
||
|
||
---
|
||
|
||
## Appendix — Testresultat
|
||
|
||
| Endpoint | Metod | Förväntad respons | Faktisk respons |
|
||
|----------|-------|-------------------|-----------------|
|
||
| `/api/qz/auth/register` | POST | 200 + JWT | ✅ 200 OK |
|
||
| `/api/qz/auth/me` | GET (Bearer) | 200 + user+onboarding | ❌ 401 (`column u.total_earned does not exist`) |
|
||
| `/api/qz/waitlist` | POST | 200 OK | ❌ 500 (`Database error`) |
|
||
| `/api/qz/waitlist/count` | GET | 200 + count | ✅ 200 `{"count":0}` |
|
||
| `www.quixzoom.com/og-image.jpg` | GET | 200 JPEG | ✅ 200 (17 KB) |
|
||
| S3 `quixzoom-landing-prod/index.html` | — | HTML | ✅ 152 KB |
|
||
| S3 `quixzoom-app-prod/index.html` | — | HTML | ✅ 18,8 KB |
|