Při startu nebo pokračování konverzace nad projektem BE automaticky injektuje OPEN PROJECT issues do CLAUDE.md — sekce # Open TODO issues. Mara tak vidí aktuální TODO list bez explicitního dotazu. UC nemá vlastní REST endpoint — jde o interní BE chování MaraContextRenderer.
- Trigger:
StartConversationUseCase,AutoStartConversationUseCase,SendMessageUseCase— kdekoliv se sestavuje CLAUDE.md pro danou konverzaci. - Řazení
reported_at ASC, id ASCje kritické pro deterministické pořadí — Anthropic prompt cache hašuje obsah CLAUDE.md, nekonzistentní pořadí by invalidovalo cache a zvyšovalo náklady. - Limit 20 issues (N+1 trick): repository query používá
LIMIT 21. Pokud výsledek vrátí 21 záznamů → je více než 20 → renderuj prvních 20 + summary řádek> _and more than 20 more open issues_. Přesné číslo se nevypisuje — žádný COUNT(*) query. - Empty case: pokud nejsou žádné OPEN/IN_PROGRESS issues, sekce
# Open TODO issuesse do CLAUDE.md nepřidá vůbec (prázdná sekce by zbytečně šumela prompt). - Pouze
OPENaIN_PROGRESSstatusy jsou injektovány —TRIAGED,RESOLVED,WONTFIX,DUPLICATEse nezobrazují.
Flow — sestavení CLAUDE.md při startu konverzace
sequenceDiagram
participant UC as StartConversationUseCase
participant Renderer as MaraContextRenderer
participant Repo as IssueRepository
participant DB
UC->>+Renderer: renderClaudeMd(projectId, tenantId, ...)
Renderer->>+Repo: findByProjectIdAndStatusInOrderByReportedAtAscIdAsc(projectId, [OPEN, IN_PROGRESS])
Repo->>DB: SELECT * FROM issues WHERE project_id=? AND tenant_id=? AND status IN ('OPEN','IN_PROGRESS')<br/>ORDER BY reported_at ASC, id ASC LIMIT 21
DB-->>Repo: issues[]
Repo-->>-Renderer: issues[]
alt issues je prázdný []
Renderer->>Renderer: nepřidávej sekci # Open TODO issues
else issues.size <= 20 (vrátil méně než 21)
Renderer->>Renderer: renderuj sekci se všemi issues, žádný summary řádek
else issues.size == 21 (víc než 20 — N+1 trick)
Renderer->>Renderer: renderuj sekci s prvními 20 issues + summary řádek<br/>"and more than 20 more open issues"<br/>Žádný COUNT(*) — přesné číslo se nevypisuje
end
Renderer-->>-UC: claudeMd (string s injektovanou sekcí nebo bez ní)
UC->>UC: odešle CLAUDE.md do konverzace jako system context
Renderovaná sekce v CLAUDE.md
Formát
# Open TODO issues
- [BUG] SQL query vrací duplicitní řádky při JOIN bez DISTINCT (#660f9511) — Metoda UserRepository.findActiveUsers() vrací duplicitní záznamy kvůli chybějícímu DISTINCT…
- [FEATURE] Exportní funkce pro CSV (#771a0022) — Uživatelé potřebují exportovat data do CSV formátu pro zpracování v Excelu.
- [BUG] Přihlašovací formulář nepřijímá speciální znaky (#882b1133) — Po zadání hesla se speciálními znaky (např. !@#$) formulář zobrazí prázdnou error me…
Pravidla formátování
| Prvek | Pravidlo |
|---|---|
| Prefix | [BUG] nebo [FEATURE] dle kind |
| Title | Beze změny, originální text |
| ID | (#<prvních 8 znaků UUID>) — zkrácené pro čitelnost; např. (#660f9511) |
| Description | Za pomlčkou —; description zkrácena na 100 znaků (trim + přidání … pokud delší) |
| Oddělovač | — (mezera, pomlčka em-dash, mezera) |
| Summary řádek | > _and more than 20 more open issues_ na konci sekce pokud issues > 20 (N+1 trick — přesné číslo se nevypisuje, žádný COUNT(*)) |
Příklad — plná sekce (2 issues)
# Open TODO issues
- [BUG] SQL query vrací duplicitní řádky při JOIN bez DISTINCT (#660f9511) — Metoda UserRepository.findActiveUsers() vrací duplicitní záznamy kvůli chybějícímu DISTINCT v…
- [FEATURE] Exportní funkce pro CSV (#771a0022) — Uživatelé potřebují exportovat data do CSV formátu pro zpracování v Excelu. Priorita: střední.
Příklad — truncated sekce (víc než 20 issues)
# Open TODO issues
- [BUG] Issue 1 (#aaaaaaaa) — popis…
- [BUG] Issue 2 (#bbbbbbbb) — popis…
[… dalších 18 issues …]
- [FEATURE] Issue 20 (#tttttttt) — popis…
> _and more than 20 more open issues_
Příklad — empty case (žádné OPEN/IN_PROGRESS issues)
CLAUDE.md sekce # Open TODO issues chybí úplně — žádný placeholder, žádný prázdný nadpis.
Implementační detail
Dotaz
// IssueRepository
fun findByProjectIdAndStatusInOrderByReportedAtAscIdAsc(
projectId: UUID,
statuses: List<IssueStatus>
): List<Issue>
SQL ekvivalent:
SELECT * FROM issues
WHERE project_id = :projectId
AND tenant_id = :tenantId
AND status IN ('OPEN', 'IN_PROGRESS')
ORDER BY reported_at ASC, id ASC
LIMIT 21
N+1 trick: BE fetchuje LIMIT 21. Pokud výsledek obsahuje 21 záznamů, víme že issues je více než 20 — renderuje prvních 20 + summary řádek > _and more than 20 more open issues_. Přesné číslo se nevypisuje, žádný separátní COUNT(*) query — cílem je minimalizovat load při každé Mara konverzaci.
Deterministické řazení pro prompt cache
Řazení reported_at ASC, id ASC:
reported_at ASC— nejstarší issues první (stabilní pořadí mezi requesty)id ASC(UUID) — tiebreaker pro issues vytvořené ve stejnou sekundu (UUID je časově sekvenční z HibernateUUIDGenerator)
Jakákoliv jiná řadící logika (random, reported_at DESC, bez tiebreakeru) by způsobovala nedeterministické pořadí → invalidaci Anthropic prompt cache → zbytečné náklady na tokenech.
Kde se volá MaraContextRenderer
| UseCase | Kdy se volá |
|---|---|
StartConversationUseCase | Nová konverzace nad projektem — CLAUDE.md se sestavuje od nuly |
AutoStartConversationUseCase | Automaticky spuštěná konverzace (batch operace) — stejné sestavení |
SendMessageUseCase | Pokračování existující konverzace — CLAUDE.md se předává jako system context při každém volání |
Renderer je stateless — pokaždé fetchuje aktuální stav issues z DB. Issues vyřešené mezi session spuštěním a dalším SendMessage se tedy projeví okamžitě v dalším volání (fresh fetch).
Backend
Test Cases
| GIVEN | WHEN | THEN |
|---|---|---|
| Projekt má 2 OPEN a 1 IN_PROGRESS issue | MaraContextRenderer.renderClaudeMd(projectId, ...) | CLAUDE.md obsahuje sekci # Open TODO issues se 3 záznamy, řazeno reported_at ASC, id ASC |
| Projekt nemá žádné OPEN ani IN_PROGRESS issues | MaraContextRenderer.renderClaudeMd(projectId, ...) | CLAUDE.md neobsahuje sekci # Open TODO issues vůbec |
| Projekt má 25 OPEN issues (repository vrátí 21 řádků — N+1 trigger) | MaraContextRenderer.renderClaudeMd(projectId, ...) | CLAUDE.md obsahuje sekci s 20 záznamy + summary řádek > _and more than 20 more open issues_; žádný COUNT(*) query |
Issue má description delší než 100 znaků | MaraContextRenderer.renderClaudeMd(projectId, ...) | Description je zkrácena na 100 znaků s … |
| Projekt má RESOLVED a WONTFIX issues (žádné OPEN/IN_PROGRESS) | MaraContextRenderer.renderClaudeMd(projectId, ...) | Sekce # Open TODO issues chybí; RESOLVED/WONTFIX se nezobrazují |
Dvě issues mají identické reported_at | MaraContextRenderer.renderClaudeMd(projectId, ...) | Pořadí je deterministické dle id ASC; opakované volání vrací stejné pořadí |
| Issues jsou ve stejném projektu, různé tenanty (cross-tenant data v DB) | MaraContextRenderer.renderClaudeMd(projectId, tenantId) | Vráceny pouze issues s tenant_id = tenantId; cross-tenant issues ignorovány |
References
- UC-09005 Report Project Issue — jak PROJECT issues vznikají
- UC-09006 View Project Issues — manuální prohlížení PROJECT issues ve FE
FEEDBACK
UC je netypický — nemá REST endpoint, jde o čistě interní BE chování. Dokumentační formát byl přizpůsoben (bez FE sekce, bez API contract bloku). Ambiguita summary řádku byla vyřešena: používá se N+1 trick (LIMIT 21), summary zní > _and more than 20 more open issues_ bez přesného čísla — žádný COUNT(*) query navíc. Cílem je minimalizovat DB load při každém SendMessage volání.
Thanks for the feedback.