Urza’s Wallet / Engineering

Data model

Costa Rica personal finance comparison platform.

schema

Migrated PostgreSQL schema

This snapshot is introspected from a disposable PostgreSQL 16 database after alembic upgrade head. All 24 application tables are shown in four domain diagrams. Relationship lines stay within a domain; the column listings retain cross-domain foreign keys.

Download the schema snapshot. Run pnpm docs:build --schema after migrations. The integration suite compares it with a fresh migrated database.

Draft tables support deferred accounts, documents and legacy content pages; their presence in the schema does not imply a shipped feature. PII collection is limited to leads and lead consent records.

product_id

issuer_id

product_id

product_id

credit_cards

uuid

product_id

PK

numeric_12__2_

annual_fee_crc

boolean

annual_fee_waivable

numeric_6__4_

interest_rate_annual_pct

varchar_10_

network

varchar_8_

reward_type

numeric_6__4_

cashback_rate_pct

numeric_14__2_

min_income_crc

text

benefits_summary

varchar_5_

currency

boolean

has_travel_benefits

financial_products

uuid

id

PK

varchar_19_

vertical

varchar_255_

product_name

varchar_100_

issuer_id

FK

varchar_8_

status

smallint

editorial_score

text

editorial_summary

timestamp

updated_at

varchar_2048_

source_url

home_loans

uuid

product_id

PK

varchar_8_

rate_type

numeric_8__4_

interest_rate_annual_pct

numeric_6__4_

max_ltv_pct

smallint

max_term_years

varchar_3_

currency

numeric_18__2_

min_amount

numeric_18__2_

max_amount

text

eligibility_notes

issuers

varchar_100_

id

PK

varchar_255_

name

varchar_50_

short_name

varchar_19_

vertical

varchar_2048_

logo_url

varchar_2048_

website_url

boolean

is_active

pension_funds

uuid

product_id

PK

varchar_3_

fund_type

varchar_255_

operadora

numeric_8__4_

return_1yr_pct

numeric_8__4_

return_3yr_pct

numeric_8__4_

return_5yr_pct

numeric_6__4_

management_fee_pct

text

risk_profile

varchar_10_

supen_rating

date

prospectus_date

catalog data model

cluster_id

guide_id

journey_id

articles

uuid

id

PK

varchar_160_

slug

varchar_19_

vertical

varchar_255_

title

text

summary

varchar_2048_

image_url

varchar_120_

author

timestamp

published_at

timestamp

updated_at

array

tags

array

related_product_ids

varchar_20_

status

text

body_md

text

excerpt

editorial_reviews

uuid

product_id

PK

array

pros

array

cons

text

best_use_case

text

review_body_md

varchar_120_

author

timestamp

published_at

timestamp

updated_at

varchar_20_

status

guide_clusters

varchar_21_

id

PK

varchar_120_

title

text

description

smallint

order_index

guides

uuid

id

PK

varchar_160_

slug

varchar_21_

cluster_id

FK

varchar_255_

title

text

summary

text

body_md

varchar_120_

author

timestamp

updated_at

smallint

order_in_cluster

array

related_guide_slugs

array

related_article_slugs

array

related_product_ids

varchar_20_

status

timestamp

published_at

journey_steps

uuid

id

PK

uuid

journey_id

FK

uuid

guide_id

FK

varchar_255_

step_title

smallint

position

learning_journeys

uuid

id

PK

varchar_160_

slug

varchar_255_

title

text

description

array

guide_slugs

varchar_40_

end_cta_kind

varchar_120_

end_cta_label

offers

uuid

id

PK

uuid

product_id

FK

varchar_160_

headline

text

terms_snippet

numeric_12__2_

bonus_crc

numeric_6__4_

intro_apr_pct

smallint

intro_period_months

timestamp

active_from

timestamp

active_until

timestamp

created_at

content data model

lead_id

cta_engagement_events

uuid

id

PK

varchar_64_

session_id

uuid

product_id

FK

varchar_19_

vertical

varchar_11_

source_surface

varchar_16_

event_type

