Files
crmPRO/.paul/phases/06-task-title-ai/06-01-PLAN.md
Codex 3b1ba1b5ed feat(06-task-title-ai): complete OpenAI task title suggestions
Phase 6 complete:

- add AI title generator service using gpt-5-nano

- add task popup button for biuro@project-pro.pl

- add AJAX endpoint returning title suggestions without auto-save
2026-05-04 23:45:54 +02:00

202 lines
8.1 KiB
Markdown

---
phase: 06-task-title-ai
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- config.php
- autoload/Domain/Tasks/TaskTitleGenerator.php
- autoload/controls/class.Tasks.php
- templates/tasks/task_popup.php
autonomous: false
delegation: off
---
<objective>
## Goal
Dodac w popupie edycji zadania przycisk generowania propozycji tytulu zadania przez OpenAI na podstawie tresci zadania.
## Purpose
Uzytkownik `biuro@project-pro.pl` ma szybciej nadawac czytelne tytuly zadaniom bez recznego streszczania opisu.
## Output
- Przycisk AI obok istniejacego przycisku edycji tytulu w `task_popup`.
- Osobny endpoint AJAX zwracajacy wygenerowana propozycje tytulu.
- Serwis domenowy do komunikacji z OpenAI, uzywajacy taniego i szybkiego modelu `gpt-5-nano`.
- Konfiguracja modelu tytulow niezalezna od importu maili.
</objective>
<context>
<clarifications>
- **[Widocznosc]** - Czy `biuro@project-pro.pl` oznacza zalogowanego uzytkownika czy zadania przypisane do tego uzytkownika?
-> Odpowiedz: tylko zalogowany uzytkownik z tym emailem widzi przycisk.
- **[Zapis]** - Czy AI ma od razu nadpisac tytul w bazie czy tylko wstawic propozycje do pola?
-> Odpowiedz: opcja A, wstawic propozycje do pola tytulu i zapisac dopiero istniejacym przyciskiem.
- **[Model]** - Czy uzyc `gpt-5-nano` jako tani/szybki model?
-> Odpowiedz: tak.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@config.php
@autoload/Domain/Tasks/MailToTaskImporter.php
@autoload/controls/class.Tasks.php
@templates/tasks/task_popup.php
@templates/tasks/main_view.php
## External References
- OpenAI model docs: https://developers.openai.com/api/docs/models/gpt-5-nano
- `gpt-5-nano` supports `v1/chat/completions` and is documented as the fastest/cheapest GPT-5 option for summarization/classification-style work.
</context>
<acceptance_criteria>
## AC-1: Przycisk widoczny tylko dla biuro
```gherkin
Given zalogowany uzytkownik ma email biuro@project-pro.pl
When otwiera popup zadania
Then obok przycisku edycji tytulu widzi przycisk generowania tytulu AI
```
## AC-2: Brak przycisku dla innych uzytkownikow
```gherkin
Given zalogowany uzytkownik ma inny email niz biuro@project-pro.pl
When otwiera popup zadania
Then przycisk generowania tytulu AI nie jest renderowany
And endpoint generowania odrzuca zadanie bez wywolania OpenAI
```
## AC-3: AI generuje propozycje bez zapisu do bazy
```gherkin
Given uzytkownik biuro@project-pro.pl otwiera popup zadania z trescia
When klika przycisk generowania tytulu AI
Then system pobiera tresc zadania i zwraca krotka propozycje tytulu
And propozycja trafia do pola edycji tytulu
And tytul w bazie nie zmienia sie przed kliknieciem istniejacego przycisku zapisu
```
## AC-4: Obsluga bledow OpenAI jest czytelna
```gherkin
Given brakuje klucza API OpenAI albo OpenAI zwroci blad
When uzytkownik klika generowanie tytulu
Then popup pokazuje czytelny komunikat bledu
And aktualny tytul zadania nie zostaje zmieniony
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Dodac serwis generowania tytulu przez OpenAI</name>
<files>config.php, autoload/Domain/Tasks/TaskTitleGenerator.php</files>
<action>
Dodac konfiguracje `openai_task_title_model` z domyslna wartoscia `gpt-5-nano`.
Utworzyc klase domenowa `Domain\Tasks\TaskTitleGenerator`, ktora:
- przyjmuje klucz API i model z konfiguracji,
- usuwa HTML z tresci zadania przed wyslaniem,
- wysyla krotki prompt do `https://api.openai.com/v1/chat/completions`,
- wymusza pojedynczy, krotki tytul bez JSON i bez dodatkowego komentarza,
- ogranicza dlugosc wejscia i wyjscia,
- zwraca tablice sukces/blad bez rzucania nieobslugiwanych wyjatkow.
Reuzyc wzorce z `MailToTaskImporter`, ale nie uzalezniac nowej funkcji od importera maili.
Dla modeli `gpt-5*` uzyc parametru `max_completion_tokens`; dla pozostalych zostawic kompatybilny fallback.
</action>
<verify>C:\xampp\php\php.exe -l autoload/Domain/Tasks/TaskTitleGenerator.php</verify>
<done>AC-3 i AC-4 maja pokrycie po stronie integracji OpenAI</done>
</task>
<task type="auto">
<name>Task 2: Dodac endpoint AJAX dla propozycji tytulu</name>
<files>autoload/controls/class.Tasks.php</files>
<action>
Dodac metode kontrolera np. `task_generate_title`, ktora:
- wymaga zalogowanego uzytkownika,
- sprawdza `strtolower($user['email']) === 'biuro@project-pro.pl'`,
- pobiera `task_id` jako int i odczytuje zadanie przez `factory\Tasks::task_details`,
- odrzuca brak zadania lub pusta tresc komunikatem JSON,
- wywoluje `TaskTitleGenerator`,
- zwraca JSON `{status: "success", title: "..."}` albo `{status: "error", msg: "..."}`.
Endpoint nie moze zapisywac `tasks.name`; zapis pozostaje w istniejacym `/tasks/task_change_title/`.
Uzyc medoo/prepared statements przez istniejace metody lub medoo API, bez skladania SQL.
</action>
<verify>C:\xampp\php\php.exe -l autoload/controls/class.Tasks.php</verify>
<done>AC-2, AC-3 i AC-4 spelnione po stronie backendu</done>
</task>
<task type="auto">
<name>Task 3: Dodac przycisk i obsluge UI w popupie zadania</name>
<files>templates/tasks/task_popup.php</files>
<action>
Rozszerzyc widok tytulu w popupie:
- wyrenderowac przycisk AI tylko gdy `$this->user['email']` to `biuro@project-pro.pl`,
- ustawic przycisk obok istniejacego przycisku edycji tytulu,
- po kliknieciu pokazac stan ladowania i wywolac `/tasks/task_generate_title/`,
- po sukcesie otworzyc inline edycje tytulu i wpisac propozycje do `.task-title-input`,
- nie klikac automatycznie `.task-title-save`,
- po bledzie pokazac komunikat i zostawic aktualny tytul bez zmian.
Zachowac istniejacy mechanizm recznej edycji i zapisu tytulu.
Escapowac dane w widoku; nie wprowadzac logiki OpenAI do widoku.
</action>
<verify>C:\xampp\php\php.exe -l templates/tasks/task_popup.php</verify>
<done>AC-1, AC-2 i AC-3 spelnione w UI</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>Przycisk AI w popupie zadania oraz generowanie propozycji tytulu do pola edycji.</what-built>
<how-to-verify>
1. Zaloguj sie jako `biuro@project-pro.pl`.
2. Otworz liste zadan i popup zadania z niepusta trescia.
3. Kliknij przycisk AI obok edycji tytulu.
4. Potwierdz, ze pole edycji tytulu wypelnia sie propozycja, ale tytul zapisuje sie dopiero po kliknieciu istniejacego przycisku zapisu.
5. Sprawdz u innego uzytkownika, ze przycisk nie jest widoczny.
</how-to-verify>
<resume-signal>Napisz "approved", jesli dziala, albo opisz blad do poprawy.</resume-signal>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- Nie zmieniac istniejacego endpointu `/tasks/task_change_title/` poza ewentualna minimalna walidacja, jesli bedzie konieczna.
- Nie zmieniac importu maili w `MailToTaskImporter`.
- Nie dodawac nowych bibliotek ani zaleznosci Composer.
- Nie zmieniac schematu bazy danych.
## SCOPE LIMITS
- Funkcja dotyczy tylko popupu zadania, nie pelnego formularza `task_edit`.
- AI generuje tylko propozycje tytulu; nie generuje ani nie zmienia tresci zadania.
- Przycisk jest dostepny tylko dla zalogowanego `biuro@project-pro.pl`.
- Brak automatycznego zapisu tytulu po generowaniu.
</boundaries>
<verification>
Before declaring plan complete:
- [ ] `C:\xampp\php\php.exe -l config.php`
- [ ] `C:\xampp\php\php.exe -l autoload/Domain/Tasks/TaskTitleGenerator.php`
- [ ] `C:\xampp\php\php.exe -l autoload/controls/class.Tasks.php`
- [ ] `C:\xampp\php\php.exe -l templates/tasks/task_popup.php`
- [ ] Reczna proba jako `biuro@project-pro.pl`: przycisk widoczny i generuje propozycje do pola.
- [ ] Reczna proba jako inny uzytkownik: przycisk niewidoczny, endpoint odrzuca dostep.
- [ ] Reczna proba potwierdza, ze baza zmienia tytul dopiero po istniejacym zapisie.
- [ ] Wszystkie AC spelnione.
</verification>
<success_criteria>
- `biuro@project-pro.pl` moze wygenerowac krotki tytul z tresci zadania w popupie.
- Wygenerowany tytul jest tylko propozycja w polu edycji, bez automatycznego zapisu.
- Inni uzytkownicy nie widza przycisku i nie moga uzyc endpointu.
- Bledy OpenAI nie psuja popupu i nie zmieniaja danych.
</success_criteria>
<output>
Po wykonaniu utworz `.paul/phases/06-task-title-ai/06-01-SUMMARY.md`.
</output>