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 vyhradne na
stderr, sbirane container runtime - verzovane Liquibase changelogy pres
scripts/db-migrate.sh - automaticke spusteni Liquibase
validatea expand-onlyupdatepristartadeploy - reconcile samostatneho readonly loginu
reply_pilot_backuppro logical backup service
Kompletni backup/restore runtime kontrakt je v Reply Pilot Database Backup.
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_permissionpublic.app_rolepublic.app_role_permissionpublic.app_user_rolepublic.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 TRUEjira_oauth_credentials_ciphertext TEXT NULLcreated_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.
jira_oauth_credentials_ciphertext je volitelny verzovany credential envelope
pro delegovane Jira komentare. Backend ho uklada sifrovany pres AES-256-GCM;
obsahuje access token, aktualni rotating refresh token, expiraci, scopes, Jira
cloud ID a overenou Atlassian identitu. Plaintext token se do DB neuklada.
Sifrovaci klic je runtime secret backendu a neni soucasti databaze.
Tabulka app_user_email_signature drzi volitelny HTML podpis pro odchozi
emailove odpovedi konkretniho aplikacniho uzivatele:
app_user_id BIGINT PRIMARY KEY REFERENCES public.app_user (id) ON DELETE CASCADEbody_html TEXT NOT NULLbody_plain_text TEXT NOT NULL DEFAULT ''created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
Podpis je volitelny; chybejici radek znamena, ze uzivatel nema nastaveny podpis. Aplikace uklada HTML podpis oddelene od markdown textu odpovedi a pri vytvareni Gmail draftu nebo primem odeslani jej pripoji az po renderovani odpovedi do HTML.
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.
RBAC tabulky drzi aplikacni role a opravneni nad stabilni identitou
app_user.id:
app_permission(code TEXT PRIMARY KEY, label TEXT, description TEXT)app_role(id BIGINT GENERATED BY DEFAULT AS IDENTITY, code TEXT UNIQUE, label TEXT, description TEXT, system_role BOOLEAN, active BOOLEAN, created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ)app_role_permission(role_id BIGINT REFERENCES app_role(id) ON DELETE CASCADE, permission_code TEXT REFERENCES app_permission(code) ON DELETE CASCADE)app_user_role(app_user_id BIGINT REFERENCES app_user(id) ON DELETE CASCADE, role_id BIGINT REFERENCES app_role(id) ON DELETE CASCADE)app_user_impersonation_audit(id BIGINT GENERATED BY DEFAULT AS IDENTITY, real_app_user_id BIGINT REFERENCES app_user(id) ON DELETE CASCADE, target_app_user_id BIGINT REFERENCES app_user(id) ON DELETE CASCADE, started_at TIMESTAMPTZ, ip_address TEXT, user_agent TEXT)
Kanonicky katalog opravneni a seedovanych roli je v Permission Catalog.
RBAC migrace seeduji opravneni:
company.view_assignedcompany.view_allcompany.writecompany.write_assignedcompany.mergesecurity.manage_rolessecurity.impersonate_user
Seedovane system role jsou:
adminse vsemi opravnenimisalesscompany.view_assignedacompany.write_assignedsales_managerscompany.view_assigned,company.view_all,company.write,company.write_assignedacompany.mergesupport_impersonatorssecurity.impersonate_user
Prirazeni konkretniho admina se nedela automaticky migraci. Musi probehnout
explicitnim SQL/script krokem nad existujicim app_user.id.
security.impersonate_user se nepridava automaticky do role admin. Ma se
prirazovat explicitne pres roli support_impersonator, protoze umoznuje
docasne pracovat jako jiny povoleny uzivatel. Start impersonace se zapisuje do
app_user_impersonation_audit. V1 nepovoluje impersonovat uzivatele s
security.manage_roles ani uzivatele se security.impersonate_user.
V1 autorizacni pravidlo pro firmy je:
- uzivatel s
company.view_allmuze videt vsechny firmy v povolenych read cestach - uzivatel bez
company.view_all, ale scompany.view_assigned, vidi jen firmy, kdeparty_organization.default_email_sales_user_id = app_user.id - firmy s
party_organization.default_email_sales_user_id IS NULLjsou ve V1 viditelne jen procompany.view_all party_organization.show_by_defaultzustava jen display filtr uvnitr autorizovaneho rozsahu, neni to autorizace- zapisove company/task endpointy pro existujici firmu prijimaji
company.writenebocompany.write_assigneda zaroven kontroluji stejny company visibility scope; rolesalestedy muze menit jen firmy a navazane tasky, kde je uzivatel vychozi osoba pro emailovou komunikaci - backend read-model company/task endpointy maji uzkou read-only vyjimku pro
aktivni delegovane
Reply Pilot Task: aktualni Jira assignee ulozeny vtask_jira/app_user_jira_profilemuze cist jen firmu napojenou na tento aktivni task a samotny aktivni task; vyjimka neplati pro zapis, nesouvisejici firmy, neprirazene tasky aniDonetasky - zalozeni nove firmy prijima
company.writenebocompany.write_assigned; backend nove firme vzdy nastaviparty_organization.default_email_sales_user_id = app_user.idaktualniho uzivatele, takze scoped zapis vytvari jen self-assigned firmu
Dalsi migrace zavedly:
public.partypublic.party_personpublic.party_person_name_legacypublic.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.task_jira_reply_pilot_taskpublic.task_jira_organize_meetingpublic.work_wizard_task_snoozepublic.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_codejira_summaryjira_description_text
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, vazby potrebne pro
aplikacni workflow a plain-text cache Jira summary/description pro read modely
a search. jira_description_text je textovy obsah, ne Jira ADF JSON.
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_emailjira_summaryjira_description_text
Jira-owned pole jako status, assignee, summary a plain-text description se
periodicky synchronizuji z Jiry. Lokální DB je cache a Jira zustava primarni
zdroj pravdy pro stav a obsah ticketu. 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.
Pozdejsi migrace normalizuje jmena osob:
public.party.display_namepro osoby je odvozene zpublic.party_person.first_nameapublic.party_person.last_name- manualni formulare osob edituji jen
first_namealast_name public.party_person.middle_namezustava kvuli historicke kompatibilite, ale nove zapisy ho nemaji plnitpublic.party_person_name_legacyuchovava hodnoty jmen pred normalizaci pro audit a rollback migrace
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 historicky pridal CME matching. Changeset 43 bezpecne
zkopiruje legacy vazby do noveho CME source modelu a contract changeset 44
odstrani legacy tabulky az v pozdejsim releasu. Aktualni CME model je popsany
v sekci CME source firem nize.
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 puvodne rozdelil hodnoty supplier_onboarding a
email_thread_reply. Pozdejsi migrace doplnila hodnotu reply_pilot_task pro
obecne delegovane Jira tasky typu Reply Pilot Task. 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.
Ctyricaty changeset vraci do public.task_jira plain-text cache pro Jira texty:
jira_summary TEXT NOT NULL DEFAULT ''jira_description_text TEXT NOT NULL DEFAULT ''
Cache se plni z Jira task syncu a z backend task mutaci, ktere vytvareji nebo edituji Supplier Onboarding a Email Thread Reply tasky. Uklada se jen plain text; Jira ADF JSON se do DB neuklada.
Ctyricaty prvni changeset pridava lokalni subtype pro obecne delegovane Jira tasky:
public.task_jira_work_typenovy kodreply_pilot_taskpublic.task_jira_reply_pilot_task
reply_pilot_task reprezentuje Jira issue type Reply Pilot Task.
customfield_10269 Jira pole taskType zustava Jira-owned hodnota a v DB se
uklada jako raw text v task_jira_reply_pilot_task.task_type_value. Aktualni
potvrzene hodnoty jsou General, Meeting organization a
Registration (B2B), ale DB nepouziva check constraint, aby Jira-owned dropdown
mohl byt pozdeji rozsiren bez destruktivni migrace.
task_jira_reply_pilot_task drzi workflow-specific data, ktera nepatri do base
task_jira:
task_id BIGINT PRIMARY KEY REFERENCES public.task_jira (task_id) ON DELETE CASCADEtask_type_value TEXT NOT NULL DEFAULT 'General'requester_app_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()
Vazba na spolecnost zustava v base task_jira.party_id; tahle hodnota je
source of truth pro Reply Pilot workflow a autorizaci. Jira description ma
obsahovat lidsky odkaz na spolecnost, ale backend se pri rozhodovani nema ridit
parsovanim description.
Pri resolve akci backend bere requester_app_user_id jako source of truth pro
zadavatele, prida zadany text do Jira/plain-text description, priradi Jira task
zpet na Jira ucet tohoto app usera a ponecha Jira status In Progress. Pri
close akci muze task uzavrit jen ulozeny zadavatel; backend presune Jira task
do Done a assignee nemeni.
Ctyricaty sesty changeset pridava do public.app_user_jira_profile:
jira_oauth_credentials_ciphertext TEXT NULL
Sloupec drzi sifrovany delegovany OAuth 2.0 credential envelope. Je nullable, protoze uzivatel muze Reply Pilot pouzivat bez delegovaneho Jira uctu; v tom pripade zapis komentare vrati vyzvu k autorizaci. Rollback sloupec odstrani. Technicky Jira API token backendu zustava mimo DB v runtime secrets.
Ctyricaty sedmy changeset pridava lokalni subtype pro Jira issue type
Organize a Meeting:
public.task_jira_work_typenovy kodorganize_meetingpublic.task_jira_organize_meeting
task_jira_organize_meeting.contact_party_id je nullable vazba na
public.party. Hodnota NULL znamena, ze pri zalozeni pozadavku nebyla
kontaktni osoba vybrana. Backend dovoli ulozit nenulovou osobu jen tehdy, kdyz
ma ke spolecnosti z task_jira.party_id aktivni vztah CONTACT_FOR.
Spolecnost, Jira assignee, summary a plain-text Description zustavaji v base
task_jira cache; contact_party_id je workflow-specific metadata subtype.
Ctyricaty osmy changeset pridava public.work_wizard_task_snooze pro docasne
odlozeni polozky v Průvodci úkoly konkretnim uzivatelem:
user_id BIGINT NOT NULL REFERENCES public.app_user (id) ON DELETE CASCADEtask_id BIGINT NOT NULL REFERENCES public.task (id) ON DELETE CASCADEsnoozed_until TIMESTAMPTZ NOT NULL- primarni klic
(user_id, task_id)
Odklad je pouze per-user pohledova vlastnost Reply Pilotu; do Jiry se
nezapisuje. Kliknuti na „Teď neřešit“ provede upsert s expiraci za tri hodiny.
Průvodce filtruje jen radky s snoozed_until v budoucnosti, proto se ukol po
expiraci znovu zobrazi i pred fyzickym uklidem radku. Worker expirovane radky
periodicky maze.
CME source firem
party_cme_source je read model puvodu firmy v CME. Primarni klic
(source_type, source_id) rozlisuje DODAVATEL a OSLOVENI; vice CME zaznamu
muze odkazovat na stejne party_id. Tabulka uchovava CME obchodnika a datumy
rezervace/oslovení oddelene od party_organization.default_email_sales_user_id,
protoze lokalni vychozi obchodnik ovlivnuje opravneni a prirazovani tasku.
Synchronizace je jednosmerna CME -> Reply Pilot. Existujici firmu hleda podle
jednoznacneho ICO, potom DIC a nakonec podle presne normalizovaneho nazvu.
Drive pouzivany party_identifier.identifier_type_code = 'CME_DODAVATEL_ID'
se uz nevytvari ani nepouziva; jedinym source of truth pro CME identitu je
party_cme_source (source_type, source_id). Nejednoznacny zaznam se automaticky
neslouci; zustane v party_cme_source s prazdnym party_id a last_error.
Lokalni vyplnene udaje synchronizace neprepisuje. Zdroj, ktery zmizi z CME,
dostane missing_since a nemaze se.
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 s filtrem !contract. Stejne tak db-deploy.sh. Tohle je zamerna
ochrana proti tomu, aby destruktivni migrace odstranila schema, ktere jeste
pouziva starsi bezici backend. Rucni migracni skript zustava zachovany a prime
Liquibase prikazy lze volat pres ./scripts/db-liquibase.sh.
Od migrace 0043 musi byt destruktivni changeset v db.changelog.xml
oznaceny contextFilter="contract". Validace deploy zablokuje, pokud najde
drop, truncate, rename nebo nekompatibilni zmenu typu bez tohoto kontextu.
Contract migrace se spousti az v pozdejsim samostatnem deployi, kdy jsou vsechny
konzumenty prokazatelne na novem schematu:
./scripts/db-liquibase.sh update --context-filter='@contract'
Prefix @contract znamena, ze se v tomto explicitnim kroku vyberou jen
changesety skutecne oznacene contract kontextem. Standardni deploy tenhle krok
nikdy nespousti.
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 - pokud je zmena destruktivni, oznac include
contextFilter="contract"a naplanuj ji do pozdejsiho releasu po nasazeni kompatibilnich konzumentu - over expand 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
Contract migraci over pres expand-only update (musi ji preskocit), potom
explicitni @contract update, rollback a znovu explicitni update:
./scripts/db-liquibase.sh validate
./scripts/db-liquibase.sh update
./scripts/db-liquibase.sh update --context-filter='@contract'
./scripts/db-liquibase.sh rollback-count 1
./scripts/db-liquibase.sh update --context-filter='@contract'
Pokud se meni activity/contact data model, aktualizuj i docs/activity-model.md
a přegeneruj souvisejici diagramy pres rp.