jsonb

metadata

timestamp

created_at

lead_consent_records

uuid

id

PK

uuid

lead_id

FK

varchar_20_

policy_version

timestamp

granted_at

varchar_64_

ip_hash

lead_deletion_requests

uuid

id

PK

varchar_320_

email

timestamp

requested_at

varchar_9_

status

timestamp

processed_at

text

processing_notes

leads

uuid

id

PK

varchar_200_

name

varchar_320_

email

varchar_19_

vertical

uuid

product_id

FK

varchar_255_

product_name_snapshot

varchar_11_

source_surface

varchar_64_

session_id

varchar_9_

status

text

notes

timestamp

created_at

timestamp

contacted_at

boolean

is_anonymized

leads data model

user_id

document_id

replaced_by

user_id

uploaded_by

user_id

admin_audit_log

uuid

id

PK

varchar_255_

actor

varchar_100_

action

varchar_100_

entity_type

varchar_255_

entity_id

jsonb

payload

timestamp

created_at

consent_records (Draft)

uuid

id

PK

uuid

user_id

FK

varchar_16_

consent_type

varchar_20_

policy_version

boolean

granted

timestamp

recorded_at

varchar_64_

ip_address_hash

content_pages (Draft)

uuid

id

PK

varchar_255_

slug

varchar_19_

vertical

varchar_8_

page_type

varchar_255_

title

text

meta_description

text

body_html

jsonb

structured_data

timestamp

published_at

timestamp

updated_at

varchar_255_

author

document_versions (Draft)

uuid

id

PK

uuid

document_id

FK

integer

version_number

varchar_1024_

storage_path

timestamp

superseded_at

uuid

replaced_by

FK

saved_comparisons (Draft)

uuid

id

PK

uuid

user_id

FK

varchar_19_

vertical

array

product_ids

varchar_120_

label

timestamp

created_at

static_documents (Draft)

uuid

id

PK

varchar_19_

vertical

varchar_100_

issuer_id

FK

varchar_12_

document_type

varchar_255_

title

varchar_1024_

storage_path

varchar_6_

storage_backend

varchar_10_

access_level

date

effective_date

boolean

is_current_version

timestamp

uploaded_at

uuid

uploaded_by

FK

user_alerts (Draft)

uuid

id

PK

uuid

user_id

FK

uuid

product_id

FK

varchar_11_

alert_type

numeric_10__4_

threshold_value

boolean

is_active

timestamp

last_triggered_at

timestamp

created_at

user_profiles (Draft)

uuid

id

PK

varchar_255_

clerk_user_id

varchar_320_

email

varchar_255_

display_name

varchar_15_

role

varchar_3_

preferred_currency

jsonb

preferred_verticals

varchar_50_

default_sort_credit_cards

varchar_50_

default_sort_pension_funds

varchar_50_

default_sort_home_loans

varchar_20_

notification_frequency

timestamp

created_at

timestamp

deleted_at

boolean

is_anonymized

platform data model

admin_audit_log

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
actorVARCHAR(255)No
actionVARCHAR(100)No
entity_typeVARCHAR(100)No
entity_idVARCHAR(255)No
payloadJSONBYes
created_atTIMESTAMPNonow()

articles

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
slugVARCHAR(160)No
verticalVARCHAR(19)No
titleVARCHAR(255)No
summaryTEXTNo
image_urlVARCHAR(2048)Yes
authorVARCHAR(120)No
published_atTIMESTAMPNo
updated_atTIMESTAMPNonow()
tagsARRAYNoARRAY[]::article_tag[]
related_product_idsARRAYNoARRAY[]::uuid[]
statusVARCHAR(20)No'draft'::character varying
body_mdTEXTYes
excerptTEXTYes

content_pages Draft

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
slugVARCHAR(255)No
verticalVARCHAR(19)Yes
page_typeVARCHAR(8)No
titleVARCHAR(255)No
meta_descriptionTEXTYes
body_htmlTEXTYes
structured_dataJSONBYes
published_atTIMESTAMPYes
updated_atTIMESTAMPNonow()
authorVARCHAR(255)Yes

