# F-074 — Architect: Audit shows real-time logs from application services ## Current state The admin audit page (`/audit`) fetches audit log entries once on mount via `useEffect`. There is **no polling** — new entries only appear after a page refresh. ## Goal Add **polling** to the audit page so new log entries appear automatically without refresh. Entries from application services (product edits, category changes, tax rate toggles, etc.) will show up in real-time on the audit page. ## Scope IN - `project/apps/admin/src/app/(dashboard)/audit/page.tsx`: - Add a `useEffect` with `setInterval` (5 second interval) that fetches the latest entries when `page === 0` (first page) - Prepend new entries to the list (deduplicate by `id`) - Add a `liveIndicator` state to show "● En vivo" when polling is active on page 0 - Stop polling when navigating to page > 0 or when filter is active - Show count of new entries (e.g., "+3 nuevas" badge) when new entries arrive - Clear new entry count when user views them ## Scope OUT - Backend — no changes (existing `GET /admin/audit` is sufficient for polling) - No SSE/WebSocket (simple polling is sufficient) - No changes to the audit logger itself ## Design Polling strategy: ```tsx const [newCount, setNewCount] = useState(0); const [pollingActive, setPollingActive] = useState(false); useEffect(() => { if (page !== 0 || debounced) { setPollingActive(false); return; } setPollingActive(true); const interval = setInterval(async () => { try { const data = await auditApi.list({ limit: PAGE_SIZE, offset: 0 }); const existingIds = new Set(items.map(i => i.id)); const newItems = (data.items ?? []).filter(i => !existingIds.has(i.id)); if (newItems.length > 0) { setItems(prev => [...newItems, ...prev].slice(0, PAGE_SIZE)); setNewCount(prev => prev + newItems.length); } } catch { /* silent */ } }, 5000); return () => { clearInterval(interval); setPollingActive(false); }; }, [page, debounced, items]); ``` UI indicator: ```tsx // In header: {pollingActive && ( En vivo )} {newCount > 0 && ( )} ``` ## Risk - **Low risk**: purely frontend polling, no backend or DB changes - No performance concern: 5-second polling is lightweight - Polling stops automatically when filter is active or on paginated views ## Verification - `npx tsc --noEmit` admin - `npx eslint` on changed file - `./scripts/verify.sh` green - Manual: open audit page, perform an action (e.g. toggle a tax rate), observe new entry appears within 5 seconds