# Event Management Page (`event-management.html`)

## Overview

A unified page for managing **all of the user's Nostr events** across every kind. Three-column drill-down layout: Kinds → Events → Relay Status. Supports deletion (kind 5) with per-relay verification, and blocking (via `mute-list.mjs` kind 10000) as a fallback when deletion fails.

## Existing Infrastructure

| Component | Location | Role |
|---|---|---|
| Mute/block list | [`mute-list.mjs`](../www/js/mute-list.mjs) | NIP-51 kind:10000 — `addMute('e', eventId, isPrivate)` blocks an event across all pages |
| Block UI | [`block.html`](../www/block.html) | Manages mute list entries (pubkeys, hashtags, words, event IDs) |
| DB browser | [`db.html`](../www/db.html) | Reads IndexedDB `ndk-shared` store, grouped by kind |
| Event editor | [`event.html`](../www/event.html) | Loads/edits/reposts individual events by kind |
| Publish flow | [`init-ndk.mjs`](../www/js/init-ndk.mjs:473) `publishEvent()` → [`ndk-worker.js`](../www/ndk-worker.js:4842) `handlePublish()` | Returns `relayResults.successful[]` and `relayResults.failed[]` |
| Per-relay fetch | [`init-ndk.mjs`](../www/js/init-ndk.mjs:609) `fetchEventsFromAllRelays()` | Currently wraps `ndkFetchEvents` — returns combined, not per-relay |
| NDK subscribe | [`init-ndk.mjs`](../www/js/init-ndk.mjs) `subscribe()` | Live subscription with `ndkEvent` window events |

## Architecture

### Three-Column Layout

```mermaid
graph LR
    A[Left Column: Kind List] -->|click kind| B[Center Column: Events for Kind]
    B -->|click event| C[Right Column: Relay Detail + Actions]
```

**Left Column — Kind Summary**
- On page load, reads IndexedDB cache to build a list of kinds the user has published
- Each row: kind number, human-readable label, event count
- Clicking a kind populates the center column
- Optional "Refresh from Relays" button to hydrate from live relay data

**Center Column — Events for Selected Kind**
- Lists all events of the selected kind, sorted by `created_at` descending
- Each row shows: truncated event ID, d-tag or content preview, timestamp
- For addressable events (kinds 30000+): shows the d-tag as primary identifier
- Clicking an event populates the right column
- Batch actions: "Select All" checkbox for bulk delete

**Right Column — Event Detail + Relay Status + Actions**
- Shows full event JSON (collapsible, like db.html raw modal)
- Relay presence table: which relays have this event
- Action buttons: Delete, Block, Copy JSON
- After delete: per-relay verification results

### Startup Flow

```mermaid
flowchart TD
    A[Page Load] --> B[Read IndexedDB ndk-shared]
    B --> C[Group cached events by kind]
    C --> D[Render Kind List in left column]
    D --> E[User clicks a kind]
    E --> F[Show cached events for that kind]
    F --> G[Optional: Subscribe for live updates]
    G --> H[User clicks an event]
    H --> I[Show event detail + relay info]
```

The page starts **fast** by reading only from IndexedDB. No relay queries on startup. Relay hydration happens lazily:
1. When the user clicks a kind, a background subscription fetches fresh data for that kind
2. When the user clicks an event and wants relay detail, we query individual relays

### Repost / Copy to All Relays Flow

