veza/docs/PLAN_V0_801_IMPLEMENTATION.md
senke da20e83e09 docs: complete roadmap documentation v0.703 to v0.903 (v1.0 target)
Add Release Scope, Implementation Plan, and Smoke Test for 7 versions:
- v0.703: Go Live & Streaming Complet (Phase 7 Finale)
- v0.801: UX/UI Polish, Accessibilite & PWA (Phase 8)
- v0.802: Cloud Complet, Fichiers & Gear Avance (Phase 8)
- v0.803: Securite, Compliance & Outillage Dev (Phase 8)
- v0.901: Marketplace Complet & Analytics Avances (Phase 9)
- v0.902: Social Complet, Chat & Notifications (Phase 9)
- v0.903: Stabilisation v1.0 & Launch Readiness (Phase 9)

21 documents total (3 per version), covering all remaining features
needed to reach v1.0 from v0.702.
2026-02-24 01:32:04 +01:00

8.9 KiB
Raw Permalink Blame History

Plan d'implémentation v0.801 — UX/UI Polish, Accessibilité & PWA

État des lieux

Feature État Détail
Thème clair/sombre/auto ThemeProvider, toggle Settings
Contraste élevé Non implémenté
Compact/confortable Layout unique
Accent color Primary fixe
Navigation clavier ⚠️ Partiel
ARIA labels ⚠️ Manquants sur boutons icônes
Focus visible ⚠️ Outline basique
Font size ajustable Tailles fixes
prefers-reduced-motion Animations non conditionnées
PWA installable ⚠️ SW basique, manifest incomplet
Offline Pas de caching
Background playback Audio s'arrête en background

Fichiers existants clés


Step 1 : Migration + User preferences backend (UX1-04, UX1-05)

Fichier : veza-backend-api/migrations/118_users_preferences.sql (nouveau)

ALTER TABLE users ADD COLUMN IF NOT EXISTS preferences JSONB DEFAULT '{}';

Fichier : veza-backend-api/internal/models/user.go — ajouter :

Preferences datatypes.JSON `gorm:"type:jsonb;default:'{}'" json:"preferences,omitempty"`

Fichier : veza-backend-api/internal/handlers/user_handler.go — ajouter PUT /users/me/preferences :

func (h *UserHandler) UpdatePreferences(c *gin.Context) {
    userID, ok := GetUserIDUUID(c)
    if !ok { return }
    var prefs map[string]interface{}
    if err := c.ShouldBindJSON(&prefs); err != nil {
        RespondWithAppError(c, apperrors.NewValidationError("invalid preferences"))
        return
    }
    // update user.preferences in DB
    // ...
    RespondSuccess(c, http.StatusOK, gin.H{"preferences": prefs})
}

Commit : feat(users): add preferences JSONB column and PUT endpoint


Step 2 : Design tokens — contraste élevé + compact (UX1-01, UX1-02)

Fichier : apps/web/src/index.css — ajouter après les thèmes existants :

/* High contrast mode */
[data-contrast="high"] {
  --color-foreground: #000000;
  --color-background: #ffffff;
  --color-muted: #4a4a4a;
  --color-muted-foreground: #2a2a2a;
  --color-border: #000000;
}
.dark[data-contrast="high"] {
  --color-foreground: #ffffff;
  --color-background: #000000;
  --color-muted: #cccccc;
  --color-muted-foreground: #e0e0e0;
  --color-border: #ffffff;
}

