# Recently Removed Events โ€” Frontend Widget **For:** Socrates ๐Ÿง  **From:** Daedalus ๐ŸŽจ **Date:** 2026-04-24 **Status:** Frontend complete โ€” awaiting backend wiring --- ## What's Built ### Dashboard Widget A new "Recently Removed" card added to the HoffDesk family dashboard (`dashboard/templates/index.html`): - **JS-driven polling** โ€” calls `GET /family/events/removed?hours=24&limit=5` every 60 seconds - **Hidden by default** โ€” card starts `display: none`, only appears when `count > 0` - **Source icons:** ๐Ÿ“ฐ newsletter, ๐Ÿ“ง appointment, ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ family, ๐Ÿ“… fallback - **Strikethrough titles** โ€” removed event summaries are visually struck through with muted opacity - **Relative timestamps** โ€” "removed 2h ago" format - **Smart date display** โ€” "Today 3:30 PM", "Tomorrow 10:00 AM", "Apr 28 3:30 PM" ### CSS (in `dashboard/static/style.css`) New classes added: - `.removed-list` โ€” flex column layout matching `.event-list` - `.removed-item` โ€” row with icon + details, hover state - `.removed-icon` โ€” emoji source indicator - `.removed-summary` โ€” struck-through event title - `.removed-meta` โ€” time + relative removal timestamp --- ## Integration Notes ### Endpoint Expected ``` GET /family/events/removed?hours=24&limit=5 Header: X-Hoffdesk-Secret: ``` ### Response Format ```json { "removals": [ { "uid": "dceb54d1-...", "summary": "Softball Tryouts", "start_time": "2026-04-28T15:30:00", "removed_at": "2026-04-24T01:35:22.184532", "removed_by": "telegram_user_-5296734042", "source": "newsletter", "reason": "User clicked REMOVE button", "can_undo": false } ], "count": 1, "hours": 24, "timestamp": "2026-04-24T01:36:00.000000" } ``` ### Auth (Updated 2026-04-24 โ€” per Socrates' security review) **โš ๏ธ Never expose `X-Hoffdesk-Secret` in browser HTML or JavaScript.** | Pattern | How | Security | Status | |---------|-----|----------|--------| | **Proxy** (production) | Dashboard server adds header when proxying to API | โœ… Secret stays server-side | Recommended | | **Session cookie** (production) | User logs in โ†’ session cookie โ†’ server validates | โœ… Secret stays server-side | Recommended | | **Meta tag** (dev only) | `` JS reads | โŒ Visible in View Source | Dev only | **Current implementation:** JS sends the request without a secret header. In production, the dashboard dev server should proxy the request and inject `X-Hoffdesk-Secret` server-side. For local dev, a `` tag can be added to the HTML. **For Aundrea's production access:** Use session cookies or proxy pattern. She should never see API secrets. ### Behavior Rules | Condition | Behavior | |-----------|----------| | `count === 0` | Hide card entirely (`display: none`) | | `count > 0` | Show card with up to 5 items | | Network error | Hide card, log error to console | | `can_undo === true` | (Future) Show undo button โ€” not yet implemented | ### Files Changed | File | Change | |------|--------| | `dashboard/templates/index.html` | Added removed-card section, JS fetch/renderer, helpers | | `dashboard/static/style.css` | Added `.removed-*` classes | --- ## No Backend Changes Needed From Socrates The API spec in `shared/api-specs/recently-removed-events.md` already matches what the frontend expects. Just confirm the endpoint is live and returns the documented format. --- ## Future Enhancements (v2) - Undo button when `can_undo === true` (currently always `false` per Radicale limitations) - "View All โ†’" link to expand beyond 5 items - Group by source with section headers