# Ginxsom Management System Design

## Executive Summary

This document outlines the design for a secure management interface for ginxsom, a Blossom media storage server. The design adapts proven patterns from c-relay's management system while addressing ginxsom's specific requirements for blob storage, authentication, and FastCGI architecture.

**Key Design Principles:**
- **Security First**: NIP-17 gift wrap encryption for all admin commands
- **Database-Centric**: Configuration and state stored in SQLite
- **Unified Handler**: Tag-based routing similar to c-relay
- **Two-Step Confirmation**: Critical operations require explicit confirmation
- **Backwards Compatible**: Integrates with existing admin API without breaking changes

---

## Table of Contents

1. [System Architecture](#1-system-architecture)
2. [Database Schema](#2-database-schema)
3. [Keypair Management](#3-keypair-management)
4. [Authentication Architecture](#4-authentication-architecture)
5. [Management Commands](#5-management-commands)
6. [API Design](#6-api-design)
7. [File Structure](#7-file-structure)
8. [Implementation Plan](#8-implementation-plan)
9. [Security Considerations](#9-security-considerations)
10. [Migration Strategy](#10-migration-strategy)

---

## 1. System Architecture

### 1.1 Component Overview

```mermaid
flowchart TB
    subgraph Client["Admin Client"]
        CLI[CLI Tool / nak]
        WEB[Web Interface]
    end
    
    subgraph Gateway["nginx Gateway"]
        NGINX[nginx]
    end
    
    subgraph FastCGI["FastCGI Application"]
        MAIN[main.c]
        VALIDATOR[request_validator.c]
        ADMIN[admin_api.c]
        MGMT[management_handler.c<br/>NEW]
        DM[dm_admin.c<br/>NEW]
    end
    
    subgraph Storage["Data Layer"]
        DB[(SQLite Database)]
        BLOBS[Blob Storage]
        KEYS[Key Storage<br/>Memory Only]
    end
    
    CLI -->|NIP-17 Gift Wrap| NGINX
    WEB -->|NIP-17 Gift Wrap| NGINX
    NGINX -->|FastCGI| MAIN
    MAIN --> VALIDATOR
    VALIDATOR --> ADMIN
    ADMIN --> MGMT
    MGMT --> DM
    DM --> DB
    DM --> KEYS
    MGMT --> BLOBS
    
    style MGMT fill:#ff9
    style DM fill:#ff9
    style KEYS fill:#f99
```

### 1.2 Data Flow for Admin Commands

```mermaid
sequenceDiagram
    participant Admin
    participant nginx
    participant FastCGI
    participant Validator
    participant DM Handler
    participant Database
    
    Admin->>nginx: POST /admin<br/>NIP-17 Gift Wrap
    nginx->>FastCGI: Forward Request
    FastCGI->>Validator: Validate Auth
    Validator->>Validator: Decrypt Gift Wrap
    Validator->>Validator: Verify Admin Pubkey
    Validator-->>FastCGI: Auth Result
    
    alt Auth Failed
        FastCGI-->>Admin: 401/403 Error
    else Auth Success
        FastCGI->>DM Handler: Parse Command
        DM Handler->>DM Handler: Extract Tags
        DM Handler->>DM Handler: Route to Handler
        
        alt Critical Operation
            DM Handler->>Database: Store Pending Change
            DM Handler-->>Admin: Confirmation Required
            Admin->>nginx: POST /admin<br/>Confirmation Event
            nginx->>FastCGI: Forward Confirmation
            FastCGI->>DM Handler: Execute Pending
            DM Handler->>Database: Apply Changes
        else Non-Critical
            DM Handler->>Database: Execute Directly
        end
        
        DM Handler->>DM Handler: Encrypt Response (NIP-44)
        DM Handler-->>Admin: Encrypted Result
    end
```

### 1.3 Integration with Existing System

The management system integrates with ginxsom's existing architecture:

**Existing Components (Keep):**
- [`src/main.c`](src/main.c:1): FastCGI request loop and routing
- [`src/request_validator.c`](src/request_validator.c:1): Centralized authentication
- [`src/admin_api.c`](src/admin_api.c:1): Current admin API endpoints
- [`db/schema.sql`](db/schema.sql:1): Base database schema

**New Components (Add):**
- `src/management_handler.c`: Unified command handler
- `src/dm_admin.c`: NIP-17 gift wrap processing
- `src/keypair_manager.c`: Server and admin key management
- `src/pending_changes.c`: Two-step confirmation system

**Modified Components:**
- [`src/main.c`](src/main.c:1640): Add `/admin` endpoint routing
- [`src/request_validator.c`](src/request_validator.c:683): Add NIP-17 validation
- [`db/schema.sql`](db/schema.sql:1): Add management tables

---

## 2. Database Schema

### 2.1 New Tables

```sql
-- Server keypair (relay identity)
CREATE TABLE IF NOT EXISTS server_keys (
    id INTEGER PRIMARY KEY CHECK (id = 1), -- Singleton table
    public_key TEXT NOT NULL CHECK (length(public_key) = 64),
    private_key_encrypted TEXT NOT NULL, -- Encrypted with system key
    created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
    last_rotated INTEGER,
    UNIQUE(public_key)
);

-- Admin public keys (authorized administrators)
CREATE TABLE IF NOT EXISTS admin_keys (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    public_key TEXT NOT NULL UNIQUE CHECK (length(public_key) = 64),
    name TEXT, -- Human-readable identifier
    permissions TEXT NOT NULL DEFAULT 'full', -- JSON array of permissions
    created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
    created_by TEXT, -- Admin pubkey who added this key
    last_used INTEGER,
    enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1))
);

-- Pending changes requiring confirmation
CREATE TABLE IF NOT EXISTS pending_changes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    change_type TEXT NOT NULL, -- 'delete_blob', 'update_config', 'add_admin', etc.
    change_data TEXT NOT NULL, -- JSON with change details
    requested_by TEXT NOT NULL, -- Admin pubkey
    requested_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
    expires_at INTEGER NOT NULL, -- Confirmation deadline
    confirmed INTEGER NOT NULL DEFAULT 0 CHECK (confirmed IN (0, 1)),
    confirmed_at INTEGER,
    executed INTEGER NOT NULL DEFAULT 0 CHECK (executed IN (0, 1)),
    executed_at INTEGER,
    result TEXT -- Execution result or error
);

-- Admin command audit log
CREATE TABLE IF NOT EXISTS admin_audit_log (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    admin_pubkey TEXT NOT NULL,
    command TEXT NOT NULL, -- Command tag from event
    parameters TEXT, -- JSON with command parameters
    success INTEGER NOT NULL CHECK (success IN (0, 1)),
    error_message TEXT,
    timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
    client_ip TEXT,
    event_id TEXT -- Nostr event ID for traceability
);

-- NIP-17 gift wrap tracking (prevent replay)
CREATE TABLE IF NOT EXISTS gift_wrap_tracking (
    event_id TEXT PRIMARY KEY,
    admin_pubkey TEXT NOT NULL,
    processed_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
    expires_at INTEGER NOT NULL
);

-- Create indexes for performance
CREATE INDEX IF NOT EXISTS idx_admin_keys_pubkey ON admin_keys(public_key);
CREATE INDEX IF NOT EXISTS idx_admin_keys_enabled ON admin_keys(enabled);
CREATE INDEX IF NOT EXISTS idx_pending_changes_expires ON pending_changes(expires_at);
CREATE INDEX IF NOT EXISTS idx_pending_changes_requested_by ON pending_changes(requested_by);
CREATE INDEX IF NOT EXISTS idx_audit_log_timestamp ON admin_audit_log(timestamp);
CREATE INDEX IF NOT EXISTS idx_audit_log_admin ON admin_audit_log(admin_pubkey);
CREATE INDEX IF NOT EXISTS idx_gift_wrap_expires ON gift_wrap_tracking(expires_at);
```

### 2.2 Schema Extensions to Existing Tables

```sql
-- Add management-related config keys
INSERT OR IGNORE INTO config (key, value, description) VALUES
    ('server_pubkey', '', 'Server public key (relay identity)'),
    ('admin_dm_enabled', 'true', 'Enable NIP-17 DM-based admin commands'),
    ('admin_confirmation_timeout', '300', 'Seconds to confirm critical operations'),
    ('admin_session_timeout', '3600', 'Admin session timeout in seconds'),
    ('admin_rate_limit', '100', 'Max admin commands per hour per admin'),
    ('admin_audit_retention', '2592000', 'Audit log retention in seconds (30 days)');
```

### 2.3 Migration from Current Schema

The current schema already has:
- [`config`](db/schema.sql:21) table (unified configuration)
- [`blobs`](db/schema.sql:8) table (blob metadata)
- [`auth_rules`](db/schema.sql:47) table (authentication rules)

**Migration Strategy:**
1. Add new tables without modifying existing ones
2. Populate `admin_keys` from existing `config.admin_pubkey`
3. Generate server keypair on first startup if not exists
4. Maintain backwards compatibility with existing admin API

---

## 3. Keypair Management

### 3.1 Server Keypair (Relay Identity)

**Purpose:** Identifies the ginxsom server in Nostr ecosystem

**Generation:**
```c
// On first startup or explicit generation
int generate_server_keypair(void) {
    unsigned char privkey[32];
    unsigned char pubkey[32];
    
    // Generate using nostr_core_lib
    if (nostr_generate_keypair(privkey, pubkey) != NOSTR_SUCCESS) {
        return -1;
    }
    
    // Store in database (encrypted)
    char pubkey_hex[65];
    char privkey_hex[65];
    nostr_bytes_to_hex(pubkey, 32, pubkey_hex);
    nostr_bytes_to_hex(privkey, 32, privkey_hex);
    
    // Encrypt private key before storage
    char encrypted_privkey[256];
    encrypt_with_system_key(privkey_hex, encrypted_privkey);
    
    // Store in database
    return store_server_keypair(pubkey_hex, encrypted_privkey);
}
```

**Storage:**
- Public key: Stored in `server_keys.public_key` and `config.server_pubkey`
- Private key: **NEVER** stored in database - kept in process memory only
- On startup: Load from database, decrypt, keep in memory
- On shutdown: Clear from memory securely

**Command-Line Options:**
```bash
# Generate new server keypair
ginxsom-fcgi --generate-server-key

# Import existing keypair
ginxsom-fcgi --import-server-key <hex_private_key>

# Show server public key
ginxsom-fcgi --show-server-pubkey
```

### 3.2 Admin Keypair Management

**Purpose:** Authorize administrators to manage the server

**Initial Setup:**
```bash
# Generate admin keypair (done by admin, not server)
ADMIN_PRIVKEY=$(nak key generate)
ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)

# Add admin to server (requires existing admin or direct DB access)
sqlite3 db/ginxsom.db << EOF
INSERT INTO admin_keys (public_key, name, permissions, created_by) 
VALUES ('$ADMIN_PUBKEY', 'Primary Admin', '["full"]', 'system');
EOF
```

**Runtime Management:**
```bash
# Add new admin (via DM command)
nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \
    --tag command add_admin \
    --tag pubkey $NEW_ADMIN_PUBKEY \
    --tag name "Secondary Admin" \
    --tag permissions '["read","write"]' \
    | curl -X POST http://localhost:9001/admin -d @-

# List admins
nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \
    --tag command list_admins \
    | curl -X POST http://localhost:9001/admin -d @-

# Revoke admin
nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \
    --tag command revoke_admin \
    --tag pubkey $ADMIN_TO_REVOKE \
    | curl -X POST http://localhost:9001/admin -d @-
```

### 3.3 Key Rotation

**Server Key Rotation:**
- Generate new keypair
- Update database
- Announce new pubkey via NIP-11 relay info
- Keep old key for 30 days for transition

**Admin Key Rotation:**
- Admin generates new keypair
- Uses old key to authorize new key
- Old key remains valid during transition period
- Explicit revocation of old key after confirmation

---

## 4. Authentication Architecture

### 4.1 NIP-17 Gift Wrap Overview

**Why NIP-17?**
- End-to-end encryption between admin and server
- Prevents eavesdropping on admin commands
- Provides forward secrecy
- Standard Nostr protocol (interoperable)

**Gift Wrap Structure:**
```json
{
  "kind": 1059,
  "content": "<encrypted_seal>",
  "tags": [
    ["p", "<server_pubkey>"]
  ],
  "pubkey": "<random_ephemeral_key>",
  "created_at": 1234567890,
  "sig": "<signature>"
}
```

**Seal Structure (encrypted in gift wrap):**
```json
{
  "kind": 13,
  "content": "<encrypted_rumor>",
  "tags": [
    ["p", "<admin_pubkey>"]
  ],
  "pubkey": "<admin_pubkey>",
  "created_at": 1234567890
}
```

**Rumor Structure (encrypted in seal):**
```json
{
  "kind": 14,
  "content": "",
  "tags": [
    ["command", "list_blobs"],
    ["limit", "50"],
    ["offset", "0"]
  ],
  "pubkey": "<admin_pubkey>",
  "created_at": 1234567890
}
```

### 4.2 Authentication Flow

```mermaid
sequenceDiagram
    participant Admin
    participant Server
    participant DB
    
    Admin->>Admin: Create Kind 14 Rumor<br/>(command + params)
    Admin->>Admin: Wrap in Kind 13 Seal<br/>(encrypt with server pubkey)
    Admin->>Admin: Wrap in Kind 1059 Gift<br/>(encrypt with ephemeral key)
    
    Admin->>Server: POST /admin<br/>Gift Wrap Event
    
    Server->>Server: Unwrap Gift<br/>(decrypt with server privkey)
    Server->>Server: Unwrap Seal<br/>(decrypt with admin pubkey)
    Server->>Server: Extract Rumor<br/>(Kind 14 command)
    
    Server->>DB: Check admin_pubkey authorized
    
    alt Not Authorized
        Server-->>Admin: 403 Forbidden
    else Authorized
        Server->>DB: Check gift wrap not replayed
        
        alt Replayed
            Server-->>Admin: 409 Conflict (Replay)
        else Fresh
            Server->>DB: Store gift wrap ID
            Server->>Server: Parse command tags
            Server->>Server: Execute command
            Server->>DB: Log to audit_log
            Server->>Server: Encrypt response (NIP-44)
            Server-->>Admin: Encrypted Response
        end
    end
```

### 4.3 Validation Rules

**Gift Wrap Validation:**
1. Event kind must be 1059
2. Must have `p` tag with server pubkey
3. Signature must be valid
4. Created_at within acceptable time window (±5 minutes)

**Seal Validation:**
1. Decryption must succeed with server private key
2. Event kind must be 13
3. Must have `p` tag with admin pubkey

**Rumor Validation:**
1. Decryption must succeed with admin public key
2. Event kind must be 14
3. Admin pubkey must be in `admin_keys` table with `enabled=1`
4. Must have `command` tag
5. Event ID not in `gift_wrap_tracking` (prevent replay)
6. Created_at within acceptable time window

**Integration with Existing Validator:**

Add to [`src/request_validator.c`](src/request_validator.c:1):

```c
// Add to event kind routing (around line 438)
else if (event_kind == 1059) {
    // NIP-17 Gift Wrap for admin commands
    int gift_wrap_result = validate_gift_wrap_admin(event);
    if (gift_wrap_result != NOSTR_SUCCESS) {
        result->valid = 0;
        result->error_code = gift_wrap_result;
        strcpy(result->reason, "Gift wrap validation failed");
        cJSON_Delete(event);
        return NOSTR_SUCCESS;
    }
}
```

---

## 5. Management Commands

### 5.1 Command Categories

**Blob Operations:**
- `list_blobs` - List blobs with filters
- `get_blob_info` - Get detailed blob metadata
- `delete_blob` - Delete blob (requires confirmation)
- `mirror_blob` - Mirror blob from another server
- `verify_blob` - Verify blob integrity

**Storage Management:**
- `get_storage_stats` - Get storage usage statistics
- `get_disk_usage` - Get disk space information
- `cleanup_orphans` - Remove orphaned files
- `set_quota` - Set storage quota for user

**Configuration:**
- `get_config` - Get configuration values
- `set_config` - Set configuration value (requires confirmation)
- `list_auth_rules` - List authentication rules
- `add_auth_rule` - Add authentication rule
- `remove_auth_rule` - Remove authentication rule (requires confirmation)

**Statistics:**
- `get_stats` - Get server statistics
- `get_upload_stats` - Get upload statistics by time period
- `get_user_stats` - Get per-user statistics
- `get_bandwidth_stats` - Get bandwidth usage

**System:**
- `get_health` - Get system health status
- `get_version` - Get server version info
- `backup_database` - Create database backup
- `restore_database` - Restore from backup (requires confirmation)
- `rotate_logs` - Rotate log files

**Admin Management:**
- `list_admins` - List admin keys
- `add_admin` - Add new admin key (requires confirmation)
- `revoke_admin` - Revoke admin key (requires confirmation)
- `get_audit_log` - Get admin audit log

### 5.2 Command Structure

**Request Format (Kind 14 Rumor):**
```json
{
  "kind": 14,
  "content": "",
  "tags": [
    ["command", "list_blobs"],
    ["limit", "50"],
    ["offset", "0"],
    ["filter_type", "image/*"],
    ["since", "1234567890"]
  ],
  "pubkey": "<admin_pubkey>",
  "created_at": 1234567890
}
```

**Response Format (NIP-44 Encrypted):**
```json
{
  "status": "success",
  "command": "list_blobs",
  "data": {
    "blobs": [...],
    "total": 1234,
    "limit": 50,
    "offset": 0
  },
  "timestamp": 1234567890
}
```

**Error Response:**
```json
{
  "status": "error",
  "command": "list_blobs",
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "Invalid limit value",
    "details": "Limit must be between 1 and 1000"
  },
  "timestamp": 1234567890
}
```

### 5.3 Two-Step Confirmation

**Critical Operations Requiring Confirmation:**
- `delete_blob` - Permanent data loss
- `set_config` - System behavior changes
- `add_admin` - Security implications
- `revoke_admin` - Access control changes
- `restore_database` - Data integrity risk

**Confirmation Flow:**

**Step 1: Request**
```json
{
  "kind": 14,
  "tags": [
    ["command", "delete_blob"],
    ["sha256", "abc123..."]
  ]
}
```

**Step 1: Response**
```json
{
  "status": "confirmation_required",
  "command": "delete_blob",
  "pending_id": "42",
  "details": {
    "sha256": "abc123...",
    "size": 1048576,
    "type": "image/jpeg",
    "uploaded_at": 1234567890
  },
  "expires_at": 1234568190,
  "message": "This will permanently delete the blob. Send confirmation within 5 minutes."
}
```

**Step 2: Confirmation**
```json
{
  "kind": 14,
  "tags": [
    ["command", "confirm"],
    ["pending_id", "42"]
  ]
}
```

**Step 2: Response**
```json
{
  "status": "success",
  "command": "delete_blob",
  "data": {
    "sha256": "abc123...",
    "deleted": true
  },
  "timestamp": 1234567900
}
```

---

## 6. API Design

### 6.1 Endpoint Routing

**New Endpoint:**
- `POST /admin` - Unified admin command endpoint (NIP-17 gift wrap)

**Existing Endpoints (Keep):**
- `GET /api/stats` - Statistics (existing admin API)
- `GET /api/config` - Configuration (existing admin API)
- `PUT /api/config` - Update config (existing admin API)
- `GET /api/files` - File listing (existing admin API)
- `GET /api/health` - Health check (existing admin API)

**Integration Strategy:**
- New `/admin` endpoint for NIP-17 DM-based commands
- Existing `/api/*` endpoints remain for backwards compatibility
- Both systems share same database and authentication
- Gradual migration path for clients

### 6.2 Request Handling

**Handler Registration in [`src/main.c`](src/main.c:1640):**

```c
// Add to main request loop (around line 1640)
else if (strcmp(request_method, "POST") == 0 &&
           strcmp(request_uri, "/admin") == 0) {
    // Handle NIP-17 gift wrap admin commands
    handle_admin_dm_request();
}
```

**Unified Handler Pattern:**

```c
// src/management_handler.c
void handle_admin_dm_request(void) {
    // 1. Read gift wrap event from request body
    char *event_json = read_request_body();
    
    // 2. Validate and unwrap gift wrap
    admin_command_t cmd;
    int result = unwrap_admin_gift_wrap(event_json, &cmd);
    if (result != SUCCESS) {
        send_admin_error(result, "Failed to unwrap gift wrap");
        return;
    }
    
    // 3. Check admin authorization
    if (!is_admin_authorized(cmd.admin_pubkey)) {
        send_admin_error(ERROR_UNAUTHORIZED, "Not authorized");
        return;
    }
    
    // 4. Check for replay
    if (is_gift_wrap_replayed(cmd.event_id)) {
        send_admin_error(ERROR_REPLAY, "Gift wrap already processed");
        return;
    }
    
    // 5. Route to command handler
    admin_response_t response;
    result = route_admin_command(&cmd, &response);
    
    // 6. Log to audit log
    log_admin_command(&cmd, result);
    
    // 7. Encrypt and send response
    send_admin_response(&response, cmd.admin_pubkey);
}
```

### 6.3 Tag-Based Routing

**Command Router:**

```c
int route_admin_command(admin_command_t *cmd, admin_response_t *response) {
    const char *command = get_tag_value(cmd->tags, "command");
    
    if (!command) {
        return ERROR_MISSING_COMMAND;
    }
    
    // Blob operations
    if (strcmp(command, "list_blobs") == 0) {
        return handle_list_blobs(cmd, response);
    } else if (strcmp(command, "get_blob_info") == 0) {
        return handle_get_blob_info(cmd, response);
    } else if (strcmp(command, "delete_blob") == 0) {
        return handle_delete_blob(cmd, response);
    }
    
    // Storage management
    else if (strcmp(command, "get_storage_stats") == 0) {
        return handle_get_storage_stats(cmd, response);
    } else if (strcmp(command, "cleanup_orphans") == 0) {
        return handle_cleanup_orphans(cmd, response);
    }
    
    // Configuration
    else if (strcmp(command, "get_config") == 0) {
        return handle_get_config(cmd, response);
    } else if (strcmp(command, "set_config") == 0) {
        return handle_set_config(cmd, response);
    }
    
    // Admin management
    else if (strcmp(command, "list_admins") == 0) {
        return handle_list_admins(cmd, response);
    } else if (strcmp(command, "add_admin") == 0) {
        return handle_add_admin(cmd, response);
    }
    
    // Confirmation
    else if (strcmp(command, "confirm") == 0) {
        return handle_confirm_pending(cmd, response);
    }
    
    else {
        return ERROR_UNKNOWN_COMMAND;
    }
}
```

---

## 7. File Structure

### 7.1 New Files

**Core Management:**
```
src/management_handler.c    - Unified command handler and routing
src/management_handler.h    - Handler interface definitions
src/dm_admin.c              - NIP-17 gift wrap processing
src/dm_admin.h              - Gift wrap interface
src/keypair_manager.c       - Server and admin key management
src/keypair_manager.h       - Key management interface
src/pending_changes.c       - Two-step confirmation system
src/pending_changes.h       - Pending changes interface
```

**Command Handlers:**
```
src/commands/blob_commands.c      - Blob operation handlers
src/commands/storage_commands.c   - Storage management handlers
src/commands/config_commands.c    - Configuration handlers
src/commands/stats_commands.c     - Statistics handlers
src/commands/admin_commands.c     - Admin management handlers
src/commands/system_commands.c    - System operation handlers
```

**Utilities:**
```
src/utils/encryption.c      - NIP-44 encryption utilities
src/utils/audit_log.c       - Audit logging utilities
src/utils/response_builder.c - Response formatting
```

### 7.2 Modified Files

**[`src/main.c`](src/main.c:1):**
- Add `/admin` endpoint routing (line ~1640)
- Initialize management system on startup
- Add cleanup on shutdown

**[`src/request_validator.c`](src/request_validator.c:1):**
- Add Kind 1059 (gift wrap) validation (line ~438)
- Add gift wrap unwrapping logic
- Add replay prevention checks

**[`src/admin_api.c`](src/admin_api.c:1):**
- Keep existing endpoints for backwards compatibility
- Add integration hooks for new management system
- Share database access with new handlers

**[`db/schema.sql`](db/schema.sql:1):**
- Add new tables (server_keys, admin_keys, pending_changes, etc.)
- Add indexes for performance
- Add default configuration values

**[`Makefile`](Makefile):**
- Add new source files to build
- Add dependencies for new modules
- Update clean targets

### 7.3 Integration Points

**With Existing Admin API:**
```c
// src/admin_api.c - Add integration function
void admin_api_notify_config_change(const char *key, const char *value) {
    // Called by management system when config changes
    // Invalidates cache, triggers reload
    nostr_request_validator_force_cache_refresh();
}
```

**With Request Validator:**
```c
// src/request_validator.c - Add gift wrap validation
int validate_gift_wrap_admin(cJSON *event) {
    // Validate Kind 1059 structure
    // Unwrap and validate seal
    // Unwrap and validate rumor
    // Check admin authorization
    // Check replay prevention
    return NOSTR_SUCCESS;
}
```

**With Database:**
```c
// All handlers use shared database connection
// Consistent error handling
// Transaction support for atomic operations
```

---

## 8. Implementation Plan

### 8.1 Phase 1: Foundation (Week 1-2)

**Goals:**
- Database schema extensions
- Keypair management
- Basic gift wrap processing

**Tasks:**
1. Create database migration script
2. Implement `keypair_manager.c`
   - Server keypair generation
   - Admin keypair storage
   - Key loading on startup
3. Implement `dm_admin.c`
   - Gift wrap unwrapping
   - Seal decryption
   - Rumor extraction
4. Add gift wrap validation to `request_validator.c`
5. Create test suite for gift wrap processing

**Deliverables:**
- Working keypair management
- Gift wrap unwrap/validation
- Database schema updated
- Unit tests passing

### 8.2 Phase 2: Command Infrastructure (Week 3-4)

**Goals:**
- Unified command handler
- Tag-based routing
- Response encryption

**Tasks:**
1. Implement `management_handler.c`
   - Request parsing
   - Command routing
   - Response building
2. Implement `pending_changes.c`
   - Two-step confirmation
   - Timeout handling
   - Execution tracking
3. Add `/admin` endpoint to `main.c`
4. Implement audit logging
5. Create command handler templates

**Deliverables:**
- Working command routing
- Two-step confirmation system
- Audit logging functional
- Integration tests passing

### 8.3 Phase 3: Core Commands (Week 5-6)

**Goals:**
- Implement essential management commands
- Integration with existing systems

**Tasks:**
1. Implement blob commands
   - `list_blobs`
   - `get_blob_info`
   - `delete_blob` (with confirmation)
2. Implement storage commands
   - `get_storage_stats`
   - `get_disk_usage`
   - `cleanup_orphans`
3. Implement config commands
   - `get_config`
   - `set_config` (with confirmation)
4. Implement admin commands
   - `list_admins`
   - `add_admin` (with confirmation)
   - `revoke_admin` (with confirmation)
5. Integration testing with existing admin API

**Deliverables:**
- Core commands functional
- Integration with existing API
- End-to-end tests passing

### 8.4 Phase 4: Advanced Features (Week 7-8)

**Goals:**
- Statistics and monitoring
- System operations
- CLI tooling

**Tasks:**
1. Implement stats commands
   - `get_stats`
   - `get_upload_stats`
   - `get_user_stats`
2. Implement system commands
   - `backup_database`
   - `restore_database`
   - `rotate_logs`
3. Create CLI tool for admin operations
4. Create web interface (optional)
5. Performance optimization
6. Security audit

**Deliverables:**
- All commands implemented
- CLI tool functional
- Performance benchmarks
- Security review complete

### 8.5 Phase 5: Documentation & Deployment (Week 9-10)

**Goals:**
- Complete documentation
- Deployment guides
- Migration tools

**Tasks:**
1. Write admin documentation
2. Create setup guides
3. Create migration scripts
4. Write troubleshooting guide
5. Create example scripts
6. Production deployment testing

**Deliverables:**
- Complete documentation
- Migration tools
- Deployment guides
- Production-ready release

---

## 9. Security Considerations

### 9.1 Threat Model

**Threats:**
1. **Unauthorized Access**: Attacker gains admin privileges
2. **Replay Attacks**: Reuse of captured gift wrap events
3. **Man-in-the-Middle**: Interception of admin commands
4. **Privilege Escalation**: Regular user gains admin access
5. **Data Exfiltration**: Unauthorized access to blob data
6. **Denial of Service**: Resource exhaustion via admin commands

**Mitigations:**
1. **NIP-17 Encryption**: End-to-end encryption prevents MITM
2. **Gift Wrap Tracking**: Prevents replay attacks
3. **Admin Key Management**: Strict authorization checks
4. **Two-Step Confirmation**: Prevents accidental critical operations
5. **Audit Logging**: Tracks all admin actions
6. **Rate Limiting**: Prevents DoS via admin commands

### 9.2 Key Security

**Server Private Key:**
- **NEVER** stored in database
- Loaded into memory on startup
- Cleared on shutdown
- Protected by OS memory protection
- Consider using secure enclave if available

**Admin Private Keys:**
- **NEVER** stored on server
- Managed by admin clients only
- Rotated regularly
- Revoked immediately if compromised

**Database Encryption:**
- Consider encrypting sensitive config values
- Use system keyring for encryption keys
- Implement key rotation mechanism

### 9.3 Access Control

**Permission Levels:**
```json
{
  "full": ["*"],
  "read": ["list_*", "get_*"],
  "write": ["list_*", "get_*", "set_*", "add_*"],
  "admin": ["list_*", "get_*", "set_*", "add_*", "delete_*", "revoke_*"]
}
```

**Permission Checks:**
```c
int check_admin_permission(const char *admin_pubkey, const char *command) {
    // Load admin permissions from database
    cJSON *permissions = get_admin_permissions(admin_pubkey);
    
    // Check if command is allowed
    if (has_permission(permissions, command)) {
        return 1;
    }
    
    // Check wildcard permissions
    if (has_permission(permissions, "*")) {
        return 1;
    }
    
    return 0;
}
```

### 9.4 Audit Trail

**What to Log:**
- All admin commands (success and failure)
- Admin key additions/revocations
- Configuration changes
- Critical operations (delete, restore, etc.)
- Authentication failures
- Suspicious activity

**Log Format:**
```json
{
  "timestamp": 1234567890,
  "admin_pubkey": "abc123...",
  "command": "delete_blob",
  "parameters": {"sha256": "def456..."},
  "success": true,
  "client_ip": "192.168.1.100",
  "event_id": "ghi789..."
}
```

**Log Retention:**
- Keep audit logs for 30 days minimum
- Archive older logs to separate storage
- Implement log rotation
- Protect logs from tampering

---

## 10. Migration Strategy

### 10.1 Backwards Compatibility

**Existing Admin API:**
- Keep all existing `/api/*` endpoints
- No breaking changes to current API
- Gradual deprecation over 6 months
- Clear migration documentation

**Database:**
- Additive schema changes only
- No modifications to existing tables
- Migration script handles upgrades
- Rollback capability

**Configuration:**
- Existing config keys remain valid
- New config keys added with defaults
- No changes to config file format

### 10.2 Migration Steps

**Step 1: Database Migration**
```bash
# Backup existing database
cp db/ginxsom.db db/ginxsom.db.backup

# Run migration script
sqlite3 db/ginxsom.db < db/migrations/002_add_management_system.sql

# Verify migration
sqlite3 db/ginxsom.db "SELECT name FROM sqlite_master WHERE type='table';"
```

**Step 2: Generate Server Keypair**
```bash
# Generate server keypair
./build/ginxsom-fcgi --generate-server-key

# Verify keypair
./build/ginxsom-fcgi --show-server-pubkey
```

**Step 3: Add Initial Admin**
```bash
# Generate admin keypair
ADMIN_PRIVKEY=$(nak key generate)
ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)

# Add to database
sqlite3 db/ginxsom.db << EOF
INSERT INTO admin_keys (public_key, name, permissions, created_by) 
VALUES ('$ADMIN_PUBKEY', 'Primary Admin', '["full"]', 'system');
EOF

# Save admin private key securely
echo "$ADMIN_PRIVKEY" > ~/.config/ginxsom/admin.key
chmod 600 ~/.config/ginxsom/admin.key
```

**Step 4: Test New System**
```bash
# Test gift wrap command
nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \
    --tag command list_admins \
    | curl -X POST http://localhost:9001/admin -d @-

# Verify response
```

**Step 5: Update Clients**
- Update admin scripts to use new `/admin` endpoint
- Migrate from `/api/*` to NIP-17 commands
- Test thoroughly before production

### 10.3 Rollback Plan

**If Issues Occur:**
1. Stop ginxsom service
2. Restore database backup
3. Revert to previous version
4. Investigate issues
5. Fix and retry migration

**Database Rollback:**
```bash
# Stop service
systemctl stop ginxsom

# Restore backup
cp db/ginxsom.db.backup db/ginxsom.db

# Restart service
systemctl start ginxsom
```

---

## Appendix A: Command Reference

### Blob Commands

**list_blobs**
```json
{
  "command": "list_blobs",
  "limit": "50",
  "offset": "0",
  "filter_type": "image/*",
  "since": "1234567890"
}
```

**get_blob_info**
```json
{
  "command": "get_blob_info",
  "sha256": "abc123..."
}
```

**delete_blob** (requires confirmation)
```json
{
  "command": "delete_blob",
  "sha256": "abc123..."
}
```

### Storage Commands

**get_storage_stats**
```json
{
  "command": "get_storage_stats"
}
```

**cleanup_orphans**
```json
{
  "command": "cleanup_orphans",
  "dry_run": "true"
}
```

### Configuration Commands

**get_config**
```json
{
  "command": "get_config",
  "key": "max_file_size"
}
```

**set_config** (requires confirmation)
```json
{
  "command": "set_config",
  "key": "max_file_size",
  "value": "209715200"
}
```

### Admin Commands

**list_admins**
```json
{
  "command": "list_admins"
}
```

**add_admin** (requires confirmation)
```json
{
  "command": "add_admin",
  "pubkey": "def456...",
  "name": "Secondary Admin",
  "permissions": "[\"read\",\"write\"]"
}
```

**revoke_admin** (requires confirmation)
```json
{
  "command": "revoke_admin",
  "pubkey": "def456..."
}
```

---

## Appendix B: Example Scripts

### Setup Script

```bash
#!/bin/bash
# setup_admin.sh - Initial admin setup

set -e

echo "Ginxsom Admin Setup"
echo "==================="

# Generate admin keypair
echo "Generating admin keypair..."
ADMIN_PRIVKEY=$(nak key generate)
ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)

echo "Admin Public Key: $ADMIN_PUBKEY"

# Save private key
mkdir -p ~/.config/ginxsom
echo "$ADMIN_PRIVKEY" > ~/.config/ginxsom/admin.key
chmod 600 ~/.config/ginxsom/admin.key

echo "Private key saved to ~/.config/ginxsom/admin.key"

# Add to database
echo "Adding admin to database..."
sqlite3 db/ginxsom.db << EOF
INSERT INTO admin_keys (public_key, name, permissions, created_by) 
VALUES ('$ADMIN_PUBKEY', 'Primary Admin', '["full"]', 'system');
EOF

echo "Admin setup complete!"
echo "Test with: ./admin_command.sh list_admins"
```

### Admin Command Script

```bash
#!/bin/bash
# admin_command.sh - Send admin command

ADMIN_PRIVKEY=$(cat ~/.config/ginxsom/admin.key)
COMMAND=$1
shift

# Build tags
TAGS=""
for arg in "$@"; do
    KEY=$(echo "$arg" | cut -d= -f1)
    VALUE=$(echo "$arg" | cut -d= -f2-)
    TAGS="$TAGS --tag $KEY \"$VALUE\""
done

# Send command
eval nak event -k 14 --envelope --sec "$ADMIN_PRIVKEY" \
    --tag command "$COMMAND" \
    $TAGS \
    | curl -s -X POST http://localhost:9001/admin -d @- \
    | jq .
```

### Usage Examples

```bash
# List admins
./admin_command.sh list_admins

# Get storage stats
./admin_command.sh get_storage_stats

# List blobs
./admin_command.sh list_blobs limit=10 offset=0

# Delete blob (with confirmation)
./admin_command.sh delete_blob sha256=abc123...
# Then confirm
./admin_command.sh confirm pending_id=42
```

---

## Conclusion

This design provides a secure, scalable management system for ginxsom that:

1. **Leverages Proven Patterns**: Adapts c-relay's successful architecture
2. **Maintains Security**: NIP-17 encryption and two-step confirmation
3. **Ensures Compatibility**: Integrates with existing admin API
4. **Enables Growth**: Extensible command system for future features
5. **Provides Auditability**: Complete audit trail of admin actions

The phased implementation plan allows for incremental development and testing, while the migration strategy ensures smooth transition from the current system.

**Next Steps:**
1. Review and approve design
2. Begin Phase 1 implementation
3. Set up development environment
4. Create test infrastructure
5. Start coding!