# User-Initiated Issue Reporting with Screenshots — Implementation Roadmap

> **Location:** `docs/devops/USER_ISSUE_REPORTING_ROADMAP.md`  
> **Status:** Draft  
> **Created:** 2026-03-02

---

## Overview

Enable users to self-report issues with automatic/manual screenshots and comments. This extends the existing `feedback` module to support rich media attachments, leveraging the `blob` module for Azure Blob storage.

### Use Cases

1. **Bug Report with Screenshot** — User encounters error → taps "Report Issue" → screenshot captured → typed description submitted
2. **Feature Request with Mockup** — User uploads annotated screenshot showing desired UI change
3. **Crash Auto-Report** — App crashes → on restart, user prompted to "Send crash report with screenshot"
4. **Support Chat Attachment** — Screenshots attached to existing feedback for back-and-forth with support team

---

## Current State

### Existing Feedback Module

| Component | Status |
|-----------|--------|
| `POST /api/feedback` | ✅ Creates feedback (type, title, body, screen) |
| `GET /api/feedback` | ✅ Admin list/query |
| `PUT /api/feedback/:id` | ✅ Admin triage (status, adminNotes) |
| Screenshot support | ❌ Only text `screen` field |
| Multiple attachments | ❌ Not supported |
| Threaded comments | ❌ Not supported |

### Existing Blob Module (Reusable)

| Component | Status |
|-----------|--------|
| `POST /api/blob/sas` | ✅ Generate SAS URL for direct upload |
| Azure Blob integration | ✅ Storage + lifecycle |
| Container management | ✅ Per-product isolation |

---

## Target Architecture

```
User Flow:
1. User taps "Report Issue" in app
2. Client captures screenshot (optional annotation)
3. Client requests SAS URL: POST /api/feedback/sas
4. Client uploads image directly to Azure Blob
5. Client submits feedback: POST /api/feedback (with screenshotBlobPath)
6. Admin views feedback in dashboard with image preview
```

---

## Data Model Changes

### Option A: Inline Screenshot (Simple)

```typescript
// feedback/types.ts — Add to existing FeedbackDoc
interface FeedbackDoc {
  // ... existing fields ...
  
  // Screenshot attachment (single)
  screenshotBlobPath?: string;        // "feedback/{productId}/{feedbackId}/{screenshotId}.png"
  screenshotUrl?: string;             // Time-limited SAS URL for viewing
  screenshotUrlExpiresAt?: string;   // When SAS URL expires
  
  // Device context for debugging
  deviceContext?: {
    osVersion: string;
    appVersion: string;
    deviceModel: string;
    screenResolution: string;
    locale: string;
  };
}

// Add to CreateFeedbackSchema
screenshotBlobPath: z.string().optional(),
deviceContext: z.object({
  osVersion: z.string(),
  appVersion: z.string(),
  deviceModel: z.string(),
  screenResolution: z.string(),
  locale: z.string(),
}).optional(),
```

### Option B: Separate FeedbackAttachments Container (Extensible)

```typescript
// feedback/types.ts — New attachment model
interface FeedbackAttachmentDoc {
  id: string;                         // att_<uuid>
  feedbackId: string;                 // Parent feedback (partition key)
  productId: string;
  
  // Blob storage
  blobPath: string;                   // "feedback/{productId}/{feedbackId}/{id}.png"
  blobUrl: string;                    // SAS URL (refreshed on fetch)
  containerName: string;              // e.g., "user-feedback"
  
  // Metadata
  fileName: string;
  contentType: 'image/png' | 'image/jpeg' | 'image/webp';
  sizeBytes: number;
  width: number;
  height: number;
  
  // Capture context
  capturedAt: string;
  trigger: 'manual' | 'auto_crash' | 'auto_error';
  screenName?: string;
  
  createdAt: string;
}

interface FeedbackDoc {
  // ... existing fields ...
  
  // Reference to attachments
  attachmentCount: number;            // Denormalized counter
  hasScreenshot: boolean;            // Quick check for UI
}

// API changes
POST /api/feedback/:id/attachments      // Add attachment to existing feedback
GET  /api/feedback/:id/attachments      // List attachments
DELETE /api/feedback/:id/attachments/:attId  // Remove attachment (admin)
```

**Recommendation:** Start with **Option A** (single screenshot), migrate to **Option B** if multi-attachment demand arises.

---

## API Specification

### New Endpoints

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| `POST` | `/api/feedback/sas` | User | Get SAS URL for screenshot upload |
| `POST` | `/api/feedback` | User | Submit feedback (with optional screenshotBlobPath) |
| `GET` | `/api/feedback/:id/screenshot` | Admin | Get fresh SAS URL for viewing screenshot |
| `DELETE` | `/api/feedback/:id/screenshot` | Admin | Delete screenshot (GDPR/privacy) |

### SAS Generation Endpoint

```typescript
// POST /api/feedback/sas
// Request
{
  "contentType": "image/png",
  "sizeHint": 1024000  // Optional: 1MB hint for validation
}

// Response (201)
{
  "blobPath": "feedback/lysnrai/feedback_abc123/screenshot_xyz.png",
  "uploadUrl": "https://bytelyst.blob.core.windows.net/...?sv=...",
  "expiresIn": 300,  // 5 minutes
  "maxSizeBytes": 5242880  // 5MB limit
}
```

### Submit Feedback with Screenshot

```typescript
// POST /api/feedback
// Request
{
  "type": "bug",
  "title": "App crashes when tapping record",
  "body": "Steps: 1. Open app 2. Tap red button 3. Crash",
  "screen": "RecordingScreen",
  "screenshotBlobPath": "feedback/lysnrai/feedback_abc123/screenshot_xyz.png",
  "deviceContext": {
    "osVersion": "iOS 17.4",
    "appVersion": "2.3.1",
    "deviceModel": "iPhone15,2",
    "screenResolution": "393x852",
    "locale": "en-US"
  }
}
```

