๐Ÿ“„ recently-removed-events.md 3,615 bytes Apr 24, 2026 ๐Ÿ“‹ Raw

Recently Removed Events API Spec

For: Home Dashboard "Recently Removed" widget
Status: Backend ready โ€” awaiting frontend implementation
Owner: Socrates (backend) / Daedalus (frontend)

Related Spec: See Daedalus' frontend implementation spec at
workspace-daedalus/dashboard/REMOVED-WIDGET-SPEC.md


Auth

For production, use session-based auth or proxy pattern โ€” never expose the secret in browser HTML. See "Security Notes" below.


Endpoint

GET /family/events/removed

Auth: X-Hoffdesk-Secret header (same as webhook)

Query Parameters

Param Type Default Description
hours int 24 How far back to look
limit int 20 Max results to return

Response

{
  "removals": [
    {
      "uid": "dceb54d1-2cc4-4d1c-9210-775a1c0c8442",
      "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"
}

Fields

Field Type Description
uid string Event unique ID (Radicale UID)
summary string Event title
start_time ISO 8601 When event was scheduled
removed_at ISO 8601 When it was deleted
removed_by string Who removed it (telegram_user_{chat_id})
source string Where it came from: newsletter, appointment, family
reason string Why it was removed (optional)
can_undo boolean Always false โ€” Radicale doesn't support undo

UI Suggestions

Widget Design:
- Compact list (max 5 items visible, scroll for more)
- Show: summary + start_time (formatted nicely)
- Subtle timestamp: "Removed 2 hours ago"
- Group by source with icons: ๐Ÿ“ฐ newsletter, ๐Ÿ“ง appointment, etc.

Example Layout:

โ”Œโ”€ Recently Removed โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ๐Ÿ“ฐ Softball Tryups                 โ”‚
โ”‚    Apr 28, 3:30 PM ยท 2h ago        โ”‚
โ”‚ ๐Ÿ“ฐ Spirit Week                     โ”‚
โ”‚    Apr 28-30 ยท 5h ago              โ”‚
โ”‚                                    โ”‚
โ”‚ [View All โ†’]                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Empty State:
- Hide widget entirely if count === 0
- Or show: "No events removed recently โ€” all good!"

Integration Notes

  • Poll every 30-60 seconds if user is on dashboard
  • Or refresh on dashboard load
  • No real-time WebSocket (not needed for this)

Security Notes

โš ๏ธ Never expose X-Hoffdesk-Secret in browser HTML or JavaScript.

Recommended patterns:

Pattern How Security
Session cookie (best) User logs in โ†’ session cookie โ†’ server validates Secret stays server-side
Proxy (good for dev) Dashboard server adds header when proxying to API Secret in env, not browser
Meta tag (dev only) <meta name="secret" content="..."> JS reads โŒ Visible in View Source

For production with Aundrea: Use session cookies or proxy pattern. She should never see API secrets.


Backend Behavior

  • Events are logged when user clicks REMOVE button in Telegram
  • Retained for 30 days then auto-purged
  • Logs stored at: hoffdesk-api/data/removed_events.jsonl