When the relay status table shows an event exists on only some relays, the user can "Repost to All Relays" to spread it to every connected relay. This reuses the existing `publishRawEvent` worker message (same as `event.html`'s "Repost as-is" feature) — the event is already signed, so it gets published without re-signing.

```mermaid
flowchart TD
    A[User clicks Repost to All Relays] --> B[Send already-signed event via publishRawEvent]
    B --> C[Show relayResults.successful and relayResults.failed]
    C --> D[Update relay status table with new presence]
```

### Delete Flow

```mermaid
flowchart TD
    A[User clicks Delete] --> B[Confirm dialog]
    B --> C[Publish kind 5 deletion event]
    C --> D[Show which relays accepted the delete request]
    D --> E[Wait 2-3 seconds]
    E --> F[Re-query each relay individually for the event]
    F --> G{Event still present?}
    G -->|Yes| H[Show relay as: Delete failed - offer Block]
    G -->|No| I[Show relay as: Deleted successfully]
```

### Block Flow

When deletion fails on some relays, the user can block the event:
- Calls `addMute('e', eventId, isPrivate)` from [`mute-list.mjs`](../www/js/mute-list.mjs:269)
- This adds the event ID to the kind:10000 mute list
- All other pages that call `isEventMuted()` will filter it out
- The block is immediate and works regardless of relay cooperation

### Per-Relay Query Enhancement

The current [`fetchEventsFromAllRelays()`](../www/js/init-ndk.mjs:609) returns combined results, not per-relay. We need a new worker message type to query a specific relay for a specific event:

**New worker message: `queryRelay`**
- Input: `{ type: 'queryRelay', relayUrl, filter, requestId }`
- Opens a temporary connection to the specific relay (or uses existing pool connection)
- Returns events found on that specific relay
- Used for post-delete verification

## Implementation Plan

### Phase 1: Page Shell + Kind List from Cache

- [ ] Create `event-management.html` with standard page template (header, footer, sidenav, hamburger)
- [ ] Three-column responsive CSS layout (collapses to stacked on mobile)
- [ ] On init: open IndexedDB `ndk-shared`, read all events, group by kind
- [ ] Render left column with kind list (kind number, label, count)
- [ ] Kind label lookup table for common kinds (0=Profile, 1=Note, 3=Contacts, 10002=Relay List, 30023=Article, 31123=Skill, etc.)

### Phase 2: Event List for Selected Kind

- [ ] Click a kind → populate center column with events of that kind
- [ ] Show event ID (truncated), d-tag for addressable kinds, content preview, created_at date
- [ ] Sort by created_at descending
- [ ] Filter/search input for the event list
- [ ] Pagination or virtual scroll for kinds with many events
- [ ] Background subscription to hydrate fresh events for the selected kind

### Phase 3: Event Detail + Relay Status

- [ ] Click an event → populate right column with full detail
- [ ] Collapsible raw JSON viewer
- [ ] Parsed tag display (key tags shown as labeled fields)
- [ ] "Check Relays" button that queries each connected relay for this event
- [ ] Relay status table: relay URL, status icon (present/absent/checking)
- [ ] "Repost to All Relays" button — republishes the already-signed event to all connected relays (uses `publishRawEvent` worker message, same as event.html's Repost feature)
- [ ] After repost: update relay status table showing which relays now have the event

### Phase 4: Delete with Per-Relay Verification

- [ ] Delete button → confirmation dialog
- [ ] Publish kind 5 deletion request via `publishEvent()`
- [ ] Display which relays accepted the deletion request (from `relayResults`)
- [ ] After short delay, re-query each relay to verify event removal
- [ ] Update relay status table with verification results (deleted / still present / error)
- [ ] Add `queryRelay` message type to `ndk-worker.js` for single-relay queries

### Phase 5: Block Integration

- [ ] Block button on event detail (always available)
- [ ] "Block" button highlighted/suggested when delete verification shows failures
- [ ] Calls `addMute('e', eventId, isPrivate)` from `mute-list.mjs`
- [ ] Private/public toggle for the block (default: private)
- [ ] Visual indicator if event is already blocked
- [ ] Configure mute list on page init (same pattern as `block.html`)

### Phase 6: Polish + Batch Operations

- [ ] Batch select events in center column
- [ ] Batch delete selected events
- [ ] Batch block selected events
- [ ] Export selected events as JSON
- [ ] Kind list refresh button (re-subscribe to all user events)
- [ ] Status bar showing operation progress

## File Changes

| File | Change |
|---|---|
| `www/event-management.html` | **New** — full page |
| `www/ndk-worker.js` | Add `queryRelay` message handler for single-relay event queries |
| `www/js/init-ndk.mjs` | Add `queryRelay()` export that sends the new message type |

## UI Wireframe

```
┌─────────────────────────────────────────────────────────────────────┐
│ ☰  Event Management                                        [avatar]│
├──────────────┬──────────────────────┬───────────────────────────────┤
│ Kinds        │ Events (Kind 1)      │ Event Detail                  │
│              │                      │                               │
│ [search]     │ [search/filter]      │ ID: abc123...                 │
│              │                      │ Created: 2025-01-15           │
│  0  Profile 1│ ☐ abc1.. 2025-01-15 │ Content: Hello world...       │
│  1  Notes  47│ ☑ def2.. 2025-01-14 │                               │
│  3  Contacts │ ☐ ghi3.. 2025-01-13 │ ┌─ Raw JSON ──────────────┐  │
│  7  Reactions│ ☐ jkl4.. 2025-01-12 │ │ { "kind": 1, ... }      │  │
│ 10002 Relays │                      │ └─────────────────────────┘  │
│ 30023 Article│                      │                               │
│ 31123 Skills │                      │ Relay Status:                 │
│              │                      │ ✅ wss://relay1  present      │
│              │                      │ ✅ wss://relay2  present      │
│              │                      │ ❌ wss://relay3  not found    │
│              │                      │                               │
│              │ [Delete Selected]    │ [Repost All] [Delete] [Block] │
│              │                      │ [Copy JSON]                   │
│ [Refresh]    │                      │ Delete Results:               │
│              │                      │ ✅ relay1: deleted             │
│              │                      │ ⚠️ relay2: still present      │
│              │                      │   → [Block this event]        │
├──────────────┴──────────────────────┴───────────────────────────────┤
│ footer: relay status                                        0 sats  │
└─────────────────────────────────────────────────────────────────────┘
```

## Kind Label Reference

| Kind | Label |
|---|---|
| 0 | Profile |
| 1 | Note |
| 3 | Contacts |
| 4 | Encrypted DM |
| 5 | Deletion |
| 6 | Repost |
| 7 | Reaction |
| 10000 | Mute List |
| 10002 | Relay List |
| 10123 | Skill Adoption |
| 30023 | Long-form Article |
| 30024 | Draft Article |
| 30078 | App-specific Data |
| 31123 | Skill (Public) |
| 31124 | Skill (Private) |

## Responsive Behavior

- **Desktop (>1280px)**: Three columns side by side
- **Tablet (800-1280px)**: Two columns (kinds + events), detail as overlay/modal
- **Mobile (<800px)**: Single column, drill-down navigation with back buttons