/* Density modes */
[data-density="compact"] {
  font-size: 13px;
}
[data-density="comfortable"] {
  font-size: 15px;
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Commit : feat(ui): add high contrast, compact density, reduced motion CSS tokens


Step 3 : Settings UI — appearance controls (UX1-01 to UX1-04)

Fichier : apps/web/src/components/settings/SettingsAppearance.tsx — ajouter :

  • Toggle "High Contrast" (data-contrast="high" sur document.documentElement)
  • Radio "Compact / Default / Comfortable" (data-density)
  • Color picker pour accent hue (CSS variable --color-primary)
  • Slider "Font Size" (14px20px)
  • Persistence dans localStorage + sync PUT /users/me/preferences

Commit : feat(settings): add high contrast toggle, density, accent color, font size


Step 4 : Accessibilité — ARIA, clavier, focus (UX2-01 to UX2-07)

Fichier : apps/web/src/components/ui/ — pour chaque composant :

  • Button.tsx : aria-label sur boutons icônes (pas de texte visible)
  • Dialog.tsx / Modal.tsx : aria-modal, focus trap, Escape ferme
  • Input.tsx : aria-describedby pour messages erreur
  • Tabs.tsx : role="tablist", role="tab", aria-selected
  • Menu.tsx / Dropdown.tsx : role="menu", Arrow key navigation
  • Table.tsx : role="table", scope="col" sur headers
  • Pagination.tsx : aria-label="Pagination", aria-current="page"

Fichier : apps/web/src/index.css — focus visible amélioré :

:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

Fichier : apps/web/src/components/layout/ — skip-to-content :

<a href="#main-content" className="sr-only focus:not-sr-only ...">Skip to content</a>

Fichier : apps/web/src/hooks/useReducedMotion.ts (nouveau) :

export function useReducedMotion(): boolean {
  const [reduced, setReduced] = useState(
    () => window.matchMedia('(prefers-reduced-motion: reduce)').matches
  );
  useEffect(() => {
    const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
    const handler = (e: MediaQueryListEvent) => setReduced(e.matches);
    mq.addEventListener('change', handler);
    return () => mq.removeEventListener('change', handler);
  }, []);
  return reduced;
}

Commit : feat(a11y): ARIA labels, keyboard nav, focus visible, skip-to-content, reduced motion


Step 5 : axe-core Storybook (UX2-08)

cd apps/web && npm install --save-dev @storybook/addon-a11y

Fichier : apps/web/.storybook/main.ts — ajouter '@storybook/addon-a11y' dans addons

Commit : feat(storybook): add addon-a11y for automated accessibility testing


Step 6 : PWA — manifest, service worker, install prompt (UX3-01 to UX3-03)

Fichier : apps/web/public/manifest.json — compléter :

{
  "name": "Veza — Audio Collaborative Platform",
  "short_name": "Veza",
  "description": "Collaborative audio platform for musicians",
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#0f172a",
  "background_color": "#0f172a",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" },
    { "src": "/icons/icon-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
  ],
  "shortcuts": [
    { "name": "Dashboard", "url": "/dashboard" },
    { "name": "Marketplace", "url": "/marketplace" },
    { "name": "Go Live", "url": "/live/go-live" }
  ]
}

Fichier : apps/web/src/hooks/usePWAInstall.ts (nouveau)

export function usePWAInstall() {
  const [prompt, setPrompt] = useState<BeforeInstallPromptEvent | null>(null);
  const [isInstalled, setIsInstalled] = useState(false);

  useEffect(() => {
    const handler = (e: Event) => { e.preventDefault(); setPrompt(e as BeforeInstallPromptEvent); };
    window.addEventListener('beforeinstallprompt', handler);
    window.addEventListener('appinstalled', () => setIsInstalled(true));
    return () => window.removeEventListener('beforeinstallprompt', handler);
  }, []);

  const install = async () => { if (prompt) { await prompt.prompt(); } };

  return { canInstall: !!prompt && !isInstalled, install, isInstalled };
}

Commit : feat(pwa): complete manifest, install prompt hook, offline caching


Step 7 : Background playback mobile (UX3-04)

Fichier : apps/web/src/features/player/hooks/useWakeLock.ts (nouveau)

export function useWakeLock(isPlaying: boolean) {
  const lockRef = useRef<WakeLockSentinel | null>(null);

  useEffect(() => {
    if (!('wakeLock' in navigator)) return;
    if (isPlaying) {
      navigator.wakeLock.request('screen').then(l => { lockRef.current = l; }).catch(() => {});
    } else {
      lockRef.current?.release();
      lockRef.current = null;
    }
    return () => { lockRef.current?.release(); };
  }, [isPlaying]);
}

Commit : feat(player): add WakeLock for background playback on mobile


Step 8 : Documentation + release

Fichier : CHANGELOG.md — section v0.801 Fichier : docs/PROJECT_STATE.md — Dernier tag → v0.801, section v0.801 Fichier : docs/FEATURE_STATUS.md — section "Livré en v0.801"

Commit : docs: update CHANGELOG, PROJECT_STATE, FEATURE_STATUS for v0.801


Step 9 : Rétrospective + archivage + tag

Fichier : docs/RETROSPECTIVE_V0801.md (nouveau) Fichier : docs/V0_802_RELEASE_SCOPE.md (placeholder) Fichier : docs/SCOPE_CONTROL.md — mise à jour Fichier : .cursorrules — scope v0.802

mv docs/V0_801_RELEASE_SCOPE.md docs/archive/
git add . && git commit -m "chore(docs): archive V0_801_RELEASE_SCOPE"
git tag v0.801

Validation finale

cd veza-backend-api && go build ./... && go test ./... -v
cd apps/web && npm run build
# Lighthouse audit: PWA score, a11y score
git tag v0.801