Reply Pilot Backend

Tato stranka popisuje modul reply-pilot-be/.

Role modulu

  • vlastni JSON API pro inbox a komunikacni workflow
  • vlastni app-facing inbox/read orchestration a DB materializaci emailu
  • vola reply-pilot-gmail pro Gmail sync, cache reads, attachment bytes, drafty a send
  • pri zobrazeni inboxu/detailu threadu udrzuje komunikacni historii v reply-pilot-db
  • vlastni OpenAI debug/generation flow pro reply-pilot-app
  • vlastni typed AI prompt CRUD API pro reply-pilot-app
  • vlastni reply draft, app user profile, app configuration a Jira assignee mapping API
  • vlastni simple-auth nonce persistence API pro replay protection app callbacku
  • vlastni read-model API pro firmy, osoby, kontakty, aktivity, emaily a tasky
  • vlastni company/task mutace vcetne navazanych Jira operaci
  • vlastni app-facing search API a vola reply-pilot-search
  • vlastni server-side lead import workflow pro JSONL batch soubory
  • je verejna backendova orchestrace e-mailove vrstvy; Gmail API a mailbox cache fyzicky vlastni reply-pilot-gmail

Java Backend Contract

Stav k 2026-06-13:

  • reply-pilot-be je Java 21 Spring Boot/Maven REST/JSON aplikace.
  • Legacy Python/Flask backend package, Python backend tests, Python-only dependencies and obsolete backend Python utilities were removed.
  • Backend contract is now maintained in Java controllers, Java services and Maven/JUnit 5 tests under reply-pilot-be/src/test/java.

Endpointove rodiny pokryte backend kontrolery:

Oblast Endpointy Java stav
Health/meta/Jira meta 3 ported
Search proxy 1 ported
AI prompt CRUD 6 ported
Reply draft storage 5 ported
User profile/app config/Jira assignee storage 9 ported
Simple-auth nonce API 2 ported
Jira proxy + task sync 14 ported
Company/person/activity/contact/task read models 19 ported
Company/person/contact/identifier/task mutations 25 ported
AI draft/debug generation 3 ported
Lead import 6 ported
Inbox/email/attachment read 5 ported
Mailbox watch/import 9 ported
Worker job endpoints 5 ported
Email draft/send 4 ported

Route-shape notes:

  • Java ReadModelController pouziva jednu catch-all route GET /api/email-threads/{*threadPath} a uvnitr ji dispatchuje na /companies, /requirements a /task, aby zustaly podporovane slash-capable thread IDs.
  • Requirement review route pouziva jeden path segment. Aktualni requirement kody jsou jednosegmentove hodnoty (ENLISTMENT_TABLE, FEED, SUPPLIER_IDENTIFIER), takze aktualni kontrakt je pokryty; slash-containing requirement kody nejsou podporovany ani dokumentovane.

Authorization notes:

  • Business read/write endpointy pouzivaji trusted internal header X-Reply-Pilot-App-User-Id, ktery posila reply-pilot-app po vyreseni nebo zalozeni app_user.
  • Backend autorizuje jen podle app_user.id a efektivnich opravneni z app_user_role -> app_role_permission; emaily a display names nejsou autorizacni identita.
  • Company read scope je enforced v backend read modelu i search proxy. company.view_all vidi vsechny firmy, company.view_assigned vidi jen firmy, kde party_organization.default_email_sales_user_id = app_user.id. Mimo delegovanou task vyjimku backend bez techto opravneni nevraci zadne firmy.
  • Backend read-model company/task endpointy navic udeluji uzkou read-only vyjimku pro delegovane Reply Pilot Task: aktualni Jira assignee aktivniho tasku muze nacist jen firmu navazanou na tento aktivni task a samotny aktivni task. Vyjimka neplati pro neprirazene delegovane tasky, Done tasky, nesouvisejici firmy ani zapisove mutace.
  • Search proxy nepouziva samostatne task.* opravneni. Reuseuje zakladni company scope a posila search modulu efektivni app_user_id: company.view_all vidi vsechny indexovane tasky, company.view_assigned vidi tasky podle vlastnika firmy a aktivni delegovane Reply Pilot Task prirazene aktualnimu uzivateli. Uzivatel bez company view opravneni nedostane zadne search vysledky. Done delegovane tasky se ve fulltextu nehledi jako aktivni delegated-assignee vyjimka, ale zustavaji dohledatelne pres normalni company scope nebo company.view_all; defaultni task prehled je skryva oddelene.
  • Company/task mutace navazane na existujici firmu vyzaduji company.write nebo company.write_assigned a zaroven stejny company visibility scope. Bezne sales role proto muze zapisovat jen prirazene firmy a jejich tasky, ne vsechny firmy. Zalozeni nove firmy zustava globalni operace vyzadujici company.write.
  • Delegovane Reply Pilot Task mutace nepouzivaji obecne company write opravneni. POST /api/tasks/{taskId}/reply-pilot-task/resolve smi zavolat jen aktualni cached Jira assignee aktivniho delegated tasku; backend prida zadany text do Jira description, priradi Jira task na lokalne ulozeneho zadavatele a ponecha stav In Progress. POST /api/tasks/{taskId}/reply-pilot-task/close smi zavolat jen lokalne ulozeny zadavatel; backend presune Jira task do Done a assignee nemeni.

