PROJECT issues jsou zobrazitelné ve třech lokacích — Workspace tab (per-project), Studio dashboard widget (cross-project preview) a dedikovaná list stránka /studio/issues (full cross-project list). Všechny lokace jsou scoped na přihlášeného tenantu — uživatel nikdy nevidí issues jiného tenantu.
- Existující
GET /api/issuesendpoint (UC-09002) se rozšiřuje o query parametrytargetType=PROJECTaprojectId=<uuid>pro per-project view. - Cross-project view (Studio widget + list stránka) posílá
targetType=PROJECT&tenantScoped=true— BE vrátí všechny PROJECT issues daného tenantu bez filtru na projekt. - Žádná nová DB migrace — pouze BE query logika a FE komponenty.
- Scoping: BE vždy filtruje přes
tenant_idz JWT — cross-tenant přístup není možný.
Flow 1 — Workspace tab Issues (per-project view)
sequenceDiagram
actor User
User->>+FE: otevře Workspace tab "Issues" pro projekt X
FE->>+BE: GET /api/issues?targetType=PROJECT&projectId={id}&status=OPEN
Note over FE,BE: Authorization: Bearer {userJWT}
BE->>BE: ověř JWT, extrahuj tenant_id
BE->>DB: SELECT issues WHERE target=PROJECT AND project_id={id} AND tenant_id=<z JWT><br/>AND status=OPEN ORDER BY reported_at DESC LIMIT 50
BE-->>-FE: 200 OK [ IssueSummary[] ]
FE->>-User: zobrazí list issues pro projekt X (kind badge, severity badge, title, reported_at, status)
Flow 2 — Studio dashboard widget (cross-project preview)
sequenceDiagram
actor User
User->>+FE: otevře Studio dashboard
FE->>+BE: GET /api/issues?targetType=PROJECT&tenantScoped=true&status=OPEN&pageSize=5
Note over FE,BE: Authorization: Bearer {userJWT}
BE->>BE: ověř JWT, extrahuj tenant_id
BE->>DB: SELECT issues WHERE target=PROJECT AND tenant_id=<z JWT><br/>AND status=OPEN ORDER BY severity DESC, reported_at DESC LIMIT 5
BE-->>-FE: 200 OK { items: [...], total: 12, page: 1, pageSize: 5 }
FE->>-User: zobrazí sekci ISSUES na dashboardu: top-5 issues + "View All (12) →" link
Note over FE: "12" = response.total — žádný separátní /count request
Flow 3 — Dedikovaná list stránka /studio/issues (cross-project full list)
sequenceDiagram
actor User
User->>+FE: naviguje na /studio/issues (nebo klikne "View All →" z dashboardu)
FE->>+BE: GET /api/issues?targetType=PROJECT&tenantScoped=true
Note over FE,BE: s aktivními filtry: &projectId=&status=&query=
BE->>BE: ověř JWT, extrahuj tenant_id
BE->>DB: SELECT issues WHERE target=PROJECT AND tenant_id=<z JWT><br/>s aplikovanými filtry ORDER BY severity DESC, reported_at DESC LIMIT 100
BE-->>-FE: 200 OK [ IssueSummary[] ]
FE->>-User: zobrazí full list s filter barem (projekt, status, kind, search)
REST API
GET /api/issues (rozšíření Phase 3)
Autentizace: User JWT nebo Agent JWT.
Nové query params (Phase 3):
| Param | Typ | Popis |
|---|---|---|
targetType | string | PROJECT nebo PLATFORM (alternativa k stávajícímu target — oba přijaty) |
projectId | UUID | Per-project filter; vrátí issues pouze pro daný projekt |
tenantScoped | boolean | Pokud true, vrátí všechny PROJECT issues tenantu bez filtru na projekt |
limit | integer | Max počet výsledků; default 50, max 100 |
Pozn.: Parametry
targetType/targetjsou aliasy — BE akceptuje oba pro zpětnou kompatibilitu. Nový kód preferujetargetType.
Scoping pravidla:
- Vždy:
tenant_id = <z JWT>— žádný cross-tenant přístup. projectIdpřítomen: filtruj jen na daný projekt (+ ověřproject.tenant_id = tenant_id z JWT).tenantScoped=true: vrátí issues pro všechny projekty tenantu.- Bez parametrů: chování jako Phase 1 (scoped na
reporter_user_id).
Příklad — per-project:
GET /api/issues?targetType=PROJECT&projectId=a1b2c3d4-0000-0000-0000-000000000001&status=OPEN
Authorization: Bearer <userJWT>
Příklad — cross-project (Studio list):
GET /api/issues?targetType=PROJECT&tenantScoped=true
Authorization: Bearer <userJWT>
200 OK:
{
"items": [
{
"id": "660f9511-e3ac-42d5-b827-557766551234",
"target": "PROJECT",
"project_id": "a1b2c3d4-0000-0000-0000-000000000001",
"project_name": "my-app",
"kind": "BUG",
"severity": "HIGH",
"status": "OPEN",
"title": "SQL query vrací duplicitní řádky při JOIN bez DISTINCT",
"reporter_agent": "MARA",
"reported_at": "2026-05-14T08:30:00Z",
"url": "https://talkide.app/studio/issues/660f9511-e3ac-42d5-b827-557766551234",
"reporter_email": null,
"tenant_slug": "my-tenant"
}
],
"total": 12,
"page": 1,
"pageSize": 50
}
project_nameje nové pole vIssueSummarypro PROJECT issues — BE JOIN-uje naprojects.name. PLATFORM issues majíproject_name: null.
total= celkový počet záznamů vyhovujících filtru (bez stránkování). Studio dashboard používátotalpro “View All (N) →” badge — žádný separátní/countendpoint není potřeba.
200 OK (prázdný výsledek):
{
"items": [],
"total": 0,
"page": 1,
"pageSize": 50
}
401 Unauthorized:
{
"code": "UNAUTHORIZED",
"message": "Missing or invalid authentication token"
}
400 Bad Request (neplatné projectId UUID):
{
"code": "VALIDATION",
"message": "projectId must be a valid UUID"
}
Frontend
Workspace tab — Issues list
Route: součást Workspace panel pro daný projekt (ne samostatná route).
| Prvek | Popis |
|---|---|
| Status filter | Výchozí OPEN; volby OPEN, TRIAGED, IN_PROGRESS, RESOLVED, WONTFIX, DUPLICATE, ALL |
| ”Nahlásit problém” button | Otevře modal z UC-09005 |
| Tabulka issues | Kind badge, Severity badge, Title, Reported at (relativní), Status badge |
Empty state: Ilustrace + “Zatím žádné issues pro tento projekt.”
Studio dashboard widget — sekce ISSUES
Umístění: Studio dashboard, sekce “ISSUES” (pod Projects).
| Prvek | Popis |
|---|---|
| Nadpis | ”ISSUES” (uppercase, small caps — design pattern dashboardu) |
| Top-5 issues | Řazeno severity DESC, reported_at DESC; zobrazit: Project name, Severity badge, Title (zkrácený na 60 chars), Status badge |
| ”View All (N) →“ | Link na /studio/issues; N = response.total z GET /api/issues?pageSize=5 — bez separátního count requestu |
Pokud count = 0, sekce ISSUES se na dashboardu nezobrazí (prázdná sekce ruší přehlednost).
Dedikovaná list stránka /studio/issues
Route: /studio/issues
Toolbar:
| Prvek | Popis |
|---|---|
| Project filter dropdown | Výchozí “All projects”; volby = názvy projektů tenantu |
| Status filter dropdown | Výchozí OPEN; všechny statusy + ALL |
| Kind filter | ALL, BUG, FEATURE |
| Search input | ?query=; debounce 300 ms |
| Refresh button | Ikona RefreshCw (lucide-vue-next) |
Tabulka — sloupce:
| Sloupec | Zdroj | Poznámka |
|---|---|---|
| Project | project_name | Kliknutelný link → otevře Workspace daného projektu |
| Severity badge | severity | HIGH=červená, MEDIUM=žlutá, LOW=šedá |
| Kind | kind | BUG / FEATURE |
| Title | title | Kliknutelný link → detail issue |
| Reporter | reporter_agent icon | MARA=robot icon, USER=user icon |
| Reported at | reported_at | Relativní čas; hover = absolutní ISO |
| Status badge | status | Barevné kódy identické s UC-09002 FE sekce |
Výchozí řazení: severity DESC, reported_at DESC.
Paging: Bez explicitního stránkování. Limit 100; pokud vráceno přesně 100, notice “Zobrazeno prvních 100 výsledků — zpřesni filtr.”
Validations (FE)
| Param | Constraints | Note |
|---|---|---|
projectId | nullable UUID nebo prázdný string | Pokud vybrán projekt z dropdownu |
status | nullable, in(OPEN, TRIAGED, IN_PROGRESS, RESOLVED, WONTFIX, DUPLICATE) | |
query | nullable, max 200 chars | Trim před odesláním |
Backend
Validations
| Param | Constraints | Note |
|---|---|---|
targetType / target | nullable, in(PLATFORM, PROJECT) | Oba aliasy přijaty |
projectId | nullable UUID | Pokud předán: ověř project.tenant_id = tenant_id z JWT → 403 při mismatch |
tenantScoped | boolean | Pokud true, ignoruje reporter_user_id scope (vrátí celý tenant) |
status | nullable, in(OPEN, TRIAGED, IN_PROGRESS, RESOLVED, WONTFIX, DUPLICATE) | Neplatná hodnota → 400 |
query | nullable, max 200 chars | ILIKE %query% nad title a description |
limit | integer, default 50, max 100 | |
| Tenant scope | tenant_id = <z JWT> vždy aplikován | Nelze vypnout; cross-tenant přístup zakázán |
Test Cases
| GIVEN | WHEN | THEN |
|---|---|---|
| Projekt má 3 OPEN PROJECT issues | GET /api/issues?targetType=PROJECT&projectId=<id>&status=OPEN | 200 OK, 3 záznamy; každý má project_id, project_name, kind, severity, status |
| Tenant má 12 OPEN PROJECT issues napříč 4 projekty | GET /api/issues?targetType=PROJECT&tenantScoped=true&status=OPEN | 200 OK, 12 záznamů; issues ze všech 4 projektů |
projectId patří jinému tenantu | GET /api/issues?targetType=PROJECT&projectId=<cizi> | 403 Forbidden nebo prázdný výsledek [] (tenant scope filter eliminuje cizí projekt) |
| Žádné PROJECT issues pro daný projekt | GET /api/issues?targetType=PROJECT&projectId=<id> | 200 OK, prázdné pole [] |
| Chybějící JWT | GET /api/issues?targetType=PROJECT&tenantScoped=true | 401 Unauthorized |
Neplatné UUID v projectId | GET /api/issues?projectId=not-a-uuid | 400 Bad Request, code=VALIDATION |
query delší než 200 znaků | GET /api/issues?query=... | 400 Bad Request |
References
- UC-09002 Search Issues — základní search endpoint (Phase 1); Phase 3 rozšiřuje query params
- UC-09005 Report Project Issue — vytváření PROJECT issues
- UC-09007 Mara Injects Open Issues — OPEN issues injektovány do CLAUDE.md pro cross-session continuity
FEEDBACK
UC pokrývá 3 flows v jednom dokumentu — alternativou bylo 3 separátní UCs, ale všechny tři sdílí jeden endpoint a jeden datový model, takže sloučení dává smysl. Obě ambiguity byly vyřešeny: (1) separátní GET /api/issues/count endpoint se neimplementuje — FE derivuje count z response.total v pagination envelope; (2) Studio dashboard widget fetchuje top-5 s pageSize=5 a total z téhož response použije pro “View All (N) →” badge — jeden request, žádný extra COUNT.
Thanks for the feedback.