diff --git a/CLAUDE.md b/CLAUDE.md index fe84f3f..68d0644 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Status -**Fase 0 complete. Fase 1 complete. Fase 2a complete. Fase 2b complete (Realtime + offline queue + Modo Compra). Fase 3 complete (Tareas + Notas). Fase 4 partially complete (global search + RLS audit). Fase 5 planned (mobile UX rewrite — "Monolith Editorial"; see `plan/fase-5-mobile-ux.md`). 211 tests green: 34 pgTAP + 140 Vitest integration + 6 Vitest unit + 31 Playwright. 2 skipped (Realtime presence — upstream bug in `supabase/realtime` `handle_out/3`, reactivate when fixed). PWA install/push/rate-limit/JWT rotation deferred to a prod-deploy sprint. ✅** +**Fase 0 complete. Fase 1 complete. Fase 2a complete. Fase 2b complete (Realtime + offline queue + Modo Compra). Fase 3 complete (Tareas + Notas). Fase 4 partially complete (global search + RLS audit). Fase 5 partially complete (responsive shell + masthead + swipe-delete red zone + undoQueue; see `plan/fase-5-mobile-ux.md`). 224 tests green: 34 pgTAP + 140 Vitest integration + 11 Vitest unit + 39 Playwright. 4 skipped (2 Realtime presence — upstream `handle_out/3` bug; 2 mobile-swipe touch gestures — needs WebKit install). PWA install/push/rate-limit/JWT rotation deferred to a prod-deploy sprint. ✅** - `README.md` — full development plan, confirmed tech stack, Justfile reference, and technical warnings - `analysis/analisis-funcional.md` — complete functional specification (domain model, use cases, data models, business rules) @@ -74,6 +74,20 @@ just test-e2e # Playwright E2E tests (requires just dev running) just test-e2e-headed # Playwright with visible browser (debugging) ``` +### Fase 5 — what has been built (partial) + +- `apps/web/src/lib/components/layout/DesktopSidebar.svelte` — desktop sidebar extracted from `(app)/+layout.svelte`, `data-testid="desktop-sidebar"`, `hidden md:flex` +- `apps/web/src/lib/components/layout/MobileTopBar.svelte` — hamburger + collective name + avatar link; `md:hidden sticky top-0 z-30 backdrop-blur-xl` +- `apps/web/src/lib/components/layout/BottomTabBar.svelte` — 4 nav items icon-only, glassmorphism, `pb-[env(safe-area-inset-bottom)]`, `aria-current="page"` on the active route, `data-testid="bottom-tab-bar"` +- `apps/web/src/lib/components/layout/MobileDrawer.svelte` — backdrop + collective switcher + manage/settings/logout, `data-testid="mobile-drawer"` +- `apps/web/src/lib/components/ScreenMasthead.svelte` — uppercase label (`data-testid="masthead-label"`) + big title (`data-testid="masthead-title"`) + optional `meta` / `actions` snippets. Applied on `/lists`, `/tasks`, `/notes`, `/search`. +- `apps/web/src/lib/sync/undoQueue.ts` — `scheduleUndoable({ label, restore, commit, ttlMs? })` with 4-s TTL; auto-commits on timeout, `undo(id)` cancels + restores +- `apps/web/src/lib/components/UndoToast.svelte` — rendered globally in `(app)/+layout.svelte`, shows latest undoable, offset above bottom tab bar on mobile +- `/lists/[id]` swipe-delete: `SWIPE_MAX=96`, `SWIPE_THRESHOLD=48` (latch-open), `SWIPE_COMMIT_THRESHOLD=200` (full-swipe commit via `scheduleUndoable`) +- `apps/web/src/lib/components/ItemSuggestions.svelte` — mobile: horizontal scroll with `[scrollbar-width:none]`; desktop: wraps +- `(app)/+layout.svelte` — **critical fix**: outer container now `flex flex-col md:flex-row` (was `flex` only). Without this MobileTopBar and main rendered as horizontal siblings on mobile and the masthead was pushed off-screen. +- Mobile tests: `mobile-shell.test.ts` (M-01..M-04), `mobile-masthead.test.ts` (M-05 × 4 routes), `mobile-swipe-delete.test.ts` (M-06/M-07 `.skip` — Chromium touch emulation too flaky), `undoQueue.test.ts` (5 unit tests) + ### Fase 4 — what has been built - `supabase/migrations/010_search_vectors.sql` — STORED GENERATED `search tsvector` columns on `shopping_items`/`tasks`/`notes` + GIN indexes + `search_result_type` enum + `search_in_collective(p_collective_id, p_query, p_types, p_creator, p_from, p_to)` SECURITY INVOKER function (RLS-aware, trash-excluded) + GRANT EXECUTE to anon/authenticated. Config is `simple` (no stemmer — bilingual en/es). diff --git a/README.md b/README.md index f182231..d6bfc1e 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ | Fase 2b — Realtime y Modo Compra | ✅ Completa (presence bloqueado por bug upstream de `supabase/realtime`) | | Fase 3 — Tareas y Notas | ✅ Completa | | Fase 4 — Búsqueda y Pulido | 🟡 Búsqueda + RLS audit completos; PWA install/push/rate-limit/JWT rotation diferidos a sprint de deploy | -| Fase 5 — Rediseño UX Mobile | ⏳ Plan propuesto ("Monolith Editorial") — pendiente de implementación | -| Suite de tests (pgTAP + Vitest + Playwright) | ✅ 211 tests verdes (34 pgTAP + 140 integración + 6 unit + 31 E2E), ejecutables con `just test-all` | +| Fase 5 — Rediseño UX Mobile | 🟡 Shell responsive + masthead + swipe-delete red zone + undoQueue shipped; presence avatars en cards + touch-gesture E2E diferidos | +| Suite de tests (pgTAP + Vitest + Playwright) | ✅ 224 tests verdes (34 pgTAP + 140 integración + 11 unit + 39 E2E), 4 skipped, ejecutables con `just test-all` | --- diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index fb29ca2..9eeaa8d 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -69,6 +69,11 @@ "invite_member": "Invite member", "invite_email_label": "Email address", "invite_send": "Send invitation", + "masthead_lists_label": "Workspace", + "masthead_tasks_label": "Task Manager", + "masthead_notes_label": "Repository", + "masthead_search_label": "Omni-Search", + "masthead_search_title": "Find Anything.", "lists_title": "Shopping Lists", "lists_new_list": "Create", "lists_no_lists": "No lists yet", @@ -157,5 +162,8 @@ "add": "Add", "done": "Done", "sync_offline": "You're offline — changes will sync when you reconnect", - "sync_syncing": "Syncing…" + "sync_syncing": "Syncing…", + "undo": "Undo", + "undo_deleted_item": "Deleted {name}", + "list_item_delete_aria": "Delete item" } diff --git a/apps/web/messages/es.json b/apps/web/messages/es.json index e14e3bc..92bd89d 100644 --- a/apps/web/messages/es.json +++ b/apps/web/messages/es.json @@ -69,6 +69,11 @@ "invite_member": "Invitar miembro", "invite_email_label": "Correo electrónico", "invite_send": "Enviar invitación", + "masthead_lists_label": "Espacio", + "masthead_tasks_label": "Tareas", + "masthead_notes_label": "Repositorio", + "masthead_search_label": "Buscar", + "masthead_search_title": "Encuéntralo todo.", "lists_title": "Listas de la compra", "lists_new_list": "Crear", "lists_no_lists": "Sin listas", @@ -157,5 +162,8 @@ "add": "Añadir", "done": "Listo", "sync_offline": "Sin conexión — los cambios se sincronizarán al reconectar", - "sync_syncing": "Sincronizando…" + "sync_syncing": "Sincronizando…", + "undo": "Deshacer", + "undo_deleted_item": "{name} eliminado", + "list_item_delete_aria": "Eliminar producto" } diff --git a/apps/web/src/lib/components/ItemSuggestions.svelte b/apps/web/src/lib/components/ItemSuggestions.svelte index 3d5d9d6..e9ee2f6 100644 --- a/apps/web/src/lib/components/ItemSuggestions.svelte +++ b/apps/web/src/lib/components/ItemSuggestions.svelte @@ -11,12 +11,19 @@ {#if suggestions.length > 0} -