credit_cards

Primary key: product_id

ColumnTypeNullableDefaultForeign key
product_idUUIDNofinancial_products(id) · CASCADE
annual_fee_crcNUMERIC(12, 2)No0
annual_fee_waivableBOOLEANNofalse
interest_rate_annual_pctNUMERIC(6, 4)No
networkVARCHAR(10)No
reward_typeVARCHAR(8)No'none'::reward_type
cashback_rate_pctNUMERIC(6, 4)Yes
min_income_crcNUMERIC(14, 2)Yes
benefits_summaryTEXTYes
currencyVARCHAR(5)No'CRC'::card_currency
has_travel_benefitsBOOLEANNofalse

cta_engagement_events

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
session_idVARCHAR(64)No
product_idUUIDNofinancial_products(id) · CASCADE
verticalVARCHAR(19)No
source_surfaceVARCHAR(11)No
event_typeVARCHAR(16)No
metadataJSONBYes
created_atTIMESTAMPNonow()

document_versions Draft

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
document_idUUIDNostatic_documents(id) · CASCADE
version_numberINTEGERNo
storage_pathVARCHAR(1024)No
superseded_atTIMESTAMPNonow()
replaced_byUUIDYesstatic_documents(id) · SET NULL

editorial_reviews

Primary key: product_id

ColumnTypeNullableDefaultForeign key
product_idUUIDNofinancial_products(id) · CASCADE
prosARRAYNoARRAY[]::text[]
consARRAYNoARRAY[]::text[]
best_use_caseTEXTYes
review_body_mdTEXTYes
authorVARCHAR(120)Yes
published_atTIMESTAMPYes
updated_atTIMESTAMPNonow()
statusVARCHAR(20)No'draft'::character varying

financial_products

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
verticalVARCHAR(19)No
product_nameVARCHAR(255)No
issuer_idVARCHAR(100)Noissuers(id) · RESTRICT
statusVARCHAR(8)No'draft'::product_status
editorial_scoreSMALLINTNo0
editorial_summaryTEXTYes
updated_atTIMESTAMPNonow()
source_urlVARCHAR(2048)Yes

guide_clusters

Primary key: id

ColumnTypeNullableDefaultForeign key
idVARCHAR(21)No
titleVARCHAR(120)No
descriptionTEXTNo
order_indexSMALLINTNo

guides

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
slugVARCHAR(160)No
cluster_idVARCHAR(21)Noguide_clusters(id) · RESTRICT
titleVARCHAR(255)No
summaryTEXTNo
body_mdTEXTNo
authorVARCHAR(120)No
updated_atTIMESTAMPNonow()
order_in_clusterSMALLINTNo0
related_guide_slugsARRAYNo(ARRAY[]::character varying[])::character varying(160)[]
related_article_slugsARRAYNo(ARRAY[]::character varying[])::character varying(160)[]
related_product_idsARRAYNoARRAY[]::uuid[]
statusVARCHAR(20)No'draft'::character varying
published_atTIMESTAMPYes

home_loans

Primary key: product_id

ColumnTypeNullableDefaultForeign key
product_idUUIDNofinancial_products(id) · CASCADE
rate_typeVARCHAR(8)No
interest_rate_annual_pctNUMERIC(8, 4)No
max_ltv_pctNUMERIC(6, 4)No
max_term_yearsSMALLINTNo
currencyVARCHAR(3)No
min_amountNUMERIC(18, 2)Yes
max_amountNUMERIC(18, 2)Yes
eligibility_notesTEXTYes

issuers

Primary key: id

ColumnTypeNullableDefaultForeign key
idVARCHAR(100)No
nameVARCHAR(255)No
short_nameVARCHAR(50)No
verticalVARCHAR(19)Yes
logo_urlVARCHAR(2048)Yes
website_urlVARCHAR(2048)Yes
is_activeBOOLEANNotrue

journey_steps

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
journey_idUUIDNolearning_journeys(id) · CASCADE
guide_idUUIDNoguides(id) · RESTRICT
step_titleVARCHAR(255)No
positionSMALLINTNo

