Reply Pilot Database
reply-pilot-db je samostatny PostgreSQL modul pro Reply Pilot. Nevystavuje
REST/JSON API; vystavuje samotny PostgreSQL server na sdilene Docker siti
reply-pilot-internal a na host bind ${HOST_DB_BIND}:${HOST_DB_PORT}.
Co modul resi
- persistentni ulozeni databazovych souboru na host path mimo kontejner
- PostgreSQL konfiguraci pres
conf/postgresql.conf - logovani do
logs/reply-pilot-db.log - verzovane Liquibase changelogy pres
scripts/db-migrate.sh - automaticke spusteni Liquibase
validateaupdatepristartadeploy
Persistencni host path
Nejdulesitejsi parametr je HOST_DATA_DIR v .env.local nebo .env.server.
Tahle cesta urcuje, kam na hostu fyzicky spadnou PostgreSQL data. Proto data
preziji restart kontejneru i serveru.
Uvnitř kontejneru se PostgreSQL cluster inicializuje do PGDATA=/app/data/postgresql.
To je schvalne podadresar bind mountu, protoze oficialni PostgreSQL image
nepodporuje initdb primo do rootu mountpointu.
Migrace
Liquibase pouziva vlastni tabulky:
public.databasechangelogpublic.databasechangeloglock
Pri prvnim spusteni nad starsi databazi se puvodni public.schema_migrations
automaticky prevede do Liquibase historie, aby se uz aplikovane zmeny
nepoustely znovu. Nasledny changeset 0004 stary tracking table smaze.
Aktualni user a aplikacni konfiguracni tabulky jsou:
public.app_userpublic.app_user_jira_profilepublic.app_configuration
Tabulka app_user ma zatim:
id BIGINT GENERATED BY DEFAULT AS IDENTITYlogin_key TEXT NOT NULLauth_user_id TEXT NOT NULL DEFAULT ''email TEXT NULLdisplay_name TEXT NOT NULL DEFAULT ''gmal_box_link TEXT NOT NULL DEFAULT ''created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
Tabulka app_user_jira_profile drzi lokalni Jira assignment nastaveni pro
aplikacniho uzivatele:
app_user_id BIGINT PRIMARY KEY REFERENCES public.app_user (id) ON DELETE CASCADEjira_account_id TEXT NULLjira_email TEXT NULLjira_assignable BOOLEAN NOT NULL DEFAULT TRUEcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
jira_account_id je stabilni Atlassian identifikator uzivatele a ma prednost
pri mapovani assignee z Jiry. Kdyz jira_email neni vyplneny, aplikace pro Jira
lookup pouzije app_user.email. Migrace zalozi vychozi profil pro existujici
uzivatele a aplikacni Jira assignee service pri nacitani seznamu zalozi chybejici
profily pro nove uzivatele s jira_assignable = TRUE.
Tabulka app_configuration drzi singleton konfiguraci aplikace:
id SMALLINT PRIMARY KEY DEFAULT 1default_email_sales_user_id BIGINT NULL REFERENCES public.app_user (id) ON DELETE SET NULLcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
default_email_sales_user_id je globalni fallback obchodnik pro emailovou
komunikaci, kdyz konkretni firma nema nastaveny vlastni
party_organization.default_email_sales_user_id.
Dalsi migrace zavedly:
public.partypublic.party_personpublic.party_organizationpublic.party_outreach_policypublic.contact_mechpublic.contact_mech_emailpublic.contact_mech_phonepublic.party_contact_mechpublic.party_relationshippublic.activity_typepublic.activitypublic.activity_emailpublic.activity_email_attachmentpublic.activity_email_linkpublic.activity_callpublic.activity_meetingpublic.activity_notepublic.activity_participantpublic.task_typepublic.taskpublic.task_jirapublic.task_jira_email_threadpublic.task_jira_work_typepublic.task_jira_supplier_onboardingpublic.task_jira_email_thread_replypublic.jira_sync_statepublic.ai_prompt_typepublic.ai_promptpublic.lead_import_batchpublic.lead_import_itempublic.requirement_typepublic.requirement_state_typepublic.requirement_evidence_source_typepublic.requirement_evidence_verdict_typepublic.party_requirement_statepublic.party_requirement_evidencepublic.party_requirement_eval_queuepublic.party_feed_factpublic.party_supplier_identifier_fact
Legacy tabulky public.company, public.company_contact a
public.communication_history byly po migraci na party/activity model
odstranene changesetem 0010.
Treti changeset pridava:
public.simple_auth_nonce
Tuto tabulku pouziva reply-pilot-app pro replay protection simple-auth
callbacku. Uklada pouzite rp_nonce a jejich expiraci.
Jedenacty changeset pridava task model:
public.task_typepublic.taskpublic.task_jirapublic.task_jira_email_threadpublic.task_jira_work_typepublic.task_jira_supplier_onboardingpublic.task_jira_email_thread_reply
task je obecny root zaznam podobny activity. Aktualne ma jediny typ jira,
ulozeny v task_type.
task_jira drzi Jira-specific pole a lokalni vazby:
jira_keystatusparty_iduser_idresolutionjira_work_type_code
jira_work_type_code rozlisuje lokalni cache pro Jira work item typu
supplier_onboarding nebo email_thread_reply. Jira zustava source of truth
pro workflow status, lokalni DB drzi work-type klasifikaci a vazby potrebne pro
aplikacni workflow. Jira summary a description se v Reply Pilotu neukladaji;
aplikace je smi pouze docasne nacist z Jiry pro aktualni request.
task_jira_supplier_onboarding je subtype tabulka pro supplier onboarding
ticket. Vazba na firmu je pres task_jira.party_id; onboarding-only metadata
feed_state_code a enlistment_table jsou ulozena tady, ne v base
task_jira.
task_jira_email_thread_reply je subtype tabulka pro email-thread reply ticket.
Vazba na firmu je pres task_jira.party_id, vazba na email thread pres
external_thread_id.
task_jira_email_thread je historicka tabulka z puvodniho modelu. Novy kod pro
reply work items pouziva task_jira_email_thread_reply.
Pozdejsi migrace rozsiruje task_jira o metadata lokalni Jira cache:
jira_updated_atjira_synced_atjira_sync_errorjira_assignee_account_idjira_assignee_display_namejira_assignee_email
Jira-owned pole jako status a assignee se periodicky synchronizuji z Jiry.
Lokální DB je cache a Jira zustava primarni zdroj pravdy pro stav ticketu.
Summary a description se zamerne nesynchronizuji ani neukladaji v lokalni DB.
user_id zustava lokalni mapovani na
app_user, zatimco jira_assignee_* drzi raw hodnoty z Jiry i pro uzivatele,
ktere Reply Pilot lokalne nezna.
Dvanacty changeset pridava:
public.party_organization.show_by_default BOOLEAN NOT NULL DEFAULT TRUE
show_by_default urcuje, jestli se firma ma bezne zobrazovat ve standardnich
listingu, odvozenych company lookupu a company search dokumentech. Primy detail
firmy zustava pristupny i kdyz je hodnota nastavena na FALSE.
Pozdejsi migrace rozsiruje public.party_organization o:
default_email_sales_user_id BIGINT NULL REFERENCES public.app_user (id) ON DELETE SET NULL
Sloupec urcuje vychoziho obchodnika pro emailovou komunikaci konkretni firmy. Aplikace ho pouzije pri predvyplneni assignee email reply tasku, pokud je uzivatel porad dostupny v Jira assignable seznamu.
Trinacty changeset rozsiril public.task_jira o:
feed BOOLEAN NOT NULL DEFAULT FALSEenlistment_table BOOLEAN NOT NULL DEFAULT FALSE
Oba atributy jsou lokalni metadata Jira tasku v Reply Pilotu. Pri vytvoreni
tasku maji vychozi hodnotu FALSE a meni se v editaci tasku.
Ctrnacty changeset pridava CME company tracking:
public.party_cme_matchpublic.party_cme_check_queue
party_cme_match drzi posledni znamy vysledek porovnani firmy proti CME
lookupu. Uklada technicky vysledek matchu (NO_MATCH, MATCHED,
AMBIGUOUS, ERROR), CME integration_state, volitelny cme_dodavatel_id,
dalsi metadata shody a cas posledni kontroly.
party_cme_check_queue je interní worker fronta pro firmy, ktere cekaji na CME
check. Umoznuje periodicky zpracovavat jen nove nebo starnouci firmy misto full
scanu cele tabulky party_organization.
Patnacty changeset nahrazuje puvodni task_jira.feed BOOLEAN stavovym kodem:
public.task_feed_statepublic.task_jira.feed_state_code TEXT NOT NULL DEFAULT 'missing'
task_feed_state je lookup tabulka s internimi kody:
missingverifyingavailable
Pri migraci se puvodni feed = FALSE prevadi na missing a feed = TRUE na
available. Zobrazene ceske popisky zustavaji zalezitosti aplikace, ne DB
schema, aby se daly menit v releasu bez prepisu ulozenych dat.
Sestnacty changeset pridava requirement tracking nad firmami:
public.requirement_typepublic.requirement_state_typepublic.requirement_evidence_source_typepublic.requirement_evidence_verdict_typepublic.party_requirement_statepublic.party_requirement_evidencepublic.party_requirement_eval_queue
requirement_type urcuje, jake onboardingove nebo dokumentacni pozadavky se u
firmy sleduji, napr. ENLISTMENT_TABLE, PRICE_LIST, TOP10, FEED nebo
BUSINESS_TERMS.
party_requirement_state drzi aktualni agregovany stav pozadavku pro jednu
firmu. Umoznuje odlisit UNKNOWN, REQUESTED, CANDIDATE_RECEIVED,
CONFIRMED_RECEIVED, REJECTED a NEEDS_REVIEW, plus volitelny manualni
override.
party_requirement_evidence uklada jednotlive dukazy odvozene z emailu,
threadu, prilohy nebo manualniho vstupu. Evidence muze odkazovat na konkretni
activity_email zpravu pres activity_email_id, a protoze model zatim nema
samostatnou DB entitu pro email thread ani attachment, uklada i
external_thread_id, metadata prilohy a AI vysvetleni/confidence.
party_requirement_eval_queue je worker fronta pro prubezny prepocet
agregovaneho stavu po novych emailech, novych prompt verzi nebo manualnich
zasazich bez nutnosti full scanu celeho activity modelu.
Sedmnacty changeset pridava extracted facts z emailu:
public.party_feed_factpublic.party_supplier_identifier_fact
party_feed_fact uklada konkretni kandidátní feed hodnoty nalezene v jednom
emailu nebo jeho priloze. Drzi URL, delivery mode, confidence a odkaz na
zdrojovy activity_email; volitelne muze ukazovat i na
party_requirement_evidence.
party_supplier_identifier_fact uklada konkretni kandidátní identifikatory
dodavatele nalezene v jednom emailu nebo jeho priloze. Drzi
identifier_type_code, raw/normalized hodnotu, confidence a vazbu na
activity_email; volitelne muze ukazovat i na party_requirement_evidence.
Obe fact tabulky predstavuji vrstvu mezi raw email evidence a finalnim
agregovanym stavem firmy. Finalni company atributy se i nadale pocitaji do
party_requirement_state.
Osmnacty changeset pridava email artifact model navazany na activity_email:
public.activity_email_attachmentpublic.activity_email_link
activity_email_attachment uklada metadata priloh k jednomu importovanemu
emailu. Je to DB source of truth pro attachment metadata, ale ne pro samotny
binární obsah. Binarky zustavaji v existujici file cache modulu
reply-pilot-be a relative_path slouzi jako bridge mezi DB a lokalnim
storage.
activity_email_link uklada explicitni http(s) URL nalezene v body_text
jednoho importovaneho emailu. Drzi raw i normalizovanou podobu, host, path a
kratky kontext. Tato tabulka je source of truth pro dalsi feed/url extractory.
activity_email.body_html uklada pouze dekodovane text/html MIME body casti,
ne raw RFC822 email. body_text zustava source pro summary, search, AI kontext
a extrakci odkazu.
Devatenacty changeset rozsiril finalni requirement projection vrstvu:
public.party_requirement_state.resolved_delivery_mode_codepublic.party_requirement_state.resolved_value_type_codepublic.party_requirement_state.resolved_value_rawpublic.party_requirement_state.resolved_value_normalizedpublic.requirement_typenovy kodSUPPLIER_IDENTIFIER
party_requirement_state tak nove umi drzet nejen finalni state_code, ale i
propagovanou konkretni hodnotu vybranou agregatorem:
- pro
FEEDfinalnidelivery_modea pripadny finalnifeed_url - pro
SUPPLIER_IDENTIFIERfinalniidentifier_typea hodnotu - pro
ENLISTMENT_TABLEzustavaji projekcni sloupce prazdne
Dvacity changeset pridava lead import a outreach policy vrstvu:
public.party_outreach_policypublic.lead_import_batchpublic.lead_import_item
party_outreach_policy drzi explicitni obchodni rozhodnuti nad firmou, hlavne
stav DO_NOT_CONTACT s lidskou poznamkou a vazbou na operatora.
lead_import_batch drzi auditni zaznam o jednom serverovem JSONL souboru,
typicky pripravenem mimo Reply Pilot batch modulem reply-pilot-wholesale-scout.
Uklada jmeno souboru, hash, cestu v backend storage a agregovany stav review.
lead_import_item drzi jednotlive kandidaty z daneho batch souboru. U kazde
polozky uklada puvodni JSON payload, prefill match na existujici firmu, AI draft
prvniho osloveni, operatorovu poznamku a vysledek rozhodnuti IMPORTED,
DO_NOT_CONTACT nebo SKIPPED. Pri importu muze navazat i lokalni task
zaznam a Jira key.
Dvacaty prvni changeset nahrazuje puvodni single-purpose prompt tabulku obecnym typed modelem:
public.ai_prompt_typepublic.ai_prompt
ai_prompt_type je lookup tabulka pro workflow-specific seznamy promptu.
Aktualne se seeduji tyto typy:
EMAIL_REPLAYIMPORT_WIZARDSUPPLIER_ONBOARDING
ai_prompt drzi konkretni predpripravene prompty. Kazdy radek ma povinnou vazbu
na ai_prompt_type, zobrazene name, prompt_text a sort_order.
Pri migraci se puvodni obsah public.email_replay_ai_prompt automaticky presune
do public.ai_prompt pod typ EMAIL_REPLAY a legacy tabulka se odstrani.
Stejny changeset rozsiri public.lead_import_item o:
ai_prompt_idai_prompt_snapshot
ai_prompt_id ukazuje na vybrany prompt pouzity pri generovani AI draftu v
lead import wizardu. ai_prompt_snapshot uklada presne instrukce, ktere byly
do AI requestu poslany, aby audit zustal stabilni i po pozdejsi uprave nebo
smazani promptu.
Dvacaty druhy changeset odstranuje z public.ai_prompt legacy sloupec code;
unikatnost promptu se dale neridi kodem, ale vazbou na typ a internim ID.
Dvacaty treti changeset pridava:
public.app_user_jira_profile
app_user_jira_profile oddeluje Simple Auth identitu v app_user od lokalniho
Jira assignment profilu. jira_account_id je stabilni Jira/Atlassian account id
pro mapovani assignee z Jiry. jira_email je volitelny override pro vyhledani
Jira uzivatele; pokud chybi, pouzije se app_user.email. jira_assignable
urcuje, jestli se uzivatel nabizi v dropdown seznamech pro prirazeni Jira tasku.
Dvacaty ctvrty changeset doplni vychozi app_user_jira_profile radky pro
existujici uzivatele s jira_assignable = TRUE. Stejny default pro nove
uzivatele pri nacitani assignee seznamu prubezne zajistuje aplikacni sluzba.
Dvacaty paty changeset pridava Jira task sync podporu:
public.task_jira.jira_updated_atpublic.task_jira.jira_synced_atpublic.task_jira.jira_sync_errorpublic.jira_sync_state
jira_sync_state drzi globalni stav periodicke synchronizace Jira tasku.
Hlavni watermark je last_seen_jira_updated_at, tedy Jira updated cas,
nikoli cas serveru Reply Pilotu. Incremental sync pouziva tento watermark minus
konfigurovatelny safety overlap; pokud watermark chybi, job provede full sync
projektovych Jira ticketu.
Dvacaty sesty changeset rozsiruje Jira task cache o raw assignee hodnoty z Jiry:
public.task_jira.jira_assignee_account_idpublic.task_jira.jira_assignee_display_namepublic.task_jira.jira_assignee_email
Tyto sloupce oddeluji skutecneho Jira assignee od lokalni vazby
task_jira.user_id. Pokud Jira API vrati email, jira_assignee_email lze
porovnat s app_user_jira_profile.jira_email; kdyz email kvuli Jira privacy
chybi, UI muze porad zobrazit Jira display name nebo account id.
Dvacaty sedmy changeset pridava do public.app_user_jira_profile:
jira_account_id
Mapovani tasku na lokalniho uzivatele pri Jira syncu a filtr Moje ukoly
porovnavaji nejdriv task_jira.jira_assignee_account_id proti
app_user_jira_profile.jira_account_id; email zustava fallback pro pripady, kdy
Jira email vraci.
Dvacaty osmy changeset rozdeluje lokalni Jira task cache podle work typu:
public.task_jira_work_typepublic.task_jira.jira_work_type_code TEXT NOT NULL DEFAULT 'supplier_onboarding'public.task_jira_supplier_onboardingpublic.task_jira_email_thread_reply
Lookup task_jira_work_type ma hodnoty supplier_onboarding a
email_thread_reply. Migrace backfilluje vsechny existujici task_jira radky
na supplier_onboarding a zalozi odpovidajici subtype radky v
task_jira_supplier_onboarding. Jira-side zmena existujicich work items z
puvodniho Task na Supplier Onboarding se dela rucne v Jira Cloud pres bulk
move.
Dvacaty devaty changeset presouva onboarding-only pole feed_state_code a
enlistment_table z base tabulky task_jira do subtype tabulky
task_jira_supplier_onboarding. Email Thread Reply tasky tato pole ve schematu
nemaji; jejich workflow stav zustava Jira-owned task_jira.status cache.
Tricaty changeset pridava novy public.ai_prompt_type kod
SUPPLIER_ONBOARDING pro predpripravene prompty pouzite pri generovani
editovatelneho Jira summary a description pred zalozenim Supplier Onboarding
ticketu z detailu firmy.
Tricaty druhy changeset pridava globalni public.app_configuration singleton
a firemni party_organization.default_email_sales_user_id pro vychoziho
obchodnika emailove komunikace.
Readonly preview user
Operacni skripty DB modulu umi po migracich sladit i volitelneho readonly
PostgreSQL uzivatele pro nahled do DB. Konfigurace je v .env.local nebo
.env.server:
DB_PREVIEW_USER_ENABLEDDB_PREVIEW_USER_NAMEDB_PREVIEW_USER_PASSWORD
Kdyz je DB_PREVIEW_USER_ENABLED=1, skripty vytvori nebo zapnou login a daji
mu CONNECT na databazi, USAGE na public a SELECT na vsechny aktualni i
budouci tabulky/sekvence v public. Kdyz je DB_PREVIEW_USER_ENABLED=0,
skripty roli prepnou na NOLOGIN, takze jde v produkci vypnout jen nastavenim.
Lokalni start
cd reply-pilot-db
cp .env.example .env.local
./scripts/db-start.sh
db-start.sh po readiness checku automaticky spusti Liquibase
validate a update. Stejne tak db-deploy.sh. Rucni migracni skript zustava
zachovany a prime Liquibase prikazy lze volat pres
./scripts/db-liquibase.sh.
Pro host publikaci DB plati:
HOST_DB_BINDurcuje bind adresu na hostu; default je127.0.0.1HOST_DB_PORTurcuje host port; default je5433- kdyz je
HOST_DB_BIND=0.0.0.0, PostgreSQL je dostupna i mimo serverovy loopback
Ověření
./scripts/db-psql.sh -c '\dt public.*'
./scripts/db-psql.sh -c 'select id, author, filename, orderexecuted from public.databasechangelog order by orderexecuted;'
./scripts/db-liquibase.sh history
./scripts/db-liquibase.sh rollback-count 1
Opakovane spusteni ./scripts/db-migrate.sh musi nechat schema beze
zmen. Kazdy migrations/*.sql soubor ma presne jeden Liquibase changeset a
musi obsahovat explicitni --rollback.
Workflow při změně schema
Kdyz menis databazove schema:
- pridej Liquibase changeset do
reply-pilot-db/migrations/ - dopln novy soubor do
reply-pilot-db/migrations/db.changelog.xml - zajisti explicitni
--rollback - over migraci pres:
cd reply-pilot-db
./scripts/db-liquibase.sh validate
./scripts/db-liquibase.sh update
./scripts/db-liquibase.sh rollback-count 1
./scripts/db-liquibase.sh update
Pokud se meni activity/contact data model, aktualizuj i docs/activity-model.md
a přegeneruj souvisejici diagramy pres rp.