Endpoint parity caveats:

  • Worker job endpointy jsou v Jave portovane jako REST orchestrace a typovane porty. Java ma konkretni JDBC worker bean pro CME company sync, AI requirement klasifikaci, requirement agregaci, requirement monitoring/report a historicky requirement backfill.
  • Java mailbox/send/lead-import aktivita ma produkcni JDBC ActivityEmailImportRepository pro zakladni activity, activity_email, activity_participant, activity_email_attachment a activity_email_link persistenci. Ten samy importer zapisuje i deterministicke party_feed_fact, party_supplier_identifier_fact, party_requirement_evidence a party_requirement_eval_queue radky pro incoming emaily a preklapi uz navazane email_thread_reply Jira tasky do Drafting Reply pri nove prichozi externi odpovedi. Pro nenavazane incoming odpovedi s jednoznacne vyresenou dodavatelskou firmou Java po uspesnem commit importu zaklada automaticky Email Thread Reply task pres stejnou prioritu vychoziho assignee jako zbytek backend kontraktu.
  • Java lead-import outbound email aktivita se zapisuje pres caller-owned JDBC connection uvnitr stejne DB transakce jako update lead-import itemu. Externi Gmail send a Jira issue operace zustavaji mimo DB rollback hranici, protoze jde o externi systemove side efekty.

Runtime

  • bezi jako samostatny Java 21 Spring Boot kontejner
  • zapisuje do reply-pilot-be/data a reply-pilot-be/logs
  • conf/ zustava read-only mount
  • na interni siti se hlasi jako reply-pilot-be
  • reply-pilot-app a reply-pilot-worker ho volaji pres http://reply-pilot-be:5000
  • Gmail sluzbu vola pres GMAIL_API_BASE_URL, defaultne http://reply-pilot-gmail:5000; to je interni URL modulu reply-pilot-gmail, ne Google Gmail API endpoint
  • v EMAIL_SYNC_BACKEND=gmail_service modu necte ani nezapisuje reply-pilot-be/data/emails; inbox cache, cursory a attachment bytes cte pres HTTP z Gmail modulu
  • nedrzi Gmail OAuth token, Gmail mailbox cache, mailbox/query konfiguraci ani Pub/Sub credentials
  • Search sluzbu vola pres SEARCH_API_BASE_URL, defaultne http://reply-pilot-search:5000
  • PostgreSQL vola pres reply-pilot-db na interni siti

Email Artifact Flow

Import emailu probiha ve trech vrstvach:

  1. reply-pilot-be spusti sync/detail/attachment operaci pres reply-pilot-gmail HTTP API. Gmail modul vola Google Gmail API a zapisuje fyzickou cache do reply-pilot-gmail/data/accounts/<GMAIL_CACHE_ACCOUNT_ID>/emails/.
  2. BE cte snapshoty, detail, attachment metadata a attachment bytes pres interni HTTP cache endpointy Gmail modulu. relative_path zustava logicka hodnota ve tvaru emails/attachments/<thread>/<file>, ne host filesystem cesta.
  3. Activity import zapise do PostgreSQL:
  4. activity + activity_email
  5. activity_email_attachment jako DB metadata nad Gmail-owned cache
  6. activity_email_link jako explicitni URL nalezene v body_text
  7. Pozdejsi attachment phase muze pres Gmail modul dotahnout chybejici binarky; backend pak znovu synchronizuje activity_email_attachment, aby DB metadata odpovidala aktualni Gmail-owned cache.

