# Bugsink to Gitea Issue Synchronization

This document describes the automated workflow for syncing Bugsink error tracking issues to Gitea tickets.

## Overview

The sync system automatically creates Gitea issues from unresolved Bugsink errors, ensuring all application errors are tracked and assignable.

**Key Points:**

- Runs **only on test/staging server** (not production)
- Syncs **all 6 Bugsink projects** (including production errors)
- Creates Gitea issues with full error context
- Marks synced issues as resolved in Bugsink
- Uses Redis db 15 for sync state tracking

## Architecture

```
TEST/STAGING SERVER
┌─────────────────────────────────────────────────┐
│                                                  │
│  BullMQ Queue ──▶ Sync Worker ──▶ Redis DB 15   │
│  (bugsink-sync)   (15min)        (sync state)   │
│                      │                           │
└──────────────────────┼───────────────────────────┘
                       │
         ┌─────────────┴─────────────┐
         ▼                           ▼
    ┌─────────┐               ┌─────────┐
    │ Bugsink │               │  Gitea  │
    │ (read)  │               │ (write) │
    └─────────┘               └─────────┘
```

## Bugsink Projects

| Project Slug                      | Type     | Environment | Label Mapping                       |
| --------------------------------- | -------- | ----------- | ----------------------------------- |
| flyer-crawler-backend             | Backend  | Production  | bug:backend + env:production        |
| flyer-crawler-backend-test        | Backend  | Test        | bug:backend + env:test              |
| flyer-crawler-frontend            | Frontend | Production  | bug:frontend + env:production       |
| flyer-crawler-frontend-test       | Frontend | Test        | bug:frontend + env:test             |
| flyer-crawler-infrastructure      | Infra    | Production  | bug:infrastructure + env:production |
| flyer-crawler-test-infrastructure | Infra    | Test        | bug:infrastructure + env:test       |

## Gitea Labels

| Label              | Color              | ID  |
| ------------------ | ------------------ | --- |
| bug:frontend       | #e11d48 (Red)      | 8   |
| bug:backend        | #ea580c (Orange)   | 9   |
| bug:infrastructure | #7c3aed (Purple)   | 10  |
| env:production     | #dc2626 (Dark Red) | 11  |
| env:test           | #2563eb (Blue)     | 12  |
| env:development    | #6b7280 (Gray)     | 13  |
| source:bugsink     | #10b981 (Green)    | 14  |

## Environment Variables

Add these to **test environment only** (`deploy-to-test.yml`):

```bash
# Bugsink API
BUGSINK_URL=https://bugsink.projectium.com
BUGSINK_API_TOKEN=<from Bugsink Settings > API Keys>

# Gitea API
GITEA_URL=https://gitea.projectium.com
GITEA_API_TOKEN=<personal access token with repo scope>
GITEA_OWNER=torbo
GITEA_REPO=flyer-crawler.projectium.com

# Sync Control
BUGSINK_SYNC_ENABLED=true   # Only set true in test env
BUGSINK_SYNC_INTERVAL=15    # Minutes between sync runs
```

## Gitea Secrets to Add

Add these secrets in Gitea repository settings (Settings > Secrets):

| Secret Name            | Value                  | Environment |
| ---------------------- | ---------------------- | ----------- |
| `BUGSINK_API_TOKEN`    | API token from Bugsink | Test only   |
| `GITEA_SYNC_TOKEN`     | Personal access token  | Test only   |
| `BUGSINK_SYNC_ENABLED` | `true`                 | Test only   |

## Redis Configuration

| Database | Purpose                  |
| -------- | ------------------------ |
| 0        | BullMQ production queues |
| 1        | BullMQ test queues       |
| 15       | Bugsink sync state       |

**Key Pattern:**

```
bugsink:synced:{issue_uuid}
```

**Value (JSON):**

```json
{
  "gitea_issue_number": 42,
  "synced_at": "2026-01-17T10:30:00Z",
  "project": "flyer-crawler-frontend-test",
  "title": "[TypeError] t.map is not a function"
}
```

## Sync Workflow

