Reply Pilot Web App

Tato stranka popisuje modul reply-pilot-app/, ktery po rozdeleni architektury funguje primarne jako frontend/BFF vrstva nad reply-pilot-be.

UX/UI pravidla pro obrazovky, nadpisy, formulare a navigaci jsou v UX/UI Principles.

Co je soucasti

  • Flask aplikace v balicku reply_pilot_app/
  • HTTP klient pro reply-pilot-be
  • dashboard s kalendarem, filtry a draft formularem
  • search stranka nad party/activity fulltextem
  • signpost prehledy pro firmy, osoby, emaily a tasky
  • backend-backed formulare pro firmy, osoby, kontakty, identifikace, requirement review a task workflow mutace
  • sprava typed AI promptu pro email reply, import wizard a supplier onboarding workflow
  • GET /healthz pro monitoring
  • Docker image a Compose runtime s non-root uzivatelem

Runtime

  • aplikace bezi v kontejneru jako non-root uzivatel
  • runtime UID:GID se do Compose predava pres HOST_UID a HOST_GID
  • lokalni mounty jsou data -> /app/data, reply-pilot-app/conf -> /app/conf
  • aplikace se na backend napojuje pres sdilenou Docker sit reply-pilot-internal
  • hlavni runtime zavislost je BACKEND_API_BASE_URL, defaultne http://reply-pilot-be:5000
  • footer pouzije DOCUMENTATION_URL jako explicitni override; bez nej na localhost a 127.0.0.1 odkazuje na lokalni docs :9095, jinak na https://reply-pilot-docs.mathbox.90.cz
  • fulltext vola pres BACKEND_API_BASE_URL; backend dale vola reply-pilot-search
  • mount conf/ zustava read-only
  • logy jdou vyhradne na stdout/stderr; lokalne pouzij docker compose logs
  • image modulu se jmenuje reply-pilot-app:latest
  • operacni skripty jsou app-start.sh, app-stop.sh, app-deploy.sh

Konfigurace

Hlavni konfigurace je pres promenne prostredi:

  • APP_PORT
  • BACKEND_API_BASE_URL
  • BACKEND_TIMEOUT_SECONDS
  • DOCUMENTATION_URL
  • APP_INTERNAL_EMAIL_DOMAINS
  • APP_DATA_DIR
  • HOST_HTTP_PORT
  • APP_TIMEZONE
  • FLASK_SECRET_KEY
  • LOG_LEVEL
  • MAX_EMAILS
  • HOST_UID
  • HOST_GID

Zdroj dat

Ve standardnim runtime si appka taha inbox, detail threadu, sync i draft akce z reply-pilot-be.

Manualni vytvoreni tasku z e-mailoveho vlakna zustava z pohledu UI stejne: formular, vyber firmy, vyber assignee a AI draft pripravuje appka. Pokud je nastavene BACKEND_API_BASE_URL, samotne zalozeni Email Thread Reply tasku probiha pres backend endpoint POST /api/email-threads/<email_id>/reply-tasks. Backend pak vytvori Jira issue i lokalni task_jira_email_thread_reply vazbu a pri duplicate odpovedi vraci existujici task, na ktery appka presmeruje.

Delegovane Reply Pilot Task tasky appka zobrazuje ve stejnem prehledu a detailu jako ostatni Jira tasky. Detail ukazuje navazanou spolecnost, Jira description a read-only Jira komentare. Prirazeny uzivatel muze otevrit jednopolozkovou stranku Vyresit; appka pak vola backend mutaci, ktera ulozi text do Jira description a vrati task zadavateli. Po vraceni tasku zadavatel vidi na detailu POST akci Uzavrit, ktera vola backend close mutaci. Detail firmy ma sekci Obecné tickety pro Reply Pilot Task a akci Přidat úkol; zalozeni pres formular vola backend endpoint POST /api/companies/<party_id>/reply-pilot-tasks.

Rucni zalozeni firmy probiha z odkazu Nova spolecnost na rozcestniku. Appka zobrazi jednopage formular pro samotnou spolecnost a pri ulozeni vola backend endpoint POST /api/companies. Povinne jsou Pravni nazev a ICO; obchodni nazev je volitelny, web a role firmy se v tomto formulari nenastavuji. Appka do payloadu doplni aktualniho app uzivatele jako vychoziho obchodnika pro emailovou komunikaci a show_by_default=true; formular nema samostatnou volbu viditelnosti. Pri lokalni validaci se chyby ukazuji primo u konkretnich poli; pri duplicitach backend vraci jen kandidaty, ktere aktualni uzivatel smi videt, a appka zustava na formulari.

Fulltext si appka taha z reply-pilot-be endpointu /api/search. Backend nasledne vola reply-pilot-search, ktery vraci vysledky s linkem na detail firmy, osoby, emailu, obecne aktivity nebo Jira tasku. Task search pouziva stejny company scope jako ostatni read modely a navic umi aktivni delegovany Reply Pilot Task najit podle aktualniho assignee. Done delegovane tasky nevyuzivaji tuto aktivni assignee vyjimku, ale zustavaji dohledatelne pres normalni company scope nebo company.view_all.

Po prihlaseni appka zajisti app_user profil a do internich backend volani posila trusted header X-Reply-Pilot-App-User-Id. UI si z backendu nacita aktualni opravneni a podle nich skryva write/merge/admin akce. Backend zustava vynucovaci hranice; frontendove skryti akci je jen UX vrstva.

Stejnou backendem overenou identitu pouzivaji vsechny interaktivni Jira operace. App token nikdy necte ani neposila. Pokud backend vrati HTTP 428 s kodem jira_oauth_required, Jira formulare zachovaji zadane hodnoty a nabidnou existujici flow pro pripojeni Jira uctu v nove zalozce. Po novem consentu uzivatel puvodni operaci odesle znovu. Detailni hranice jsou v Jira OAuth 2.0 (3LO).