Dulezite pravidlo:

  • PostgreSQL je source of truth pro attachment metadata a pro nalezene URL
  • binarni obsah priloh zustava v Gmail module cache a BE ho pro klienty proxyuje pres HTTP
  • vazba z DB na cache vede pres activity_email_attachment.relative_path; hodnota je kompatibilni logicky path, ne dukaz vlastnictvi filesystemu v BE
  • odeslane e-maily se po uspesnem Gmail send materializuji stejnou ActivityImportStore cestou jako importovane zpravy; lead import wizard pri akci odeslat+a importovat posila e-mail v backendu, aby se pred zapisem activity_email nejdriv zalozila firma a kontaktni vazby

Lead Import Runtime

Lead import flow cte serverove JSONL soubory z backend storage, typicky pod reply-pilot-be/data/lead-imports/:

  • inbox/ ceka na operatora
  • processing/ drzi soubor navazany na aktivni review batch
  • done/ drzi dokoncene batch soubory
  • failed/ drzi soubory, ktere nesly nacist nebo zalozit do DB

Backend:

  • vypise dostupne soubory pro web app
  • ze zvoleneho souboru zalozi lead_import_batch a lead_import_item
  • pri otevreni detailu polozky umi vygenerovat AI draft prvniho osloveni
  • pri operatorove akci umi zalozit nebo doplnit firmu, odeslat prvni osloveni, ulozit odeslany e-mail do kontaktni historie, ulozit activity_note, propsat party_outreach_policy a vytvorit Jira task

Simple Auth Nonce API

Backend exposeuje male JSON API pro durable replay protection app login callbacku:

  • POST /api/simple-auth/nonces/check
  • POST /api/simple-auth/nonces/mark-used

Backend uklada nonce do existujici tabulky public.simple_auth_nonce. reply-pilot-app tedy pri simple-auth callbacku necte ani nezapisuje nonce primo do DB.

Manual Company Create

Backend exposeuje POST /api/companies pro rucni zalozeni firmy z web appky. Endpoint v jedne transakci zalozi pouze organizaci nad existujicim party modelem. Kontakty, osoby, poznamky, outreach policy ani Jira tasky nejsou soucasti tohoto V1 formulare.

V1 request obsahuje:

  • company: display_name, legal_name, company_registration_number, tax_identifier, show_by_default, default_email_sales_user_id

legal_name a company_registration_number jsou povinne. display_name je volitelny obchodni nazev; kdyz chybi, backend pouzije pravni nazev jako display nazev. Web appka neposila website ani roles; backend stare payload fieldy porad toleruje kvuli kompatibilite. Web appka rucniho zalozeni posila show_by_default=true, protoze formular uz neobsahuje samostatnou volbu viditelnosti.

Backend ignoruje klientem poslanou hodnotu default_email_sales_user_id jako zdroj pravdy a uklada efektivniho uzivatele z X-Reply-Pilot-App-User-Id. Zalozena firma je tedy hned viditelna pro uzivatele se scoped opravnenim company.write_assigned.

Pred insertem backend kontroluje duplicity podle presneho ICO, DIC, normalizovaneho pravniho nazvu a DOMAIN/WEBSITE identifikatoru. Pri nalezu vraci 409 a zadny zaznam neuklada. Kandidaty v odpovedi filtruje podle company visibility scope aktualniho uzivatele; pokud duplicita existuje, ale uzivatel ji nesmi videt, odpoved neobsahuje zadne detaily o firme.

Email Thread Reply Tasky