lead_deletion_requests

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
emailVARCHAR(320)No
requested_atTIMESTAMPNonow()
statusVARCHAR(9)No'pending'::deletion_request_status
processed_atTIMESTAMPYes
processing_notesTEXTYes

leads

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
nameVARCHAR(200)Yes
emailVARCHAR(320)Yes
verticalVARCHAR(19)No
product_idUUIDNofinancial_products(id) · RESTRICT
product_name_snapshotVARCHAR(255)No
source_surfaceVARCHAR(11)No
session_idVARCHAR(64)No
statusVARCHAR(9)No'new'::lead_status
notesTEXTYes
created_atTIMESTAMPNonow()
contacted_atTIMESTAMPYes
is_anonymizedBOOLEANNofalse

learning_journeys

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
slugVARCHAR(160)No
titleVARCHAR(255)No
descriptionTEXTNo
guide_slugsARRAYNo
end_cta_kindVARCHAR(40)No
end_cta_labelVARCHAR(120)No

offers

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
product_idUUIDNofinancial_products(id) · CASCADE
headlineVARCHAR(160)No
terms_snippetTEXTYes
bonus_crcNUMERIC(12, 2)Yes
intro_apr_pctNUMERIC(6, 4)Yes
intro_period_monthsSMALLINTYes
active_fromTIMESTAMPYes
active_untilTIMESTAMPYes
created_atTIMESTAMPNonow()

pension_funds

Primary key: product_id

ColumnTypeNullableDefaultForeign key
product_idUUIDNofinancial_products(id) · CASCADE
fund_typeVARCHAR(3)No
operadoraVARCHAR(255)No
return_1yr_pctNUMERIC(8, 4)Yes
return_3yr_pctNUMERIC(8, 4)Yes
return_5yr_pctNUMERIC(8, 4)Yes
management_fee_pctNUMERIC(6, 4)No
risk_profileTEXTYes
supen_ratingVARCHAR(10)Yes
prospectus_dateDATEYes

saved_comparisons Draft

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
user_idUUIDNouser_profiles(id) · CASCADE
verticalVARCHAR(19)No
product_idsARRAYNo
labelVARCHAR(120)Yes
created_atTIMESTAMPNonow()

static_documents Draft

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
verticalVARCHAR(19)Yes
issuer_idVARCHAR(100)Noissuers(id) · RESTRICT
document_typeVARCHAR(12)No
titleVARCHAR(255)No
storage_pathVARCHAR(1024)No
storage_backendVARCHAR(6)No'volume'::storage_backend
access_levelVARCHAR(10)No'public'::document_access
effective_dateDATEYes
is_current_versionBOOLEANNotrue
uploaded_atTIMESTAMPNonow()
uploaded_byUUIDYesuser_profiles(id) · SET NULL

user_alerts Draft

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
user_idUUIDNouser_profiles(id) · CASCADE
product_idUUIDNofinancial_products(id) · CASCADE
alert_typeVARCHAR(11)No
threshold_valueNUMERIC(10, 4)Yes
is_activeBOOLEANNotrue
last_triggered_atTIMESTAMPYes
created_atTIMESTAMPNonow()

user_profiles Draft

Primary key: id

ColumnTypeNullableDefaultForeign key
idUUIDNogen_random_uuid()
clerk_user_idVARCHAR(255)No
emailVARCHAR(320)No
display_nameVARCHAR(255)Yes
roleVARCHAR(15)No'registered_user'::user_role
preferred_currencyVARCHAR(3)No'CRC'::character varying
preferred_verticalsJSONBNo'[]'::jsonb
default_sort_credit_cardsVARCHAR(50)Yes
default_sort_pension_fundsVARCHAR(50)Yes
default_sort_home_loansVARCHAR(50)Yes
notification_frequencyVARCHAR(20)Yes'immediate'::character varying
created_atTIMESTAMPNonow()
deleted_atTIMESTAMPYes
is_anonymizedBOOLEANNofalse