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
20 KiB
20 KiB
Design Spec — Internationalisation, Locale-Aware Sandbox & Visual Storytelling
Landvex × quiXzoom
Datum: 2026-06-20
Uppdragsgivare: Erik Svensson
Status: Produktionskrav — levereras till designteam + engineering
DEL 1 — ELIMINERA ALLA SVENSKA STANDARDARTEFAKTER
Princip
Standardupplevelsen är engelska + marknadens lokala kontext. Sverige är en marknad bland 20+, inte ett default.
Inventering — svenska artefakter som måste bort
| Artefakt | Nuläge | Krav | Fil/yta |
|---|---|---|---|
| Exempeladress | "Storgatan 14, Stockholm" (floating card) | Dynamisk per marknad | quiXzoom homepage hero |
| Exempelvaluta i schema | priceCurrency: "SEK" (fixat) |
EUR/USD som global default | quiXzoom index.html |
| Skatteinfo | "Grundavdrag ~17 500 SEK/year" som primärt exempel | Marknadsdynamisk eller bort från hero-kontext | quiXzoom FAQ-tabs |
| Juridisk text | terms.html på svenska (lang="sv") |
Engelsk default, sv-variant under /sv/ |
quiXzoom/terms.html |
zoomer-start.html |
<html lang="sv">, "Bli Zoomer", hela texten på svenska |
Primärsida ska vara engelska | nginx index-priority |
| Exempelnamn | Implicita svenska namn i onboarding-data | Marknadsneutrala eller dynamiska | |
| Karta/geo-default | Stockholmscentrerad demo-karta | Geo-IP eller marknadsselektion | quiXzoom map.html |
| Landvex exempeldata | Stockholmsvärden i intelligence-tabeller | Dynamisk per vald stad/marknad | Landvex cities/* |
Implementation — Locale Architecture
DEFAULT LOCALE: en-001 (World English)
DEFAULT MARKET: none selected → prompt user
URL-struktur:
/ → en, marknadsneutral
/markets/se/ → sv-SE, svenska artefakter
/markets/de/ → de-DE, tyska artefakter
/markets/us/ → en-US, amerikanska artefakter
/markets/th/ → th-TH, thailändska artefakter
Cookie: qx_locale=de-DE (persisteras vid val)
HTTP: Accept-Language läses → föreslår marknad, aldrig tvingar
Locale Data Bundle — per marknad
{
"de-DE": {
"currency": "EUR",
"currencySymbol": "€",
"exampleAddress": "Maximilianstraße 12, München",
"exampleCompany": "Müller GmbH",
"examplePerson": "Hans Müller",
"exampleLegalId": "HRB 123456 AG München",
"examplePhone": "+49 89 12345678",
"examplePostalCode": "80539",
"exampleCity": "München",
"taxThreshold": "22.000 € (Kleinunternehmerregelung)",
"payoutRail": "SEPA",
"dateFormat": "DD.MM.YYYY",
"numberFormat": "1.234,56",
"mapCenter": [11.5820, 48.1351],
"missionExamples": [
{ "title": "Fassadeninspektion", "location": "Schwabing, München", "reward": 14 },
{ "title": "Parkplatzkartierung", "location": "Maxvorstadt", "reward": 9 }
]
},
"en-US": {
"currency": "USD",
"currencySymbol": "$",
"exampleAddress": "1234 Main St, Houston TX",
"exampleCompany": "Acme Corp",
"examplePerson": "James Wilson",
"exampleLegalId": "EIN 12-3456789",
"examplePhone": "+1 713 555 0123",
"examplePostalCode": "77002",
"exampleCity": "Houston",
"taxThreshold": "$400/year (self-employment threshold)",
"payoutRail": "ACH",
"dateFormat": "MM/DD/YYYY",
"numberFormat": "1,234.56",
"mapCenter": [-95.3698, 29.7604],
"missionExamples": [
{ "title": "Facade Survey", "location": "Midtown Houston", "reward": 18 },
{ "title": "Parking Lot Audit", "location": "Downtown Houston", "reward": 12 }
]
},
"th-TH": {
"currency": "THB",
"currencySymbol": "฿",
"exampleAddress": "123 Sukhumvit Rd, Khlong Toei, Bangkok",
"exampleCompany": "Thai Inspire Co., Ltd.",
"examplePerson": "Somchai Jaidee",
"exampleLegalId": "0105561012345",
"examplePhone": "+66 2 123 4567",
"examplePostalCode": "10110",
"exampleCity": "Bangkok",
"taxThreshold": "฿1,800,000/year (VAT threshold)",
"payoutRail": "PromptPay",
"dateFormat": "DD/MM/YYYY",
"numberFormat": "1,234.56",
"mapCenter": [100.5018, 13.7563],
"missionExamples": [
{ "title": "Shop Sign Survey", "location": "Silom, Bangkok", "reward": 120 },
{ "title": "Facade Condition", "location": "Chatuchak", "reward": 85 }
]
},
"ar-AE": {
"currency": "AED",
"currencySymbol": "د.إ",
"exampleAddress": "Al Wasl Road, Jumeirah, Dubai",
"exampleCompany": "Al Noor Trading LLC",
"exampleLegalId": "Commercial License 1234567",
"examplePhone": "+971 4 123 4567",
"exampleCity": "Dubai",
"payoutRail": "SWIFT",
"dateFormat": "DD/MM/YYYY",
"mapCenter": [55.2708, 25.2048],
"rtl": true,
"missionExamples": [
{ "title": "Building Facade Inspection", "location": "Business Bay, Dubai", "reward": 55 }
]
}
}
Sandbox-propagering — tekniskt krav
Varje demo/sandbox-vy MÅSTEläsa från locale bundle. Inga hårdkodade värden.
// Fel — hårdkodat
const demoCard = {
address: "Storgatan 14, Stockholm",
reward: "285 kr",
company: "Stockholms Stad"
};
// Rätt — dynamiskt
const locale = getLocale(); // "de-DE" från cookie/URL/GeoIP
const demoCard = {
address: localeData[locale].missionExamples[0].location,
reward: formatCurrency(localeData[locale].missionExamples[0].reward, locale),
company: localeData[locale].exampleCompany
};
Propageras till:
- Hero floating mission card
- Demo-kartan (mapCenter + exempelmarkeringar)
- Onboarding-flow exempeldata
- Earnings-kalkylator
- FAQ skatteinfo (visas bara för vald marknad)
- Landvex intelligence-tabeller (exempelrader)
- City pages (redan marknadsseparerade — korrekt arkitektur)
DEL 2 — SANDBOX FÖLJER VALD MARKNAD
Flöde
Användaren landar på quixzoom.com
↓
GeoIP → föreslår marknad (banner: "Looks like you're in Germany. Switch to DE →")
↓
Användaren väljer (eller behåller default)
↓
Cookie qx_market=DE sätts
↓
ALL demo-data propageras: adresser, valutor, namn, karta, skatteinfo, juridik
↓
Onboarding → "How much can I earn in Germany?"
→ Visar tyska exempel, EUR, tyska skatttrösklar
Market Selector Component
<div class="market-selector" role="navigation" aria-label="Select your market">
<button class="market-btn" data-market="current">
<img src="/flags/{{current}}.svg" alt="" width="20" height="14" aria-hidden="true">
<span>{{currentMarketName}}</span>
<svg aria-hidden="true"><!-- chevron --></svg>
</button>
<div class="market-dropdown" role="listbox">
<button role="option" data-market="SE">🇸🇪 Sweden</button>
<button role="option" data-market="DE">🇩🇪 Germany</button>
<button role="option" data-market="US">🇺🇸 United States</button>
<button role="option" data-market="GB">🇬🇧 United Kingdom</button>
<button role="option" data-market="TH">🇹🇭 Thailand</button>
<button role="option" data-market="AE">🇦🇪 UAE</button>
<button role="option" data-market="NL">🇳🇱 Netherlands</button>
<button role="option" data-market="FR">🇫🇷 France</button>
<!-- +13 markets at launch -->
</div>
</div>
document.querySelectorAll('[data-market]').forEach(btn => {
btn.addEventListener('click', () => {
const market = btn.dataset.market;
document.cookie = `qx_market=${market};path=/;max-age=31536000`;
updateAllLocaleContent(market); // triggers locale bundle swap
updateMap(localeData[market].mapCenter);
updateDemoCard(localeData[market].missionExamples[0]);
updateFAQTax(localeData[market]);
});
});
DEL 3 — VISUELLT STORYTELLING
Princip
Användaren ska förstå vad sidan gör inom 3 sekunder, innan de läser ett enda stycke.
Nuläge vs mål
| Yta | Nuläge | Mål |
|---|---|---|
| Hero | Text + telefon-mockup | Animated workflow: Mission → Zoomer → Verified data → Payout |
| How it works | 4 textblock | 4 illustrerade steg med process-ikoner + connectors |
| Tier pricing | 3 textkort | 3 illustrerade nivåkort med visuell differentiering |
| Landvex homepage | Textblock + dark hero | Contradictions-diagram + data-flow-illustration |
| Landvex methodology | Texttunga steg | Visuell pipeline: Observation → AI → Score → Report |
| Onboarding | Formulär | Illustrated steps med progress indicator |
| Empty states | Ingen data/text | Custom illustration per kontext |
Illustration-system — specifikation
Stil
Stil: Flat / geometric, linjär
Färgpalett: --color-accent #0066FF + white + #0a0a0a + accent-green #00C853
Stroke: 2px consistent
Ikonstil: 24×24px grid, rounded corners 2px
Animationer: CSS-only, prefers-reduced-motion respected
Format: SVG (inline för animering, externa för statiska)
Prioriterade illustrationer att producera (ordning)
quiXzoom — 8 illustrationer
QX-ILL-01: Mission Flow (hero)
Visar: Briefcase icon → Map pin → Camera → Checkmark → Coins
Animation: left-to-right flow, 3s loop
Plats: Hero, ovanför/bredvid telefon-mockup
QX-ILL-02: How it Works — 4 steg
Steg 1: Browse Map → pin-ikon på karta
Steg 2: Claim Mission → handskaknings-ikon
Steg 3: Photograph → kamera-ikon
Steg 4: Get Paid → plånbok + check-ikon
Format: Horisontell rad desktop, vertikal stack mobil
QX-ILL-03: Tier Differentiation
Supplementary: singel person, 2-3 per vecka
Active: person + ryggsäck, 8-12 per vecka
Professional: person + utrustning + badge
QX-ILL-04: Identity Verification (onboarding)
Shield + ID-kort + checkmark
QX-ILL-05: Zoomer Profile Empty State
Person med kamera, "Your first mission awaits"
QX-ILL-06: Mission Approved
Checkmark-animation + mynt-ikon + "Credits added"
QX-ILL-07: Earnings Calculator
Slider → graf → utbetalningsikon
QX-ILL-08: Global Presence
Världskarta med markerade launch-länder, pulsande pins
Landvex — 6 illustrationer
LV-ILL-01: Contradiction Detection (hero)
Visar: Officiell rapport (dokument-ikon) ← → Faktisk observation (kamera-ikon)
Mittenpil med "≠" (contradiction marker)
Animation: dokumentet och kameran "pulsar" mot mitten
LV-ILL-02: Intelligence Pipeline (methodology)
Observation → Collection → AI Analysis → Scoring → Report → Decision
6 noder, connectors, ikoner per steg
LV-ILL-03: Control Intelligence Output
Dashboard-mockup med score (0-100 gauge) + trend + alert
LV-ILL-04: Data Coverage Map
Polygon-overlay på karta + coverage percentage
"94% commercial facade coverage, Södermalm, updated <30 days"
LV-ILL-05: Enterprise Client Flow
Request → Deploy → Collect → Analyse → Deliver
LV-ILL-06: Zoomer Network (quiXzoom → Landvex bridge)
Många prickar (Zoomers) → Aggregation-nod → Intelligence-output
Visuellt förklarar relationen mellan QX och LV
Content Ratio Target
Per sida (desktop, above-the-fold):
Hero: 60% visual / 40% text
Feature section: 50% visual / 50% text
Proof/social: 30% visual / 70% text (social proof är text-tungt by nature)
CTA section: 70% visual / 30% text
Globalt per sida:
illustrations + UI: 40%
data + charts: 20%
text: 40%
Workflow Diagram — quiXzoom How it Works
SVG-spec för QX-ILL-02 (inline, production-ready):
<!-- QX-ILL-02: How it Works — 4 Steps -->
<svg viewBox="0 0 800 120" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="How quiXzoom works: Browse, Claim, Photograph, Get Paid">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#0066FF" opacity="0.4"/>
</marker>
</defs>
<!-- Step 1: Browse -->
<g transform="translate(60,60)">
<circle r="32" fill="#0066FF" opacity="0.1"/>
<circle r="32" fill="none" stroke="#0066FF" stroke-width="1.5" opacity="0.3"/>
<!-- Map pin icon -->
<path d="M0-14 C-8-14 -14-8 -14 0 C-14 10 0 20 0 20 C0 20 14 10 14 0 C14-8 8-14 0-14Z" fill="none" stroke="#0066FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="0" cy="0" r="4" fill="#0066FF"/>
<!-- Label -->
<text y="50" text-anchor="middle" font-family="system-ui,sans-serif" font-size="13" fill="#3a3a3a" font-weight="600">Browse</text>
<text y="64" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="#6B6B6B">Find a mission near you</text>
</g>
<!-- Arrow 1→2 -->
<line x1="105" y1="60" x2="195" y2="60" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="4 3" opacity="0.4" marker-end="url(#arrow)"/>
<!-- Step 2: Claim -->
<g transform="translate(230,60)">
<circle r="32" fill="#0066FF" opacity="0.1"/>
<circle r="32" fill="none" stroke="#0066FF" stroke-width="1.5" opacity="0.3"/>
<!-- Handshake/check icon -->
<path d="M-10-6 L-4 0 L10-8" fill="none" stroke="#0066FF" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="-14" y="-14" width="28" height="28" rx="6" fill="none" stroke="#0066FF" stroke-width="1.5" opacity="0.5"/>
<text y="50" text-anchor="middle" font-family="system-ui,sans-serif" font-size="13" fill="#3a3a3a" font-weight="600">Claim</text>
<text y="64" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="#6B6B6B">Accept the brief</text>
</g>
<!-- Arrow 2→3 -->
<line x1="275" y1="60" x2="365" y2="60" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="4 3" opacity="0.4" marker-end="url(#arrow)"/>
<!-- Step 3: Photograph -->
<g transform="translate(400,60)">
<circle r="32" fill="#0066FF" opacity="0.1"/>
<circle r="32" fill="none" stroke="#0066FF" stroke-width="1.5" opacity="0.3"/>
<!-- Camera icon -->
<rect x="-14" y="-8" width="28" height="20" rx="3" fill="none" stroke="#0066FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="0" cy="2" r="6" fill="none" stroke="#0066FF" stroke-width="2"/>
<path d="M-6-8 L-4-12 L4-12 L6-8" fill="none" stroke="#0066FF" stroke-width="1.5" stroke-linecap="round"/>
<text y="50" text-anchor="middle" font-family="system-ui,sans-serif" font-size="13" fill="#3a3a3a" font-weight="600">Photograph</text>
<text y="64" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="#6B6B6B">Submit your photos</text>
</g>
<!-- Arrow 3→4 -->
<line x1="445" y1="60" x2="535" y2="60" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="4 3" opacity="0.4" marker-end="url(#arrow)"/>
<!-- Step 4: Get Paid -->
<g transform="translate(570,60)">
<circle r="32" fill="#00C853" opacity="0.12"/>
<circle r="32" fill="none" stroke="#00C853" stroke-width="1.5" opacity="0.4"/>
<!-- Coin/check icon -->
<circle cx="0" cy="0" r="12" fill="none" stroke="#00C853" stroke-width="2"/>
<path d="M-5 0 L-2 3 L6-4" fill="none" stroke="#00C853" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<text y="50" text-anchor="middle" font-family="system-ui,sans-serif" font-size="13" fill="#3a3a3a" font-weight="600">Get Paid</text>
<text y="64" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="#6B6B6B">Credits paid weekly</text>
</g>
</svg>
Landvex — Contradiction Detection Hero Illustration
<!-- LV-ILL-01: Contradiction Detection -->
<svg viewBox="0 0 600 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Landvex identifies contradictions between reported reality and observed reality">
<defs>
<style>
@media (prefers-reduced-motion: no-preference) {
.pulse-left { animation: pulseLeft 2s ease-in-out infinite; }
.pulse-right { animation: pulseRight 2s ease-in-out 1s infinite; }
@keyframes pulseLeft { 0%,100%{opacity:.7} 50%{opacity:1} }
@keyframes pulseRight { 0%,100%{opacity:.7} 50%{opacity:1} }
}
</style>
</defs>
<!-- LEFT: Official Report -->
<g transform="translate(100,100)" class="pulse-left">
<rect x="-50" y="-60" width="100" height="120" rx="8" fill="#111" stroke="rgba(255,255,255,0.1)" stroke-width="1"/>
<!-- Doc lines -->
<line x1="-30" y1="-30" x2="30" y2="-30" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-linecap="round"/>
<line x1="-30" y1="-16" x2="20" y2="-16" stroke="rgba(255,255,255,0.2)" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-30" y1="-4" x2="25" y2="-4" stroke="rgba(255,255,255,0.2)" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-30" y1="8" x2="15" y2="8" stroke="rgba(255,255,255,0.2)" stroke-width="1.5" stroke-linecap="round"/>
<!-- Green checkmark = "official says OK" -->
<circle cx="0" cy="32" r="14" fill="#00C853" opacity="0.15"/>
<path d="M-6 32 L-2 36 L8 26" fill="none" stroke="#00C853" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<text y="70" text-anchor="middle" font-family="system-ui,sans-serif" font-size="12" fill="rgba(255,255,255,0.5)">Official report</text>
<text y="83" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="rgba(255,255,255,0.3)">No issues found</text>
</g>
<!-- CENTER: Contradiction marker -->
<g transform="translate(300,100)">
<circle r="28" fill="#0066FF" opacity="0.08"/>
<circle r="28" fill="none" stroke="#0066FF" stroke-width="1" opacity="0.3"/>
<!-- ≠ symbol -->
<text text-anchor="middle" dy="7" font-size="28" font-weight="900" fill="#0066FF" opacity="0.8">≠</text>
<!-- Left arrow -->
<line x1="-60" y1="0" x2="-35" y2="0" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="3 2" opacity="0.4"/>
<!-- Right arrow -->
<line x1="35" y1="0" x2="60" y2="0" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="3 2" opacity="0.4"/>
</g>
<!-- RIGHT: Field Observation -->
<g transform="translate(500,100)" class="pulse-right">
<rect x="-50" y="-60" width="100" height="120" rx="8" fill="#111" stroke="rgba(255,255,255,0.1)" stroke-width="1"/>
<!-- Camera icon -->
<rect x="-24" y="-20" width="48" height="34" rx="4" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="1.5"/>
<circle cx="0" cy="-3" r="10" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="1.5"/>
<path d="-10-20 L-8-26 L8-26 L10-20" fill="none" stroke="rgba(255,255,255,0.3)" stroke-width="1.5" stroke-linecap="round"/>
<!-- Red warning = "field says different" -->
<circle cx="0" cy="32" r="14" fill="#FF3B30" opacity="0.15"/>
<line x1="0" y1="25" x2="0" y2="34" stroke="#FF3B30" stroke-width="2.5" stroke-linecap="round"/>
<circle cx="0" cy="39" r="1.5" fill="#FF3B30"/>
<text y="70" text-anchor="middle" font-family="system-ui,sans-serif" font-size="12" fill="rgba(255,255,255,0.5)">Field observation</text>
<text y="83" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="rgba(255,255,255,0.3)">Defects detected</text>
</g>
</svg>
IMPLEMENTATION — PRIORITETSORDNING
Sprint 1 (1–2 veckor): Locale architecture
- Skapa
locale-data.jsbundle med 6 marknader (SE, DE, US, GB, TH, AE) - Implementera market selector component
- Koppla floating mission card i hero till locale bundle
- Koppla demo-kartan till locale mapCenter
- Sätt GeoIP-banner (max 1 fråga per session, kan stängas)
Sprint 2 (2–3 veckor): Illustrationer
- QX-ILL-01: Mission flow animation (hero)
- QX-ILL-02: How it works — 4 steg (inline SVG, klar ovan)
- LV-ILL-01: Contradiction detection (inline SVG, klar ovan)
- LV-ILL-02: Intelligence pipeline
- QX-ILL-03: Tier cards
- QX-ILL-08: Global presence map
Sprint 3 (3–4 veckor): Full propagation
- Onboarding-flow lokalisering
- Skatteinfo per marknad (FAQ-tabs)
- Earnings calculator med lokal valuta
- zoomer-start.html → engelska default + locale-aware
- Resterende illustrationer (QX-ILL-04 through 07, LV-ILL-03 through 06)
LEVERANS TILL DESIGNTEAM
Fil: /home/bernt/.openclaw/workspace/reports/i18n-illustration-spec-2026-06-20.md
Innehåller:
- Fullständig locale-arkitektur med 4 marknaders data-bundles
- Market selector component (HTML + JS)
- Illustration-spec: 14 illustrationer, stil-guide, prioritetsordning
- 2 production-ready SVG-illustrationer (QX-ILL-02 + LV-ILL-01)
- Content ratio targets per sidtyp
- 3-sprints implementation roadmap