Backend vlastni vytvareni Jira tasku typu Email Thread Reply.

  • UI vola POST /api/email-threads/<email_id>/reply-tasks s party_id, assignee_user_id, summary a description.
  • Backend nacita e-mailove vlakno ze sve e-mail sluzby, kontroluje duplicitu pres task_jira_email_thread_reply.external_thread_id, vytvari Jira issue typu JIRA_DEFAULT_ISSUE_TYPE_REPLY_EMAIL a uklada existujici lokalni tabulky task, task_jira a task_jira_email_thread_reply.
  • Do Jira description doplnuje link na detail firmy a po lokalnim ulozeni i link na detail tasku podle APP_PUBLIC_BASE_URL.
  • Lokalni task_jira.jira_summary a task_jira.jira_description_text cache se aktualizuje hned pri vytvoreni/editaci tasku; pravidelny Jira task sync pak cache dorovnava podle Jiry.
  • Pri duplicitnim threadu endpoint vraci 409 a metadata existujiciho tasku, aby app mohla presmerovat na jiz zalozeny task.

Activity import pri nove prichozi zprave od externiho dodavatele nejdriv preklopi existujici reply task pro stejne vlakno do stavu Drafting Reply. Kdyz pro thread reply task jeste neni a importer jednoznacne vyresi dodavatelskou firmu, backend zalozi novy Email Thread Reply a novy Jira ticket take prevede do Drafting Reply.

Odeslani odpovedi nebo preposlani z existujiciho emailoveho vlakna nevytvari novy reply task. Backend posila email v kontextu puvodniho vlakna a existujici navazany Email Thread Reply task presune do Waiting for Reply, pokud uz v tomto stavu neni.

Vychozi assignee pro automaticky reply task se bere v tomto poradi:

  • party_organization.default_email_sales_user_id
  • app_configuration.default_email_sales_user_id
  • DEFAULT_EMAIL_THREAD_REPLY_ASSIGNEE_JIRA_ACCOUNT_ID
  • DEFAULT_EMAIL_THREAD_REPLY_ASSIGNEE_EMAIL
  • bez assignee, pokud zadny zdroj nedal dohledatelny Jira account

Java migration toto chovani portuje v JdbcActivityEmailImportRepository/TaskMutationService. Automaticke vytvareni bezi az po uspesnem commit email importu, aby Java task service videla i novou firmu zalozenou importem.

AI Evidence Output Contract

Pro budouci AI klasifikaci requirement evidence jsou source of truth tyto JSON schema soubory:

  • reply-pilot-be/default-conf/ai-schemas/enlistment-table.schema.json
  • reply-pilot-be/default-conf/ai-schemas/feed.schema.json
  • reply-pilot-be/default-conf/ai-schemas/supplier-identifier.schema.json

Spolecna pravidla:

  • vsechny vystupy musi projit validaci proti schema pred zapisem do DB
  • additionalProperties jsou vsude zakazane, aby backend nemusel resit tichy drift
  • evidence_key a fact_key musi byt unikatni v ramci jedne AI odpovedi
  • confidence je vzdy 0..1
  • model_name, model_version a prompt_version se neberou z AI payloadu; doplnuje je backend pri zapisu
  • extract_json ma ukladat validovany fragment, ktery vedl ke vzniku konkretniho DB radku, ne jen volny textovy summary

AI Classification Runtime

reply-pilot-be exposeuje worker endpoint POST /api/requirements/ai-classify/run. Tenhle job:

  • vybira jen emaily, ktere uz prosly deterministic prefiltrem
  • scope ENLISTMENT_TABLE bere z party_requirement_evidence s created_by = deterministic-enlistment-detector
  • scope FEED bere z party_feed_fact s created_by = deterministic-email-parser
  • scope SUPPLIER_IDENTIFIER bere z party_supplier_identifier_fact s created_by = deterministic-email-parser
  • AI job znovu nepousti kandidaty, ktere uz maji AI materializovane radky s created_by = ai-requirement-classifier
  • pri chybe jedne AI klasifikace backend zaloguje chybu, preskoci konkretni email a pokracuje dalsim kandidatem

Structured output validace:

  • backend posila do OpenAI commitnute JSON schema z default-conf/ai-schemas/
  • OpenAI schema drzi jen subset kompatibilni s Responses API; podminena pravidla typu EMAIL_ATTACHMENT => attachment_* povinne nebo DIRECT_URL => url_* povinne hlida nasledna backend validace
  • po odpovedi dela vlastni strict validaci fixnich payload shape pravidel, bez runtime dependency na externi jsonschema knihovne
  • az po uspesne validaci zapisuje DB evidence/facts

Requirement Aggregation Runtime