---

## Implementation Phases

### Phase 1: Server Foundation (2-3 days)

#### 1.1 Data Model Extension
- [ ] Add `screenshotBlobPath` to `FeedbackDoc` interface
- [ ] Add `deviceContext` to `FeedbackDoc` interface  
- [ ] Update `CreateFeedbackSchema` with new fields
- [ ] Add `feedback_screenshots` container to `cosmos-init.ts` (if Option B)

#### 1.2 Repository Layer
- [ ] Extend `createFeedback()` to handle screenshot metadata
- [ ] Add `generateScreenshotSas()` function (wrapper around blob module)
- [ ] Add `getFeedbackWithScreenshot()` with fresh SAS URL generation
- [ ] Add `deleteFeedbackScreenshot()` for GDPR compliance

#### 1.3 API Routes
- [ ] `POST /api/feedback/sas` — Generate upload URL
  - Rate limit: 5 requests per 10 minutes per user
  - Validate content type (image/* only)
  - Return blob path + SAS URL
- [ ] Update `POST /api/feedback` — Accept screenshot metadata
- [ ] `GET /api/feedback/:id/screenshot` — Get fresh view URL
- [ ] `DELETE /api/feedback/:id/screenshot` — Admin delete

#### 1.4 Integration
- [ ] Wire new routes into `server.ts`
- [ ] Add blob container `user-feedback` to blob module config
- [ ] Set lifecycle policy: 90-day TTL for user screenshots

#### 1.5 Testing
- [ ] Unit tests for SAS generation
- [ ] Unit tests for feedback with screenshot submission
- [ ] Integration test: full flow (SAS → upload → submit → view)
- [ ] GDPR deletion test

### Phase 2: Client SDK Updates (3-4 days)

#### 2.1 TypeScript SDK (`@bytelyst/feedback-client`)
- [ ] `FeedbackClient.submitWithScreenshot(params)`
  - Internal flow: get SAS → upload blob → submit feedback
  - Progress callbacks for upload
- [ ] `FeedbackClient.captureAndSubmit()` — Auto-capture current screen

#### 2.2 Swift SDK (iOS)
- [ ] `FeedbackManager.submit(title:body:screenshot:)`
- [ ] `FeedbackManager.captureScreenshot()` — UIImage → blob upload
- [ ] Annotation overlay (optional drawing on screenshot)

#### 2.3 Kotlin SDK (Android)
- [ ] `FeedbackManager.submitWithScreenshot()`
- [ ] MediaProjection integration for screenshot capture
- [ ] Composable for in-app feedback sheet with screenshot preview

### Phase 3: Admin Dashboard UI (2-3 days)

#### 3.1 Feedback List Enhancements
- [ ] Thumbnail preview of screenshot in list view
- [ ] Filter: "Has screenshot" / "No screenshot"

#### 3.2 Feedback Detail View
- [ ] Full-size screenshot display (lightbox)
- [ ] Device context panel (OS version, app version, screen resolution)
- [ ] "Download screenshot" button
- [ ] "Delete screenshot" (GDPR compliance)

#### 3.3 Client Library
- [ ] `lib/feedback-client.ts` — Add `getScreenshotUrl(feedbackId)`

---

## Privacy & Security Considerations

### PII Handling
- [ ] Screenshots may contain sensitive user data
- [ ] Blur regions API (client-side before upload)
- [ ] Auto-redact: Detect and blur common PII areas (email fields, phone numbers)
- [ ] User consent: "This screenshot may include your data. Continue?"

### Retention
- [ ] Screenshot TTL: 90 days (match feedback lifecycle)
- [ ] On feedback deletion → cascade delete screenshot blob
- [ ] User-initiated deletion: "Delete my feedback and screenshot"

### Access Control
- [ ] Users can only view their own screenshots
- [ ] Admins can view all screenshots for their product
- [ ] Fresh SAS URLs generated per view (time-limited, 15 minutes)

---

## Open Questions

| # | Question | Impact | Suggested Answer |
|---|----------|--------|------------------|
| 1 | Max screenshot size? | Storage cost | 5MB limit, WebP compression recommended |
| 2 | Multiple screenshots per feedback? | Complexity | Start with 1, add array support later |
| 3 | Screenshot annotation/drawing? | Client complexity | Phase 2.2 for iOS, others skip |
| 4 | Auto-capture on crash? | Privacy risk | Opt-in only, show preview before submit |
| 5 | Video screen recording? | Storage cost | Future Phase 4, not now |
| 6 | Anonymous feedback allowed? | Auth complexity | No — require auth for accountability |

---

## Success Metrics

- **Adoption:** 30% of bug reports include screenshot within 3 months
- **Resolution time:** -20% time-to-resolution for reports with screenshots
- **Storage:** <100GB/month for screenshots (at 1000 reports/day, 100KB avg)

---

## Appendix: File Changes

### New Files
```
services/platform-service/src/modules/feedback/
  ├── sas.ts                    # SAS generation helpers
  └── attachment.types.ts       # (if Option B)
```

### Modified Files
```
services/platform-service/src/modules/feedback/
  ├── types.ts                  # Add screenshot fields
  ├── repository.ts             # Add SAS functions
  └── routes.ts                 # Add SAS endpoint

services/platform-service/src/lib/cosmos-init.ts
  └── Add feedback_attachments container (if Option B)

services/platform-service/src/server.ts
  └── Register feedback SAS routes
```

---

**Last Updated:** 2026-03-02
