{
  "meta": {
    "generated_at": "2025-01-27T00:00:00Z",
    "scope": "backend veza-backend-api <-> frontend apps/web integration",
    "repo_commit": "e4212ee59420e1c2d53e84af5cba1d9351d123d5",
    "auditor": "Cursor AI",
    "severity_model": {
      "P0": "Critical - breaks core functionality or security, must fix immediately",
      "P1": "High - frequent functional breakage or major UX regression",
      "P2": "Medium - correctness/consistency issues that will create bugs soon",
      "P3": "Low - maintainability, dead code, tech debt"
    }
  },
  "summary": {
    "health_score_0_to_10": 4,
    "issue_counts": {
      "P0": 5,
      "P1": 10,
      "P2": 8,
      "P3": 7
    },
    "top5_issue_ids": [
      "INT-000001",
      "INT-000002",
      "INT-000003",
      "INT-000004",
      "INT-000005"
    ]
  },
  "issues": [
    {
      "id": "INT-000001",
      "severity": "P0",
      "priority_rank": 1,
      "title": "CORS Configuration Will Break Production - Empty Origins Reject All Requests",
      "component": {
        "frontend": "",
        "backend": "veza-backend-api/internal/api/router.go, internal/config/config.go, internal/middleware/cors.go",
        "infra": "deployment configs"
      },
      "category": ["cors", "env", "production"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "medium",
        "notes": "All API requests will fail in production if CORS_ALLOWED_ORIGINS is not set"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/api/router.go",
            "lines": "L119-L128",
            "excerpt": "if r.config != nil {\n    router.Use(middleware.CORS(r.config.CORSOrigins))\n    if len(r.config.CORSOrigins) == 0 {\n        r.logger.Warn(\"CORS origins not configured - strict mode enabled: ALL CORS requests will be rejected.\")\n    }\n}"
          },
          {
            "path": "veza-backend-api/internal/config/config.go",
            "lines": "L638-L664",
            "excerpt": "case EnvProduction:\n    return []string{}  // Empty list = reject all"
          },
          {
            "path": "veza-backend-api/internal/middleware/cors.go",
            "lines": "L34-L37",
            "excerpt": "if len(allowed) == 0 {\n    return false  // Reject all origins"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Set APP_ENV=production",
          "Leave CORS_ALLOWED_ORIGINS unset",
          "Start backend server",
          "Make CORS request from frontend",
          "Observe: Request rejected with CORS error"
        ],
        "expected": "CORS requests should work with configured origins",
        "actual": "All CORS requests rejected because origins list is empty"
      },
      "root_cause": "Production environment defaults to strict mode (empty origins list) but frontend expects CORS to work. No validation ensures CORS_ALLOWED_ORIGINS is set in production.",
      "fix_plan": {
        "minimal_steps": [
          "Add startup validation: fail fast if APP_ENV=production and CORS_ALLOWED_ORIGINS empty",
          "Document CORS_ALLOWED_ORIGINS as REQUIRED in production deployment guide",
          "Update docker-compose.production.yml with example CORS_ALLOWED_ORIGINS",
          "Add integration test with production-like CORS config"
        ],
        "tests_to_add": [
          "E2E test: Verify CORS works with configured origins",
          "Unit test: Verify startup fails if prod + empty CORS"
        ],
        "regression_risks": ["None - this is a new validation"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000002",
      "severity": "P0",
      "priority_rank": 2,
      "title": "Multiple Auth Storage Mechanisms Cause Token Sync Failures",
      "component": {
        "frontend": "apps/web/src/services/tokenStorage.ts, apps/web/src/services/api/client.ts, apps/web/src/stores/auth.ts, apps/web/src/utils/token-manager.ts",
        "backend": "",
        "infra": ""
      },
      "category": ["auth", "state-management"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "low",
        "notes": "Tokens stored in localStorage, Zustand persist, and TokenStorage can desync, causing auth failures"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/tokenStorage.ts",
            "lines": "L35-L36",
            "excerpt": "localStorage.setItem(ACCESS_TOKEN_KEY, accessToken);\nlocalStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);"
          },
          {
            "path": "apps/web/src/services/api/client.ts",
            "lines": "L48-L64",
            "excerpt": "// Fallback: Si pas de token dans TokenStorage, chercher dans auth-storage Zustand\nif (!token && typeof window !== 'undefined') {\n    const authStorage = localStorage.getItem('auth-storage');\n    // Parse Zustand storage..."
          },
          {
            "path": "apps/web/src/utils/token-manager.ts",
            "lines": "L25",
            "excerpt": "localStorage.setItem(this.ACCESS_TOKEN_KEY, accessToken);"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Login via Zustand store",
          "Token stored in auth-storage (Zustand)",
          "API call uses TokenStorage.getAccessToken()",
          "TokenStorage returns null",
          "Fallback to Zustand storage works but fragile"
        ],
        "expected": "Single source of truth for token storage",
        "actual": "Tokens stored in 3+ different places, can desync"
      },
      "root_cause": "No single source of truth for token storage. Multiple classes (TokenStorage, token-manager, Zustand) all manage tokens independently.",
      "fix_plan": {
        "minimal_steps": [
          "Standardize on TokenStorage class as single source",
          "Remove token storage from Zustand (keep only user and isAuthenticated flags)",
          "Remove token-manager.ts or migrate all usage to TokenStorage",
          "Update apiClient interceptor to only use TokenStorage",
          "Add tests for token persistence across page reloads"
        ],
        "tests_to_add": [
          "Test: Token persists after page reload",
          "Test: Token sync across multiple tabs",
          "Test: Token cleared on logout"
        ],
        "regression_risks": ["Existing code using Zustand token storage may break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000003",
      "severity": "P0",
      "priority_rank": 3,
      "title": "Type Mismatch: User.id (string vs number) Causes Runtime Errors",
      "component": {
        "frontend": "apps/web/src/types/api.ts, apps/web/src/features/auth/types/index.ts, apps/web/src/services/api/auth.ts",
        "backend": "veza-backend-api/internal/dto/user_response.go",
        "infra": ""
      },
      "category": ["schema-drift", "type-safety"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "none",
        "notes": "TypeScript type errors and runtime coercion bugs when accessing user.id"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/types/api.ts",
            "lines": "L3",
            "excerpt": "id: string;  // ✅ Correct"
          },
          {
            "path": "apps/web/src/features/auth/types/index.ts",
            "lines": "L8",
            "excerpt": "id: number;  // ❌ Wrong type"
          },
          {
            "path": "veza-backend-api/internal/dto/user_response.go",
            "lines": "L30",
            "excerpt": "ID: uuid.UUID  // Serializes as string"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Import User type from features/auth/types",
          "Access user.id in TypeScript",
          "TypeScript expects number but receives string",
          "Runtime: String operations on number or vice versa"
        ],
        "expected": "User.id is string (UUID) everywhere",
        "actual": "Mixed types: string in some places, number in others"
      },
      "root_cause": "Inconsistent type definitions across frontend modules. Backend uses UUID (string) but some frontend types use number.",
      "fix_plan": {
        "minimal_steps": [
          "Audit all User type definitions in frontend",
          "Update apps/web/src/features/auth/types/index.ts to use id: string",
          "Update all Zod schemas to validate UUID format",
          "Run TypeScript strict mode checks",
          "Fix all type errors"
        ],
        "tests_to_add": [
          "TypeScript compilation test",
          "Runtime validation: Verify user.id is string"
        ],
        "regression_risks": ["Code expecting number may break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000004",
      "severity": "P0",
      "priority_rank": 4,
      "title": "Deprecated ApiService Expects Wrong Response Format",
      "component": {
        "frontend": "apps/web/src/services/api.ts",
        "backend": "veza-backend-api/internal/handlers/auth.go",
        "infra": ""
      },
      "category": ["api-contract", "error-handling"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "none",
        "notes": "Code using deprecated ApiService will break when backend response format changes"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/api.ts",
            "lines": "L238-L239",
            "excerpt": "const { user, token } = response.data.data;  // Expects flat structure"
          },
          {
            "path": "veza-backend-api/internal/handlers/auth.go",
            "lines": "L96-L106",
            "excerpt": "RespondSuccess(c, http.StatusOK, dto.LoginResponse{\n    User: {...},\n    Token: {...}\n})  // Returns { success: true, data: { user: {...}, token: {...} } }"
          },
          {
            "path": "apps/web/src/services/api.ts",
            "lines": "L74-L80",
            "excerpt": "@deprecated Cette classe est dépréciée. Utilisez apiClient"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Use ApiService.login()",
          "Backend returns { success: true, data: { user: {...}, token: {...} } }",
          "ApiService expects { user, token } directly in data",
          "Code works but fragile - depends on exact structure"
        ],
        "expected": "All code uses apiClient with consistent response unwrapping",
        "actual": "Deprecated ApiService still used, expects different format"
      },
      "root_cause": "Legacy ApiService class expects flat structure in data, but backend wraps in nested structure. Class marked deprecated but not fully migrated.",
      "fix_plan": {
        "minimal_steps": [
          "Complete migration from ApiService to apiClient (see MIGRATION_GUIDE.md)",
          "Search for all ApiService usage",
          "Replace with apiClient calls",
          "Remove ApiService class entirely",
          "Update all imports"
        ],
        "tests_to_add": [
          "Verify all API calls use apiClient",
          "No references to ApiService in codebase"
        ],
        "regression_risks": ["Code still using ApiService will break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000005",
      "severity": "P0",
      "priority_rank": 5,
      "title": "Missing CSRF Protection for State-Changing Operations",
      "component": {
        "frontend": "apps/web/src/services/csrf.ts, apps/web/src/services/secure-auth.ts",
        "backend": "veza-backend-api (no CSRF middleware found)",
        "infra": ""
      },
      "category": ["security", "csrf"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "high",
        "notes": "Vulnerable to CSRF attacks on POST/PUT/DELETE requests"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/csrf.ts",
            "lines": "L14-L17",
            "excerpt": "public async refreshCsrfToken(): Promise<void> {\n    // Placeholder: fetch from backend if needed\n    // this.csrfToken = ...\n}"
          },
          {
            "path": "apps/web/src/services/secure-auth.ts",
            "lines": "L119",
            "excerpt": "await csrfService.refreshCsrfToken();  // Does nothing"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Create malicious website",
          "Include form that POSTs to https://veza.com/api/v1/tracks (user logged in)",
          "User visits malicious site",
          "Form submits automatically",
          "Request succeeds (no CSRF protection)"
        ],
        "expected": "CSRF token required for POST/PUT/DELETE",
        "actual": "No CSRF protection implemented"
      },
      "root_cause": "CSRF protection not implemented. Frontend has placeholder service, backend has no CSRF middleware. Chat server has CSRF but REST API does not.",
      "fix_plan": {
        "minimal_steps": [
          "Implement CSRF token generation endpoint: GET /api/v1/csrf-token",
          "Backend: Add CSRF middleware for POST/PUT/DELETE (exclude GET, OPTIONS)",
          "Frontend: Fetch CSRF token on app init",
          "Update apiClient interceptor to add X-CSRF-Token header",
          "Implement csrfService.refreshCsrfToken() to fetch from backend"
        ],
        "tests_to_add": [
          "CSRF attack simulation test",
          "Verify tokens validated on backend",
          "Test token rotation"
        ],
        "regression_risks": ["Existing API calls may fail if CSRF required"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000006",
      "severity": "P1",
      "priority_rank": 6,
      "title": "18 Frontend API Calls Target Missing Backend Endpoints",
      "component": {
        "frontend": "apps/web/src/features/*/services/*.ts, apps/web/src/services/2fa-service.ts",
        "backend": "veza-backend-api/internal/api/router.go",
        "infra": ""
      },
      "category": ["api-contract"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "none",
        "notes": "Frontend calls endpoints that don't exist, causing 404 errors"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/2fa-service.ts",
            "lines": "L17, L22, L27, L31, L35",
            "excerpt": "GET /api/v1/2fa/status, POST /api/v1/2fa/setup, POST /api/v1/2fa/enable, POST /api/v1/2fa/disable, POST /api/v1/2fa/verify"
          },
          {
            "path": "apps/web/src/features/playlists/services/playlistService.ts",
            "lines": "L125, L136, L175, L186, L218",
            "excerpt": "Missing: /playlists/:id/collaborators, /playlists/search, /playlists/:id/share, /playlists/recommendations"
          },
          {
            "path": "veza-backend-api/internal/api/router.go",
            "lines": "L494-L528",
            "excerpt": "Playlist routes only: GET, POST, PUT, DELETE /playlists, POST/DELETE tracks"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Call playlistService.addCollaborator()",
          "Request: POST /api/v1/playlists/:id/collaborators",
          "Backend returns 404",
          "Feature broken"
        ],
        "expected": "All frontend API calls have corresponding backend endpoints",
        "actual": "18 endpoints called but not implemented"
      },
      "root_cause": "Frontend features implemented but backend endpoints not created. Incomplete feature implementation.",
      "fix_plan": {
        "minimal_steps": [
          "Audit all frontend API calls (grep apiClient.get/post/put/delete)",
          "Compare with backend routes (router.go)",
          "For each missing endpoint: implement OR remove frontend call",
          "Update API documentation",
          "Add integration tests"
        ],
        "tests_to_add": [
          "Integration test: Verify all frontend calls have backend endpoints",
          "E2E test: Verify feature works end-to-end"
        ],
        "regression_risks": ["Removing frontend calls may break UI features"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000007",
      "severity": "P1",
      "priority_rank": 7,
      "title": "Environment Variable Naming Inconsistency (VITE_API_BASE_URL vs VITE_API_URL)",
      "component": {
        "frontend": "apps/web/src/config/env.ts, apps/web/scripts/*.sh, apps/web/Dockerfile",
        "backend": "",
        "infra": "deployment configs"
      },
      "category": ["env", "build"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "none",
        "notes": "Some scripts use VITE_API_BASE_URL, others use VITE_API_URL, causing build failures"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/config/env.ts",
            "lines": "L6",
            "excerpt": "VITE_API_URL: z.string().url().default('http://127.0.0.1:8080/api/v1')"
          },
          {
            "path": "apps/web/scripts/check_backend.sh",
            "lines": "L16",
            "excerpt": "API_URL=\"${VITE_API_BASE_URL:-http://localhost:8080/api/v1}\""
          },
          {
            "path": "apps/web/Dockerfile",
            "lines": "L17",
            "excerpt": "ARG VITE_API_BASE_URL"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Set VITE_API_BASE_URL in environment",
          "Frontend code reads VITE_API_URL",
          "VITE_API_URL is undefined",
          "Uses default or throws error"
        ],
        "expected": "Consistent env var name: VITE_API_URL",
        "actual": "Mixed usage: VITE_API_BASE_URL and VITE_API_URL"
      },
      "root_cause": "Migration from VITE_API_BASE_URL to VITE_API_URL incomplete. Some scripts and configs still use old name.",
      "fix_plan": {
        "minimal_steps": [
          "Search for all VITE_API_BASE_URL usage",
          "Replace with VITE_API_URL",
          "Update scripts/check_backend.sh",
          "Update Dockerfile",
          "Update deployment docs"
        ],
        "tests_to_add": [
          "Verify env var name consistent everywhere",
          "Build test with VITE_API_URL"
        ],
        "regression_risks": ["Scripts using old name will break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000008",
      "severity": "P1",
      "priority_rank": 8,
      "title": "Path Mismatch: /users/:userId/profile vs /users/:id",
      "component": {
        "frontend": "apps/web/src/features/profile/services/profileService.ts",
        "backend": "veza-backend-api/internal/api/router.go",
        "infra": ""
      },
      "category": ["api-contract"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": true,
        "security_risk": "none",
        "notes": "Frontend calls /users/:userId/profile but backend expects /users/:id"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/features/profile/services/profileService.ts",
            "lines": "L17, L43",
            "excerpt": "GET /api/v1/users/${userId}/profile, PUT /api/v1/users/${userId}/profile"
          },
          {
            "path": "veza-backend-api/internal/api/router.go",
            "lines": "L344, L358",
            "excerpt": "GET /api/v1/users/:id, PUT /api/v1/users/:id"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Call profileService.getProfile(userId)",
          "Request: GET /api/v1/users/:userId/profile",
          "Backend returns 404",
          "Feature broken"
        ],
        "expected": "Frontend paths match backend routes",
        "actual": "Frontend uses /profile suffix, backend doesn't"
      },
      "root_cause": "Frontend uses /profile suffix but backend routes don't include it. Inconsistent API design.",
      "fix_plan": {
        "minimal_steps": [
          "Option A: Update frontend to use /users/:id (recommended)",
          "Option B: Add /profile routes to backend",
          "Update profileService to use correct paths",
          "Test profile features"
        ],
        "tests_to_add": [
          "Integration test: Verify profile endpoints work",
          "E2E test: Verify profile page loads"
        ],
        "regression_risks": ["Changing paths may break existing code"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000009",
      "severity": "P1",
      "priority_rank": 9,
      "title": "Error Code Type Mismatch: number vs string in ApiError",
      "component": {
        "frontend": "apps/web/src/types/api.ts, apps/web/src/schemas/validation.ts",
        "backend": "veza-backend-api/internal/errors/codes.go",
        "infra": ""
      },
      "category": ["schema-drift", "error-handling"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Type mismatches in error handling, potential runtime errors"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/types/api.ts",
            "lines": "L245",
            "excerpt": "code: number;  // ✅ Correct"
          },
          {
            "path": "apps/web/src/schemas/validation.ts",
            "lines": "L338",
            "excerpt": "code: z.string(),  // ❌ Wrong type"
          },
          {
            "path": "veza-backend-api/internal/errors/codes.go",
            "lines": "L1-L32",
            "excerpt": "ErrorCode is int type"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Backend returns error with code: 1000 (number)",
          "Frontend Zod schema expects code: string",
          "Validation fails or coerces incorrectly"
        ],
        "expected": "Error code is number everywhere",
        "actual": "Mixed types: number in types, string in Zod schemas"
      },
      "root_cause": "Inconsistent error code types. Backend uses int, frontend types use number, but Zod schemas use string.",
      "fix_plan": {
        "minimal_steps": [
          "Update Zod schemas to use z.number() for error code",
          "Verify all error parsing uses number type",
          "Update apiErrorHandler to handle number codes",
          "Test error handling"
        ],
        "tests_to_add": [
          "Test: Verify error codes parsed as numbers",
          "Test: Error display works correctly"
        ],
        "regression_risks": ["Code expecting string may break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000010",
      "severity": "P1",
      "priority_rank": 10,
      "title": "Remember Me Field Handling Inconsistency",
      "component": {
        "frontend": "apps/web/src/services/api/auth.ts, apps/web/src/features/auth/types/index.ts",
        "backend": "veza-backend-api/internal/dto/login_request.go",
        "infra": ""
      },
      "category": ["api-contract"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Field name inconsistency: remember_me vs rememberMe, may cause issues"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/api/auth.ts",
            "lines": "L150",
            "excerpt": "remember_me: data.remember_me || false"
          },
          {
            "path": "apps/web/src/features/auth/types/index.ts",
            "lines": "L11",
            "excerpt": "remember_me?: boolean;"
          },
          {
            "path": "veza-backend-api/internal/dto/login_request.go",
            "lines": "L6",
            "excerpt": "RememberMe bool `json:\"remember_me\"`"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Login form uses rememberMe (camelCase)",
          "API call converts to remember_me (snake_case)",
          "Backend expects remember_me",
          "Works but inconsistent naming"
        ],
        "expected": "Consistent field naming",
        "actual": "Mixed: rememberMe in forms, remember_me in API"
      },
      "root_cause": "Frontend uses camelCase in forms but backend expects snake_case. Conversion happens but inconsistent.",
      "fix_plan": {
        "minimal_steps": [
          "Standardize on snake_case for API (matches backend)",
          "Update form types to use remember_me",
          "Update all references",
          "Test login with remember me"
        ],
        "tests_to_add": [
          "Test: Login with remember_me=true",
          "Test: Token expiration matches remember_me setting"
        ],
        "regression_risks": ["Forms using rememberMe may break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000011",
      "severity": "P1",
      "priority_rank": 11,
      "title": "Token Refresh Response Format Ambiguity",
      "component": {
        "frontend": "apps/web/src/services/tokenRefresh.ts",
        "backend": "veza-backend-api/internal/handlers/auth.go",
        "infra": ""
      },
      "category": ["api-contract", "error-handling"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": true,
        "security_risk": "none",
        "notes": "Multiple format checks in tokenRefresh suggest uncertainty about response structure"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/tokenRefresh.ts",
            "lines": "L70-L84",
            "excerpt": "// Format with wrapper { success: true, data: {...} }\nif (response.data?.data?.access_token) { ... }\n// Format direct { access_token, refresh_token, expires_in }\nelse if (response.data?.access_token) { ... }\n// Format with token nested { token: { access_token, refresh_token } }\nelse if (response.data?.token?.access_token) { ... }"
          },
          {
            "path": "veza-backend-api/internal/handlers/auth.go",
            "lines": "L197-L201",
            "excerpt": "RespondSuccess(c, http.StatusOK, dto.TokenResponse{...})  // Returns { success: true, data: {...} }"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Token refresh called",
          "Backend returns { success: true, data: { access_token, refresh_token, expires_in } }",
          "Frontend checks 3 different formats",
          "Works but fragile"
        ],
        "expected": "Single, documented response format",
        "actual": "Multiple format checks suggest uncertainty"
      },
      "root_cause": "Frontend handles multiple response formats to be defensive, but this indicates contract uncertainty.",
      "fix_plan": {
        "minimal_steps": [
          "Document exact response format in FRONTEND_INTEGRATION.md",
          "Simplify tokenRefresh to only handle correct format",
          "Remove fallback format checks",
          "Add test for refresh response parsing"
        ],
        "tests_to_add": [
          "Test: Verify refresh response parsed correctly",
          "Test: Error handling for invalid format"
        ],
        "regression_risks": ["If format changes, code will break"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000012",
      "severity": "P1",
      "priority_rank": 12,
      "title": "No Retry Logic for Transient Errors (503, 502)",
      "component": {
        "frontend": "apps/web/src/services/api/client.ts",
        "backend": "",
        "infra": ""
      },
      "category": ["error-handling", "reliability"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "503/502 errors are handled but not retried, causing user-visible failures"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/api/client.ts",
            "lines": "L201-L213",
            "excerpt": "if (status === 503) { return Promise.reject(apiError); }\nif (status === 502) { return Promise.reject(apiError); }  // No retry"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Backend returns 503 (Service Unavailable)",
          "Frontend rejects immediately",
          "User sees error",
          "No automatic retry"
        ],
        "expected": "Transient errors (503, 502) should be retried with exponential backoff",
        "actual": "Errors rejected immediately, no retry"
      },
      "root_cause": "No retry logic for transient errors. 429 (rate limit) has retry but 503/502 do not.",
      "fix_plan": {
        "minimal_steps": [
          "Add retry logic for 503/502 errors",
          "Implement exponential backoff (max 3 retries)",
          "Add retry-after header support",
          "Update error messages to indicate retry"
        ],
        "tests_to_add": [
          "Test: Verify 503 retries with backoff",
          "Test: Verify 502 retries with backoff",
          "Test: Max retries respected"
        ],
        "regression_risks": ["May cause excessive retries if not configured correctly"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000013",
      "severity": "P1",
      "priority_rank": 13,
      "title": "Missing Error Correlation IDs in Frontend Error Boundaries",
      "component": {
        "frontend": "apps/web/src (error boundaries)",
        "backend": "veza-backend-api/internal/response/response.go",
        "infra": ""
      },
      "category": ["observability", "error-handling"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Backend returns request_id but frontend doesn't log it, making debugging difficult"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/response/response.go",
            "lines": "L106",
            "excerpt": "RequestID: c.GetString(\"request_id\")"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "API error occurs",
          "Backend returns { error: { request_id: \"req-123\", ... } }",
          "Frontend logs error but doesn't include request_id",
          "Debugging difficult"
        ],
        "expected": "Frontend error logs include request_id for correlation",
        "actual": "Request ID not logged in frontend"
      },
      "root_cause": "Backend provides request_id for error correlation but frontend doesn't extract or log it.",
      "fix_plan": {
        "minimal_steps": [
          "Update apiErrorHandler to extract request_id",
          "Include request_id in error logs",
          "Update error boundaries to log request_id",
          "Add request_id to user-facing error messages (optional)"
        ],
        "tests_to_add": [
          "Test: Verify request_id logged in errors",
          "Test: Error correlation works"
        ],
        "regression_risks": ["None"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000014",
      "severity": "P1",
      "priority_rank": 14,
      "title": "CORS Allow-Credentials Always True (Security Risk if Origins Misconfigured)",
      "component": {
        "frontend": "",
        "backend": "veza-backend-api/internal/middleware/cors.go",
        "infra": ""
      },
      "category": ["cors", "security"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "medium",
        "notes": "If CORS origins misconfigured, credentials flag enables cookie theft"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/middleware/cors.go",
            "lines": "L21",
            "excerpt": "c.Header(\"Access-Control-Allow-Credentials\", \"true\")  // Always true"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "CORS origins misconfigured (e.g., contains wildcard or wrong domain)",
          "Malicious site makes credentialed request",
          "Credentials flag allows cookies/tokens to be sent",
          "Security risk"
        ],
        "expected": "Credentials only allowed if origins correctly whitelisted",
        "actual": "Credentials always true, relies on origins being correct"
      },
      "root_cause": "Credentials flag hardcoded to true. Relies on origins being correctly configured. If origins misconfigured, security risk.",
      "fix_plan": {
        "minimal_steps": [
          "Add validation: credentials only if origins non-empty and no wildcard",
          "Log warning if credentials=true but origins contain wildcard",
          "Document security implications",
          "Add test for credentials + wildcard combination"
        ],
        "tests_to_add": [
          "Test: Verify credentials rejected with wildcard",
          "Test: Verify credentials allowed with specific origins"
        ],
        "regression_risks": ["If origins misconfigured, requests may fail"]
      },
      "dependencies": ["INT-000001"],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000015",
      "severity": "P1",
      "priority_rank": 15,
      "title": "GetMe Endpoint Returns Incomplete User Data",
      "component": {
        "frontend": "apps/web/src/features/auth/api/authApi.ts",
        "backend": "veza-backend-api/internal/handlers/auth.go",
        "infra": ""
      },
      "category": ["api-contract"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "GET /auth/me returns only id, email, role but frontend expects full user object"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/handlers/auth.go",
            "lines": "L369-L373",
            "excerpt": "RespondSuccess(c, http.StatusOK, gin.H{\n    \"id\": userID,\n    \"email\": c.GetString(\"email\"),\n    \"role\": c.GetString(\"role\")\n})  // Missing username, avatar, etc."
          },
          {
            "path": "apps/web/src/features/auth/api/authApi.ts",
            "lines": "L34-L36",
            "excerpt": "getMe: async (): Promise<User> => { ... }  // Expects full User object"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Call authApi.getMe()",
          "Backend returns { id, email, role }",
          "Frontend expects full User object with username, avatar, etc.",
          "Type mismatch or missing fields"
        ],
        "expected": "GET /auth/me returns full user object",
        "actual": "Returns only id, email, role"
      },
      "root_cause": "GetMe handler returns minimal user data from context, not full user object from database.",
      "fix_plan": {
        "minimal_steps": [
          "Update GetMe handler to fetch full user from database",
          "Return complete UserResponse object",
          "Update frontend types if needed",
          "Test getMe returns all expected fields"
        ],
        "tests_to_add": [
          "Test: Verify getMe returns full user object",
          "Test: Verify all User fields present"
        ],
        "regression_risks": ["Frontend may break if response structure changes"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000016",
      "severity": "P2",
      "priority_rank": 16,
      "title": "Field Name Mismatch: cover_art_path vs cover_art_url",
      "component": {
        "frontend": "apps/web/src/types/api.ts",
        "backend": "veza-backend-api (track models)",
        "infra": ""
      },
      "category": ["schema-drift"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Field name inconsistency may cause display issues"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/types/api.ts",
            "lines": "L66",
            "excerpt": "cover_art_path?: string;  // Backend uses cover_art_path"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Backend returns cover_art_path",
          "Frontend expects cover_art_path",
          "Works but naming inconsistent with other _url fields"
        ],
        "expected": "Consistent field naming",
        "actual": "Mixed: _path vs _url"
      },
      "root_cause": "Inconsistent naming convention. Some fields use _url, others use _path.",
      "fix_plan": {
        "minimal_steps": [
          "Document field naming convention",
          "Standardize on _url for URLs, _path for file paths",
          "Update types and backend if needed",
          "Update documentation"
        ],
        "tests_to_add": [
          "Test: Verify cover art displays correctly",
          "Test: Verify field names consistent"
        ],
        "regression_risks": ["Changing field names may break existing code"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000017",
      "severity": "P2",
      "priority_rank": 17,
      "title": "Pagination Format Inconsistencies",
      "component": {
        "frontend": "apps/web/src/types/api.ts",
        "backend": "veza-backend-api (pagination responses)",
        "infra": ""
      },
      "category": ["schema-drift"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Different pagination formats may cause parsing issues"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/types/api.ts",
            "lines": "L222-L231",
            "excerpt": "PaginationData: { page, limit, total, total_pages, has_next, has_prev, next_cursor?, prev_cursor? }"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Backend returns pagination in different format",
          "Frontend expects specific format",
          "Parsing may fail or be inconsistent"
        ],
        "expected": "Consistent pagination format across all endpoints",
        "actual": "May vary by endpoint"
      },
      "root_cause": "No standardized pagination format. Different endpoints may return different structures.",
      "fix_plan": {
        "minimal_steps": [
          "Document standard pagination format",
          "Audit all paginated endpoints",
          "Standardize pagination responses",
          "Update frontend types"
        ],
        "tests_to_add": [
          "Test: Verify pagination format consistent",
          "Test: Verify pagination parsing works"
        ],
        "regression_risks": ["Changing pagination format may break existing code"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000018",
      "severity": "P2",
      "priority_rank": 18,
      "title": "Missing Validation Schema Alignment Between Frontend and Backend",
      "component": {
        "frontend": "apps/web/src/schemas/validation.ts",
        "backend": "veza-backend-api/internal/validators",
        "infra": ""
      },
      "category": ["schema-drift", "validation"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Frontend and backend validation rules may differ, causing inconsistent errors"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/schemas/validation.ts",
            "lines": "L1-L359",
            "excerpt": "Zod schemas for validation"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Frontend validates email format",
          "Backend validates differently",
          "Frontend passes, backend rejects (or vice versa)",
          "Inconsistent user experience"
        ],
        "expected": "Frontend and backend validation rules match",
        "actual": "Validation rules may differ"
      },
      "root_cause": "No synchronization between frontend Zod schemas and backend validators. Rules may drift.",
      "fix_plan": {
        "minimal_steps": [
          "Audit validation rules in both frontend and backend",
          "Document validation rules in shared doc",
          "Align frontend Zod schemas with backend validators",
          "Add tests to verify alignment"
        ],
        "tests_to_add": [
          "Test: Verify validation rules match",
          "Test: Verify error messages consistent"
        ],
        "regression_risks": ["Changing validation may break existing forms"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000019",
      "severity": "P2",
      "priority_rank": 19,
      "title": "No Request ID Propagation to Frontend Logs",
      "component": {
        "frontend": "apps/web/src/services/api/client.ts",
        "backend": "veza-backend-api/internal/middleware/request_id.go",
        "infra": ""
      },
      "category": ["observability"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Backend generates request_id but frontend doesn't log it, making debugging difficult"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/middleware/request_id.go",
            "lines": "L1-L20",
            "excerpt": "RequestID middleware generates X-Request-ID header"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "API request made",
          "Backend generates request_id",
          "Frontend doesn't log request_id",
          "Debugging difficult"
        ],
        "expected": "Frontend logs include request_id for correlation",
        "actual": "Request ID not logged in frontend"
      },
      "root_cause": "Backend generates request_id but frontend doesn't extract or log it in request/response interceptors.",
      "fix_plan": {
        "minimal_steps": [
          "Update apiClient interceptor to extract X-Request-ID from response",
          "Include request_id in request logs",
          "Include request_id in error logs",
          "Add request_id to error objects"
        ],
        "tests_to_add": [
          "Test: Verify request_id logged",
          "Test: Verify request_id in error objects"
        ],
        "regression_risks": ["None"]
      },
      "dependencies": ["INT-000013"],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000020",
      "severity": "P2",
      "priority_rank": 20,
      "title": "Inconsistent Error Detail Formats",
      "component": {
        "frontend": "apps/web/src/utils/apiErrorHandler.ts",
        "backend": "veza-backend-api/internal/errors/errors.go",
        "infra": ""
      },
      "category": ["error-handling"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Different error detail formats may cause parsing issues"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/utils/apiErrorHandler.ts",
            "lines": "L145-L154",
            "excerpt": "normalizeApiError handles multiple error formats"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Backend returns error with details array",
          "Frontend expects specific format",
          "Parsing may fail or be inconsistent"
        ],
        "expected": "Consistent error detail format",
        "actual": "Multiple formats handled, suggests inconsistency"
      },
      "root_cause": "Backend may return errors in different formats, frontend handles multiple formats defensively.",
      "fix_plan": {
        "minimal_steps": [
          "Standardize error detail format in backend",
          "Simplify frontend error parsing",
          "Remove fallback format handling",
          "Update error documentation"
        ],
        "tests_to_add": [
          "Test: Verify error parsing works",
          "Test: Verify error details displayed correctly"
        ],
        "regression_risks": ["If format changes, parsing may break"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000021",
      "severity": "P2",
      "priority_rank": 21,
      "title": "Missing Health Check Integration Tests",
      "component": {
        "frontend": "apps/web/e2e",
        "backend": "veza-backend-api/internal/handlers/health.go",
        "infra": ""
      },
      "category": ["testing", "observability"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "No E2E tests verify health check endpoints work"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/e2e/qa-audit.spec.ts",
            "lines": "L80",
            "excerpt": "const response = await page.request.get(`${API_URL}/health`);  // Basic check but no assertion"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Health check endpoint called",
          "No test verifies response format",
          "If format changes, no test catches it"
        ],
        "expected": "E2E tests verify health check endpoints",
        "actual": "Basic check exists but no assertions"
      },
      "root_cause": "Health check endpoints exist but not properly tested in E2E suite.",
      "fix_plan": {
        "minimal_steps": [
          "Add E2E test for GET /api/v1/health",
          "Verify response format",
          "Verify health status",
          "Add tests for /healthz and /readyz"
        ],
        "tests_to_add": [
          "E2E test: Verify /health returns correct format",
          "E2E test: Verify /healthz returns 200",
          "E2E test: Verify /readyz returns 200"
        ],
        "regression_risks": ["None"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000022",
      "severity": "P2",
      "priority_rank": 22,
      "title": "No API Versioning Strategy",
      "component": {
        "frontend": "apps/web/src/services/api/client.ts",
        "backend": "veza-backend-api/internal/api/router.go",
        "infra": ""
      },
      "category": ["api-contract"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "All routes under /api/v1, no versioning strategy for future changes"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/api/router.go",
            "lines": "L152",
            "excerpt": "v1 := router.Group(\"/api/v1\")  // Hardcoded v1"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "API needs breaking change",
          "No versioning strategy",
          "Must break existing clients or maintain backward compatibility forever"
        ],
        "expected": "Versioning strategy for API changes",
        "actual": "All routes under /api/v1, no migration path"
      },
      "root_cause": "No API versioning strategy. All routes under /api/v1 with no plan for v2.",
      "fix_plan": {
        "minimal_steps": [
          "Document API versioning strategy",
          "Plan for v2 when needed",
          "Add version negotiation if needed",
          "Update documentation"
        ],
        "tests_to_add": [
          "Test: Verify versioning works",
          "Test: Verify backward compatibility"
        ],
        "regression_risks": ["None - planning only"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000023",
      "severity": "P2",
      "priority_rank": 23,
      "title": "WebSocket Token in Query Params (Security Risk)",
      "component": {
        "frontend": "apps/web/src/services/api.ts",
        "backend": "",
        "infra": ""
      },
      "category": ["security", "websocket"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "medium",
        "notes": "WebSocket tokens in URL query params exposed in logs, browser history"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/api.ts",
            "lines": "L565",
            "excerpt": "return `${WS_BASE_URL}?token=${token}`;  // Token in query param"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "WebSocket connection established",
          "Token in URL: ws://example.com/ws?token=xxx",
          "Token exposed in browser history, server logs",
          "Security risk"
        ],
        "expected": "Token in header or subprotocol, not query param",
        "actual": "Token in query param"
      },
      "root_cause": "WebSocket authentication uses query param instead of header or subprotocol.",
      "fix_plan": {
        "minimal_steps": [
          "Move token to WebSocket subprotocol or header",
          "Update WebSocket client to use header",
          "Update chat server to read from header",
          "Remove token from query params"
        ],
        "tests_to_add": [
          "Test: Verify WebSocket auth works with header",
          "Test: Verify token not in URL"
        ],
        "regression_risks": ["WebSocket connections may break if not updated correctly"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000024",
      "severity": "P3",
      "priority_rank": 24,
      "title": "Deprecated Routes Still Accessible",
      "component": {
        "frontend": "",
        "backend": "veza-backend-api/internal/api/router.go",
        "infra": ""
      },
      "category": ["api-contract", "maintainability"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Deprecated routes still work, causing confusion and maintenance burden"
      },
      "evidence": {
        "files": [
          {
            "path": "veza-backend-api/internal/api/router.go",
            "lines": "L596-L603",
            "excerpt": "router.GET(\"/health\", deprecationMW, healthCheckHandler)  // Deprecated but still works"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Call deprecated /health endpoint",
          "Returns deprecation warning but still works",
          "No removal plan"
        ],
        "expected": "Deprecated routes removed or have removal timeline",
        "actual": "Deprecated routes still accessible indefinitely"
      },
      "root_cause": "Deprecated routes marked with warning but not removed. No removal timeline.",
      "fix_plan": {
        "minimal_steps": [
          "Document removal timeline for deprecated routes",
          "Add removal date to deprecation warnings",
          "Plan migration path",
          "Remove deprecated routes after migration period"
        ],
        "tests_to_add": [
          "Test: Verify deprecated routes return warnings",
          "Test: Verify new routes work"
        ],
        "regression_risks": ["Removing routes may break existing clients"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000025",
      "severity": "P3",
      "priority_rank": 25,
      "title": "Inconsistent Logging Formats",
      "component": {
        "frontend": "apps/web/src (logging)",
        "backend": "veza-backend-api (structured logging)",
        "infra": ""
      },
      "category": ["observability"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Frontend uses console.log, backend uses structured logging, making correlation difficult"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/api/client.ts",
            "lines": "L62",
            "excerpt": "console.error('[API] Failed to parse auth storage:', e);  // Unstructured"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Frontend logs error with console.error",
          "Backend logs with structured format",
          "Log aggregation difficult",
          "Correlation challenging"
        ],
        "expected": "Structured logging in frontend for correlation",
        "actual": "Mixed: console.log in frontend, structured in backend"
      },
      "root_cause": "Frontend uses console.log while backend uses structured logging. No correlation.",
      "fix_plan": {
        "minimal_steps": [
          "Introduce structured logging library for frontend",
          "Replace console.log with structured logger",
          "Include request_id, user_id in logs",
          "Update log aggregation config"
        ],
        "tests_to_add": [
          "Test: Verify logs structured",
          "Test: Verify correlation works"
        ],
        "regression_risks": ["Changing logging may break log aggregation"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000026",
      "severity": "P3",
      "priority_rank": 26,
      "title": "Missing Observability Hooks in Frontend",
      "component": {
        "frontend": "apps/web/src (error boundaries, API calls)",
        "backend": "",
        "infra": ""
      },
      "category": ["observability"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "No error tracking (Sentry), no performance monitoring, making production debugging difficult"
      },
      "evidence": {
        "files": [],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Error occurs in production",
          "No error tracking",
          "Debugging difficult",
          "No visibility into issues"
        ],
        "expected": "Error tracking and performance monitoring in frontend",
        "actual": "No observability tools integrated"
      },
      "root_cause": "No error tracking or performance monitoring integrated in frontend.",
      "fix_plan": {
        "minimal_steps": [
          "Integrate Sentry or similar error tracking",
          "Add performance monitoring",
          "Add error boundaries with tracking",
          "Configure error reporting"
        ],
        "tests_to_add": [
          "Test: Verify errors tracked",
          "Test: Verify performance monitored"
        ],
        "regression_risks": ["None"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000027",
      "severity": "P3",
      "priority_rank": 27,
      "title": "No Rate Limit Headers in Responses",
      "component": {
        "frontend": "apps/web/src/services/api/client.ts",
        "backend": "veza-backend-api (rate limiting)",
        "infra": ""
      },
      "category": ["observability", "api-contract"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Rate limit info not exposed, frontend can't show remaining requests"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/services/api/client.ts",
            "lines": "L181-L199",
            "excerpt": "Handles 429 but no rate limit headers checked"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Rate limit hit",
          "Backend returns 429",
          "Frontend doesn't know remaining requests",
          "Can't show user-friendly message"
        ],
        "expected": "Rate limit headers (X-RateLimit-*) in responses",
        "actual": "No rate limit headers"
      },
      "root_cause": "Backend rate limiting exists but doesn't expose rate limit info in headers.",
      "fix_plan": {
        "minimal_steps": [
          "Add X-RateLimit-* headers to rate limit middleware",
          "Update frontend to read and display rate limit info",
          "Update error messages to show remaining requests",
          "Document rate limit headers"
        ],
        "tests_to_add": [
          "Test: Verify rate limit headers present",
          "Test: Verify frontend displays rate limit info"
        ],
        "regression_risks": ["None"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000028",
      "severity": "P3",
      "priority_rank": 28,
      "title": "Missing API Documentation Updates",
      "component": {
        "frontend": "apps/web/FRONTEND_INTEGRATION.md",
        "backend": "veza-backend-api/docs",
        "infra": ""
      },
      "category": ["documentation"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "API documentation may be out of sync with implementation"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/FRONTEND_INTEGRATION.md",
            "lines": "L1-L307",
            "excerpt": "API documentation"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "API endpoint changes",
          "Documentation not updated",
          "Developers use wrong format",
          "Errors occur"
        ],
        "expected": "API documentation always up to date",
        "actual": "Documentation may be outdated"
      },
      "root_cause": "No automated process to keep API documentation in sync with implementation.",
      "fix_plan": {
        "minimal_steps": [
          "Use OpenAPI/Swagger for API documentation",
          "Generate docs from code",
          "Update FRONTEND_INTEGRATION.md from OpenAPI spec",
          "Add CI check for doc sync"
        ],
        "tests_to_add": [
          "Test: Verify docs match implementation",
          "Test: Verify CI catches doc drift"
        ],
        "regression_risks": ["None"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    },
    {
      "id": "INT-000029",
      "severity": "P3",
      "priority_rank": 29,
      "title": "No Vite Proxy Configuration for Development",
      "component": {
        "frontend": "apps/web/vite.config.ts",
        "backend": "",
        "infra": ""
      },
      "category": ["env", "build"],
      "status": "open",
      "impact": {
        "user_visible": false,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "Direct CORS requests in dev, no proxy. Works but not ideal."
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/vite.config.ts",
            "lines": "L58-L92",
            "excerpt": "server config but no proxy setup"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Frontend on localhost:3000",
          "Backend on localhost:8080",
          "CORS required",
          "No proxy, direct requests"
        ],
        "expected": "Vite proxy for /api to backend (optional but cleaner)",
        "actual": "No proxy, direct CORS requests"
      },
      "root_cause": "No Vite proxy configuration. Relies on CORS for dev. Works but proxy would be cleaner.",
      "fix_plan": {
        "minimal_steps": [
          "Add Vite proxy config for /api to http://localhost:8080",
          "Update VITE_API_URL to use relative path /api/v1",
          "Test proxy works",
          "Update dev docs"
        ],
        "tests_to_add": [
          "Test: Verify proxy works",
          "Test: Verify API calls work through proxy"
        ],
        "regression_risks": ["Changing to proxy may break existing dev setup"]
      },
      "dependencies": [],
      "owner_suggestion": "frontend"
    },
    {
      "id": "INT-000030",
      "severity": "P3",
      "priority_rank": 30,
      "title": "Missing HLS Endpoints (Frontend Calls But Backend Doesn't Implement)",
      "component": {
        "frontend": "apps/web/src/features/streaming/services/hlsService.ts",
        "backend": "veza-backend-api/internal/api/router.go",
        "infra": ""
      },
      "category": ["api-contract"],
      "status": "open",
      "impact": {
        "user_visible": true,
        "breaks_core_flow": false,
        "security_risk": "none",
        "notes": "HLS streaming features may not work"
      },
      "evidence": {
        "files": [
          {
            "path": "apps/web/src/features/streaming/services/hlsService.ts",
            "lines": "L85, L97",
            "excerpt": "GET /api/v1/tracks/:id/hls/info, GET /api/v1/tracks/:id/hls/status"
          }
        ],
        "runtime": []
      },
      "repro": {
        "steps": [
          "Call hlsService.getHLSInfo()",
          "Request: GET /api/v1/tracks/:id/hls/info",
          "Backend returns 404",
          "HLS features broken"
        ],
        "expected": "HLS endpoints implemented or frontend calls removed",
        "actual": "Frontend calls endpoints that don't exist"
      },
      "root_cause": "HLS streaming features in frontend but backend endpoints not implemented.",
      "fix_plan": {
        "minimal_steps": [
          "Implement HLS endpoints in backend OR",
          "Remove HLS service calls from frontend",
          "Update documentation",
          "Test streaming works"
        ],
        "tests_to_add": [
          "Test: Verify HLS endpoints work",
          "Test: Verify streaming works end-to-end"
        ],
        "regression_risks": ["Removing calls may break streaming features"]
      },
      "dependencies": [],
      "owner_suggestion": "backend"
    }
  ]
}