reply-pilot-be exposeuje i worker endpoint POST /api/requirements/evaluate/run. Tenhle job:

  • cte party_requirement_eval_queue
  • claimuje pending polozky pres FOR UPDATE SKIP LOCKED
  • pro ENLISTMENT_TABLE agreguje historicke party_requirement_evidence
  • pro FEED agreguje historicke party_requirement_evidence a party_feed_fact
  • pro SUPPLIER_IDENTIFIER agreguje historicke party_supplier_identifier_fact
  • vysledek zapisuje do party_requirement_state
  • pro FEED propaguje i finalni resolved_delivery_mode_code a feed_url
  • pro SUPPLIER_IDENTIFIER propaguje resolved_value_type_code a hodnotu
  • pri manualnim override radek v party_requirement_state neprepisuje
  • pri chybe jedne queue polozky ji jen odlozi na pozdeji a zpracovani dalsich firem pokracuje
  • kdyz se zmeni REQUIREMENT_AGGREGATION_RULESET_VERSION, backend jednorazove znovu zaqueueuje vsechny firmy do party_requirement_eval_queue

Java Spring Boot backend ma pro tenhle runtime konkretni JdbcRequirementAggregationWorker bean. Historicky backfill ma vlastni konkretni JdbcRequirementBackfillWorker bean.

Historical Requirement Backfill

Pro jednorazovy nebo strankovany backfill historickych threadu exposeuje backend endpoint POST /api/requirements/backfill/run.

Tenhle job:

  • umi zpracovat jednu firmu pres party_id nebo strankovanou davku pres after_party_id + limit
  • nejdriv znovu synchronizuje deterministic email artifacts a extracted facts nad historickymi thready dane firmy
  • preferuje thread snapshot pres EmailCacheRepository; v gmail_service modu jde o Gmail-module HTTP cache, a kdyz snapshot chybi, spadne na DB-only fallback nad activity_email a activity_email_attachment
  • AI klasifikaci i requirement agregaci pousti jen nad vybranou sadou firem, ne globalne nad celou frontou
  • je idempotentni, protoze deterministic vrstvy delaji replace svych radku a agregace bezi pres existujici queue/upsert model
  • vraci operativni report poctu firem, threadu, synchronizovanych zprav, AI kandidatu a prepoctenych atributu

AI prompt refresh:

  • AI candidate scan bere v uvahu aktualni REQUIREMENT_AI_PROMPT_VERSION
  • pokud pro email existuji jen starsi AI radky s jinou prompt verzi, backend je povazuje za stale a zaradi email znovu do AI klasifikace

ENLISTMENT_TABLE

Schema:

  • top-level summary
  • pole evidence_items
  • kazdy evidence_item reprezentuje jeden kandidátní dukaz

Mapovani do DB:

  • pro kazdy evidence_item vytvor jeden radek v party_requirement_evidence
  • requirement_code = 'ENLISTMENT_TABLE'
  • source_type_code, verdict_code, confidence, reason se berou primo z itemu
  • activity_email_id a external_thread_id doplni backend z aktualniho importovaneho emailu
  • pokud je source_type_code = 'EMAIL_ATTACHMENT', backend prenese attachment_filename, attachment_relative_path a volitelne attachment_sha256
  • pokud je source_type_code = 'EMAIL_MESSAGE', attachment sloupce zustanou prazdne
  • extract_json na evidence radku ma obsahovat presny evidence_item a volitelne i top-level summary
  • top-level summary se nezapisuje primo do party_requirement_state; slouzi jako vstup pro pozdejsi agregacni worker

FEED

Schema:

  • top-level summary
  • pole evidence_items
  • pole feed_facts
  • kazdy feed_fact odkazuje na jeden evidence_item pres evidence_key

Mapovani do DB:

  • evidence_items se materializuji do party_requirement_evidence
  • requirement_code = 'FEED'
  • backend si vytvori mapu evidence_key -> party_requirement_evidence.id
  • pro kazdy feed_fact vytvori jeden radek v party_feed_fact
  • evidence_id se naplni z evidence_key; kdyz reference chybi nebo ukazuje na neexistujici key, cely AI payload se ma povazovat za nevalidni
  • delivery_mode_code, url_raw, url_normalized, confidence, reason se berou primo z factu
  • pri delivery_mode_code DIRECT_URL nebo LOGIN_REQUIRED musi byt vyplnene url_raw i url_normalized
  • pri IDENTIFIER_ONLY, MANUAL_EXPORT, NO_FEED nebo OTHER mohou byt URL prazdne
  • attachment metadata se do party_feed_fact kopiruji z navazaneho evidence_item; kdyz je zdrojem EMAIL_MESSAGE, zustanou attachment sloupce prazdne
  • extract_json na fact radku ma obsahovat konkretni feed_fact; extract_json na evidence radku konkretni evidence_item