1. **Trigger**: Every 15 minutes (or manual via admin API)
2. **Fetch**: List unresolved issues from all 6 Bugsink projects
3. **Check**: Skip issues already in Redis sync state
4. **Create**: Create Gitea issue with labels and full context
5. **Record**: Store sync mapping in Redis db 15
6. **Resolve**: Mark issue as resolved in Bugsink

## Issue Template

Created Gitea issues follow this format:

```markdown
## Error Details

| Field        | Value                   |
| ------------ | ----------------------- |
| **Type**     | TypeError               |
| **Message**  | t.map is not a function |
| **Platform** | javascript              |
| **Level**    | error                   |

## Occurrence Statistics

- **First Seen**: 2026-01-13 18:24:22 UTC
- **Last Seen**: 2026-01-16 05:03:02 UTC
- **Total Occurrences**: 4

## Request Context

- **URL**: GET https://flyer-crawler-test.projectium.com/

## Stacktrace

<details>
<summary>Click to expand</summary>

[Full stacktrace]

</details>

---

**Bugsink Issue**: https://bugsink.projectium.com/issues/{id}
**Project**: flyer-crawler-frontend-test
```

## Admin Endpoints

### Manual Sync Trigger

```bash
POST /api/admin/bugsink/sync
Authorization: Bearer <admin_jwt>

# Response
{
  "success": true,
  "data": {
    "synced": 3,
    "skipped": 12,
    "failed": 0,
    "duration_ms": 2340
  }
}
```

### Sync Status

```bash
GET /api/admin/bugsink/sync/status
Authorization: Bearer <admin_jwt>

# Response
{
  "success": true,
  "data": {
    "enabled": true,
    "last_run": "2026-01-17T10:30:00Z",
    "next_run": "2026-01-17T10:45:00Z",
    "total_synced": 47
  }
}
```

## Files to Create

| File                                   | Purpose               |
| -------------------------------------- | --------------------- |
| `src/services/bugsinkSync.server.ts`   | Core sync logic       |
| `src/services/bugsinkClient.server.ts` | Bugsink HTTP client   |
| `src/services/giteaClient.server.ts`   | Gitea HTTP client     |
| `src/types/bugsink.ts`                 | TypeScript interfaces |
| `src/routes/admin/bugsink-sync.ts`     | Admin endpoints       |

## Files to Modify

| File                                  | Changes                   |
| ------------------------------------- | ------------------------- |
| `src/services/queues.server.ts`       | Add `bugsinkSyncQueue`    |
| `src/services/workers.server.ts`      | Add sync worker           |
| `src/config/env.ts`                   | Add bugsink config schema |
| `.env.example`                        | Document new variables    |
| `.gitea/workflows/deploy-to-test.yml` | Pass secrets              |

## Implementation Phases

### Phase 1: Core Infrastructure

- [ ] Add env vars to `env.ts` schema
- [ ] Create BugsinkClient service
- [ ] Create GiteaClient service
- [ ] Add Redis db 15 connection

### Phase 2: Sync Logic

- [ ] Create BugsinkSyncService
- [ ] Add bugsink-sync queue
- [ ] Add sync worker
- [ ] Create TypeScript types

### Phase 3: Integration

- [ ] Add admin endpoints
- [ ] Update deploy-to-test.yml
- [ ] Add Gitea secrets
- [ ] End-to-end testing

## Troubleshooting

### Sync not running

1. Check `BUGSINK_SYNC_ENABLED` is `true`
2. Verify worker is running: `GET /api/admin/workers/status`
3. Check Bull Board: `/api/admin/jobs`

### Duplicate issues created

1. Check Redis db 15 connectivity
2. Verify sync state keys exist: `redis-cli -n 15 KEYS "bugsink:*"`

### Issues not resolving in Bugsink

1. Verify `BUGSINK_API_TOKEN` has write permissions
2. Check worker logs for API errors

### Missing stacktrace in Gitea issue

1. Source maps may not be uploaded
2. Bugsink API may have returned partial data
3. Check worker logs for fetch errors

## Related Documentation

- [ADR-054: Bugsink-Gitea Sync](./adr/0054-bugsink-gitea-issue-sync.md)
- [ADR-006: Background Job Processing](./adr/0006-background-job-processing-and-task-queues.md)
- [ADR-015: Error Tracking](./adr/0015-application-performance-monitoring-and-error-tracking.md)