Pokud je zapnute SIMPLE_AUTH_ENABLED, app overuje callback a pouzite rp_nonce uklada pres backend nonce API. Replay protection tedy zustava durable, ale app uz kvuli nonce nepristupuje primo do DB.

Typed AI prompty uz appka spravuje pres reply-pilot-be endpointy /api/ai-prompt-types a /api/ai-prompts. Backend je uklada do tabulek public.ai_prompt_type a public.ai_prompt. Reply workflow filtruje typ EMAIL_REPLAY, lead import wizard filtruje typ IMPORT_WIZARD a Supplier Onboarding workflow filtruje typ SUPPLIER_ONBOARDING.

Lokalni cache fixture zustava jen kvuli testum. Mimo testy je BACKEND_API_BASE_URL povinne a prazdna hodnota zpusobi chybu startu appky.

  • BACKEND_API_BASE_URL nastavene -> app vola backend a sama nepracuje primo s Gmail/OpenAI
  • app modul nema runtime konfiguraci REPLY_PILOT_DB_*, nema zavislost na psycopg a nema produkcni DB-backed directory/record/task store fallback
  • APP_INTERNAL_EMAIL_DOMAINS nahrazuje drivejsi app-side Gmail mailbox config pro UI heuristiky, ktere potrebuji znat interni emailove domeny

Endpointy

  • / dashboard
  • /search fulltext nad emaily, party a activity modely
  • /companies/new rucni zalozeni firmy pres backend API
  • /companies/<party_id> detail firmy z party modelu
  • /companies/<party_id>/reply-pilot-tasks/create zalozeni obecneho Reply Pilot Task pro firmu
  • /companies/<party_id>/notes/new pridani poznamky k firme
  • /companies/<party_id>/contacts/new pridani kontaktu firmy pres backend API
  • /companies/<party_id>/contacts/<contact_mech_id>/edit uprava vazby kontaktu firmy
  • /companies/<party_id>/contacts/<contact_mech_id>/remove potvrzeni odebrani kontaktu firmy
  • /companies/<party_id>/identifiers/new pridani identifikace firmy
  • /companies/<party_id>/identifiers/<identifier_id>/remove potvrzeni odebrani identifikace firmy
  • /companies/<company_id>/people/<person_id>/remove potvrzeni odebrani vazby osoby na firmu
  • /people/new rucni zalozeni osoby, volitelne s company_id
  • /people/<party_id> detail osoby z party modelu
  • /people/<party_id>/notes/new pridani poznamky k osobe
  • /people/<party_id>/edit editace identity osoby
  • /people/<party_id>/contacts/new pridani kontaktu osoby
  • /people/<party_id>/contacts/<contact_mech_id>/edit uprava vazby kontaktu osoby
  • /people/<party_id>/contacts/<contact_mech_id>/remove potvrzeni odebrani kontaktu osoby
  • /emails/<activity_id> detail emailu z activity modelu
  • /activities/<activity_id> detail ne-emailove a ne-poznamkove aktivity
  • /tasks prehled JIRA tasku
  • /tasks/<task_id> detail tasku s navazanymi emailovymi vlakny
  • /tasks/<task_id>/reply-pilot-task/resolve vyreseni delegovaneho Reply Pilot Task s jednim textovym polem
  • /tasks/<task_id>/reply-pilot-task/close POST akce pro uzavreni delegovaneho Reply Pilot Task
  • /reassignment prehled firem pro prerazovani ticketu; filtr default_email_sales_user omezi seznam firem podle vychoziho obchodnika pro emailovou komunikaci nebo hodnoty unset
  • /settings/roles jednoducha sprava prirazeni jedne system role uzivateli; route vyzaduje security.manage_roles
  • /ai-prompty CRUD sprava typed promptu s filtrem podle workflow typu
  • /api/emails JSON vystup pro dalsi integrace
  • /healthz health endpoint
  • /drafts placeholder POST endpoint pro dalsi navazujici logiku

Party CRUD UI

Detail firmy je pracovni prehled se sekcemi Identita, Identifikace, Kontakty firmy, Osoby, Poznamky a E-mailova vlakna. Editovatelne sekce maji radkove akce, ale samotne formulare jsou samostatne stranky ve stylu CTA form. Odkaz Pridat poznamku vede na samostatny formular s jednim povinnym textarea polem a po ulozeni presmeruje zpet na detail firmy.

Detail osoby pouziva stejne objektove schema jako firma: H1 je jmeno osoby a H2 je Osoba - Prehled, Osoba - Aktivity nebo Osoba - Editovat. Prehled osoby obsahuje Identita, Kontakty osoby, Spolecnosti a Poznamky. Odkaz Pridat poznamku pouziva stejny formular jako firma a po ulozeni presmeruje zpet na detail osoby. Prehledove sekce Poznamky ukazuji jen poznamky pripojene primo k zobrazene party.

Aktivity osoby i firmy pouzivaji timeline layout. Timeline firmy bez kontaktniho filtru zobrazuje i poznamky aktivne navazanych osob jako zdedene radky s metadatem Z osoby a odkazem na danou osobu. Poznamkove radky v timeline zobrazuji i Poridil <uzivatel>, pokud backend vratil autora. Timeline filtrovana na konkretni e-mailovou adresu tyto zdedene osobni poznamky nezobrazuje.

Appka nove mutace osob, kontaktu, identifikaci a vazeb neposila primo do DB, ale vola backend REST API. Po uspesne mutaci presmeruje zpet na relevantni detail. Odebrani kontaktu, identifikace nebo vazby osoby na firmu vzdy vede pres potvrzovaci stranku; GET nic nemeni.