SUPPLIER_IDENTIFIER

Schema:

  • top-level summary
  • pole evidence_items
  • pole identifier_facts
  • kazdy identifier_fact odkazuje na jeden evidence_item pres evidence_key

Mapovani do DB:

  • v aktualnim schema V1 se SUPPLIER_IDENTIFIER nematerializuje do party_requirement_evidence, protoze requirement_type zatim nema odpovidajici kod
  • backend proto validuje evidence_items, ale do DB zapisuje jen party_supplier_identifier_fact
  • evidence_key slouzi jako interní most pro kopirovani source metadata z evidence_items do fact radku
  • identifier_type_code, value_raw, value_normalized, confidence, reason se berou primo z identifier_fact
  • evidence_id zustava NULL
  • attachment_filename, attachment_relative_path a attachment_sha256 se kopiruji z navazaneho evidence_item, pokud je zdroj attachment
  • extract_json na fact radku ma obsahovat konkretni identifier_fact a volitelne odkaz na pouzity evidence_item
  • pokud se pozdeji prida requirement_type pro identifikatory dodavatele, schema neni potreba menit; backend jen zacne evidence_items materializovat i do party_requirement_evidence

Endpointy

Zakladni stav:

  • GET /healthz
  • GET /api/meta
  • GET /api/jira/meta

App state a BFF storage:

  • GET /api/ai-prompt-types
  • GET/POST /api/ai-prompts
  • GET/PATCH/DELETE /api/ai-prompts/<prompt_id>
  • GET/POST /api/reply-drafts
  • GET/PATCH/DELETE /api/reply-drafts/<draft_id>
  • GET/POST /api/user-profiles
  • GET/PATCH /api/user-profiles/<login_key>
  • GET/PATCH /api/app-configuration
  • GET /api/jira/assignees
  • GET /api/jira/assignees/<app_user_id>/account-id
  • PUT /api/jira/assignees/<app_user_id>
  • POST /api/simple-auth/nonces/check
  • POST /api/simple-auth/nonces/mark-used

Read modely pro app obrazovky:

  • GET /api/companies
  • GET /api/companies/<party_id>
  • GET /api/companies/<party_id>/tasks
  • GET /api/people
  • GET /api/people/<party_id>
  • GET /api/activity-emails
  • GET /api/activity-emails/<activity_id>
  • GET /api/contact-methods/<contact_mech_id>
  • GET /api/parties/<party_id>/notes
  • GET /api/parties/<party_id>/activities
  • GET /api/activities/<activity_id>
  • GET /api/email-threads/<external_thread_id>/companies
  • GET /api/email-threads/<external_thread_id>/requirements
  • GET /api/email-threads/<external_thread_id>/task
  • GET /api/email-threads/tasks
  • GET /api/contact-emails/companies
  • POST /api/company-mentions
  • GET /api/tasks
  • GET /api/tasks/<task_id>

GET /api/companies podporuje filtr default_email_sales_user=<app_user_id|unset>. Hodnota unset vraci firmy bez nastaveneho vychoziho obchodnika pro emailovou komunikaci; prazdna nebo neplatna hodnota filtr neaplikuje.

Supplier Onboarding lze filtrovat pres supplier_onboarding_ticket=<with|without> a supplier_onboarding_status=<Jira status name>. Stav se vyhodnocuje pouze nad tasky s jira_work_type_code=supplier_onboarding; firma vyhovuje, pokud ma alespon jeden takovy task ve zvolenem stavu. Kombinace without a konkretniho stavu vraci prazdny vysledek.

Company, party a task mutace:

  • POST /api/companies
  • PATCH /api/companies/<party_id>
  • POST /api/companies/<target_party_id>/merge
  • POST /api/companies/<party_id>/visibility
  • POST /api/companies/<party_id>/requirements/<requirement_code>/review
  • POST /api/companies/<party_id>/supplier-onboarding-tasks
  • POST /api/companies/<party_id>/reply-pilot-tasks
  • POST /api/people
  • PATCH /api/people/<party_id>
  • POST /api/parties/<party_id>/contacts
  • PATCH /api/parties/<party_id>/contacts/<contact_mech_id>
  • DELETE /api/parties/<party_id>/contacts/<contact_mech_id>
  • POST /api/parties/<party_id>/notes
  • POST /api/companies/<party_id>/identifiers
  • DELETE /api/companies/<party_id>/identifiers/<identifier_id>
  • DELETE /api/companies/<company_id>/people/<person_id>
  • PATCH /api/tasks/<task_id>/company
  • POST /api/tasks/<task_id>/email-threads
  • PATCH /api/tasks/<task_id>/supplier-onboarding
  • PATCH /api/tasks/<task_id>/email-thread-reply
  • POST /api/tasks/<task_id>/refresh-from-jira
  • POST /api/tasks/<task_id>/supplier-onboarding/reply
  • POST /api/tasks/<task_id>/move-reply-to-waiting
  • POST /api/tasks/<task_id>/reply-pilot-task/resolve
  • POST /api/tasks/<task_id>/reply-pilot-task/close

Jira proxy a task drafty:

  • GET /api/jira/myself
  • GET /api/jira/users/by-email
  • GET /api/jira/issues/<issue_key>
  • PUT /api/jira/issues/<issue_key>
  • GET /api/jira/issues/<issue_key>/transitions
  • POST /api/jira/issues/<issue_key>/transition
  • GET/POST /api/jira/issues/<issue_key>/comments
  • POST /api/jira/issues/<issue_key>/unassign
  • GET /api/jira/issues/search
  • GET /api/jira/issues/assigned
  • GET /api/jira/issues/stale
  • POST /api/jira/issues
  • POST /api/jira/task-sync/run
  • POST /api/supplier-onboarding/draft
  • POST /api/email-thread-task/draft

Vsechny Jira proxy endpointy vyvolane prihlasenym uzivatelem vyzaduji trusted app-user kontext a pouzivaji jeho Jira OAuth 2.0 (3LO) bearer token pro cteni i zapis. Stejny actor-aware klient pouzivaji interaktivni task workflow, lead import a explicitni refresh tasku. Chybejici nebo nepouzitelny credential se vraci jako HTTP 428 s kodem jira_oauth_required; request se neopakuje s technickym uctem.

No-actor varianta Jira klienta je povolena jen pro periodicky Jira task sync, automaticke operace vyvolane prichozim e-mailem a samostatny Jira reports modul. Tyto procesy nemaji prihlaseneho lidskeho aktera a pouzivaji technicky ucet. Presny audit, scope pozadavky a consent flow jsou v Jira OAuth 2.0 (3LO).

Jira task sync pro lokalni task cache pouziva JQL omezeny na nakonfigurovany projekt a issue typy JIRA_DEFAULT_ISSUE_TYPE_SUPPLIER_ONBOARDING, JIRA_DEFAULT_ISSUE_TYPE_REPLY_EMAIL a JIRA_DEFAULT_ISSUE_TYPE_REPLY_PILOT_TASK. Do task_jira zapisuje status, work type, assignee mapping a plain-text jira_summary/jira_description_text. U delegovanych Reply Pilot Task issue nacita Jira dropdown JIRA_REPLY_PILOT_TASK_TYPE_CUSTOM_FIELD_ID a jeho hodnotu uklada do task_jira_reply_pilot_task.task_type_value. Vychozi task list nevraci Reply Pilot Task ve stavu Done, dokud request explicitne nefiltruje stav nebo Jira key. Pri zalozeni POST /api/companies/<party_id>/reply-pilot-tasks backend vytvori Jira issue type Reply Pilot Task, nastavi Jira dropdown taskType, do task_jira_reply_pilot_task ulozi requester app user id a lokalni task type hodnotu.

Email, Gmail mailbox a OpenAI debug:

  • GET /api/inbox
  • GET /api/emails
  • GET /api/emails/<email_id>
  • GET /api/emails/<email_id>/attachments
  • POST /api/email-threads/<email_id>/reply-tasks
  • GET /api/emails/<email_id>/attachments/<filename>
  • GET /api/mailbox/watch
  • POST /api/mailbox/watch/ensure
  • POST /api/mailbox/watch/stop
  • POST /api/mailbox/watch/notify
  • POST /api/mailbox/watch/pull
  • POST /api/mailbox/sync/full
  • POST /api/mailbox/sync/sent
  • POST /api/mailbox/import
  • GET /api/mailbox/import/status
  • POST /api/mailbox/import/step
  • POST /api/emails/drafts/outbound
  • POST /api/emails/<email_id>/drafts/reply
  • POST /api/emails/send/outbound
  • POST /api/emails/<email_id>/send/reply
  • POST /api/emails/<email_id>/send/forward
  • POST /api/emails/<email_id>/debug/generate

Lead import, CME a requirement joby:

  • POST /api/cme/company-sync/run
  • GET /api/lead-imports/files
  • POST /api/lead-imports/batches
  • GET /api/lead-imports/batches/<batch_id>
  • GET /api/lead-imports/batches/<batch_id>/items/<item_id>
  • POST /api/lead-imports/batches/<batch_id>/items/<item_id>/draft
  • POST /api/lead-imports/batches/<batch_id>/items/<item_id>/actions
  • POST /api/requirements/ai-classify/run
  • POST /api/requirements/evaluate/run
  • POST /api/requirements/backfill/run
  • GET /api/requirements/report

Reply draft/send a forward-send endpointy prijimaji puvodni JSON payload bez priloh. Pokud odpoved nebo forward obsahuje prilohy, klient posila multipart/form-data se stejnymi textovymi poli recipient, subject, body_text, reply_to_message_id, volitelnymi poli body_signature_html a body_signature_plain_text a opakovanym file polem attachments. Limit je 10 souboru, 10 MB na soubor a 20 MB celkem.

Party Mutation API

Backend exposeuje rucni mutace pro osoby, kontakty, identifikace a vazby nad existujicim party/contact modelem. Vsechny mutace bezi v jedne DB transakci a overuji, ze cilova party existuje, neni mergnuta a ma ocekavany typ.

  • POST /api/people zalozi osobu a volitelne ji navaze na firmu pres CONTACT_FOR.
  • PATCH /api/people/<party_id> upravi zakladni identitu osoby.
  • POST/PATCH/DELETE /api/parties/<party_id>/contacts... spravuje aktivni vazbu party na EMAIL nebo PHONE contact mechanism.
  • DELETE kontaktu nastavuje party_contact_mech.thru_date; contact_mech ani historie aktivit se nemazou.
  • POST /api/companies/<party_id>/identifiers podporuje WEBSITE, DOMAIN, GLN, VENDOR_CODE a EXTERNAL_ID; ICO/DIC zustavaji v editaci firmy.
  • DELETE /api/companies/<party_id>/identifiers/<identifier_id> maze party_identifier, protoze tabulka nema lifecycle sloupec.
  • DELETE /api/companies/<company_id>/people/<person_id> ukonci aktivni CONTACT_FOR vztah pres thru_date; osoba zustava zachovana.
  • POST /api/parties/<party_id>/notes prida add-only poznamku nad existujicim activity + activity_note modelem. Request obsahuje note_text a volitelne created_by_user_id; response vraci kompatibilni envelope se note.activity_id, note.party_id a prazdnym note.url_path, protoze poznamky nemaji samostatnou web detail stranku.
  • GET /api/parties/<party_id>/notes vraci pouze poznamky primo pripojene k dane party, ne poznamky zdedene z navazanych osob.
  • GET /api/parties/<party_id>/activities pro firmu bez contact_email filtru zahrnuje i poznamky osob, ktere maji v okamziku cteni aktivni CONTACT_FOR vztah k firme. Tyto radky maji inherited: true a source_party_id, source_party_type_code, source_party_label, source_url_path. Activity payload vraci i volitelne created_by_user_id a created_by_display_name, aby UI mohlo u poznamek zobrazit, kdo je poridil. Timeline filtrovana pres contact_email zdedene osobni poznamky nevraci.

Chyby vraci JSON se status: error a reason. Validacni chyby pouzivaji 400, konflikt duplicit 409 s volitelnymi candidates, chybejici zaznam 404 a nenakonfigurovana DB 503.