The database
Everything NoCloud knows lives in one unified SQLite database — your finances, your photos' metadata, your family tree, your house, your health. One file, on hardware you own, queryable with any SQLite tool. See Architecture for where it sits, and Open standards for the formats each domain normalises to.
How to read it
Domain prefix. Every table starts with its domain: app_, fin_, people_, home_, photo_,
health_, tax_, chat_, inv_, decloud_. That's the first thing to look at — it tells you
which part of your life the table belongs to.
Fundamental vs derived. A column prefixed calc_ is derived: it's computed from other data
and regenerated by the builders, so it is never hand-edited and never authoritative. Everything else
is fundamental — the real, entered-once data. If a calc_ value looks wrong, the fix is upstream,
in whatever produces it.
Conventions. is_* are booleans · <entity>_id are foreign keys · sort_order is ordering
(never order, a reserved word) · identifiers are English, snake_case. The full convention lives in
docs/DB_NAMING.md.
Nothing here is your data. This page lists structure only — table and column names, types and purpose. No row ever leaves your machine; see Security & privacy.
Safety net
Every write to this database goes through a snapshot-first, append-only ledger (dbsafe): the
previous state is copied before the change and the operation is recorded, so any accident can be
rolled back. Bulk operations on the archive are reversible too — see Concepts.
Table reference
Every table in the database, grouped by domain prefix (§"How to read it" above) — auto-generated from the live schema, so it never drifts from the real columns.
APP (product: users, sections, languages)
app_import_batches — Log of each connector import run: rows received/written/inserted/updated/skipped, per dataset and source. Feeds the onboarding journey's import-history signals.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
connector |
TEXT | NOT NULL |
dataset |
TEXT | NOT NULL |
source |
TEXT | NOT NULL |
received |
INTEGER | NOT NULL |
written |
INTEGER | NOT NULL |
inserted |
INTEGER | NOT NULL |
updated |
INTEGER | NOT NULL |
skipped |
INTEGER | NOT NULL |
created_at |
TEXT | NOT NULL |
app_languages — DIMENSION of the UI languages on offer (code is the BCP-47 tag). The UI is written in English and translated from it.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
code |
TEXT | NOT NULL, UNIQUE |
name |
TEXT | NOT NULL |
app_sections — CATALOG of everything installable on the Home: the built-in sections plus every App Store app (is_app). One row per section, with the URL it opens and the icon/description shown on its tile — emoji is a legacy fallback only (real icons are each app's own icon.svg; apps stopped declaring an emoji in their manifest).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
slug |
TEXT | NOT NULL, UNIQUE |
name |
TEXT | NOT NULL |
emoji |
TEXT | — |
url |
TEXT | NOT NULL |
sort_order |
INTEGER | NOT NULL |
description |
TEXT | — |
is_app |
INTEGER | NOT NULL |
creator |
TEXT | — |
version |
TEXT | — |
updated_at |
TEXT | — |
admin_only |
INTEGER | NOT NULL |
app_timezones — DIMENSION of selectable timezones (IANA names). What turns a stored UTC timestamp into the hour you actually read.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
tz |
TEXT | NOT NULL, UNIQUE |
name |
TEXT | NOT NULL |
app_user_sections — Which sections each user has on their Home, in which order (sort_order) and whether they are hidden (is_active=0). Hiding is NOT uninstalling: the row stays.
| Field | Type | Notes |
|---|---|---|
user_id |
INTEGER | NOT NULL, → app_users, PK |
section_id |
INTEGER | NOT NULL, → app_sections, PK |
is_active |
INTEGER | NOT NULL |
sort_order |
INTEGER | — |
app_user_widgets — Per-user widget layout: order, size and whether it is hidden. Same shape as app_user_sections on purpose — a widget and a section are configured identically.
| Field | Type | Notes |
|---|---|---|
user_id |
INTEGER | NOT NULL, → app_users, PK |
widget_id |
INTEGER | NOT NULL, → app_widgets, PK |
cols |
INTEGER | — |
rows |
INTEGER | — |
sort_order |
INTEGER | — |
is_active |
INTEGER | NOT NULL |
app_users — The people who can log in. person_id links an account to its row in people_persons, which is what ties a login to a face in the photos. The live copy of this lives in the server's settings.json; this table is the normalized projection of it.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
username |
TEXT | NOT NULL, UNIQUE |
email |
TEXT | — |
is_admin |
INTEGER | NOT NULL |
is_family |
INTEGER | NOT NULL |
person_id |
TEXT | → people_persons |
language_id |
INTEGER | NOT NULL, → app_languages |
timezone_id |
INTEGER | NOT NULL, → app_timezones |
email_verified |
INTEGER | NOT NULL |
github |
TEXT | — |
app_widgets — CATALOG of Home widgets, with their default size in grid columns × rows (default_cols/default_rows). Adding a row here makes the widget appear for everyone.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
slug |
TEXT | NOT NULL, UNIQUE |
name |
TEXT | NOT NULL |
emoji |
TEXT | — |
description |
TEXT | — |
default_cols |
INTEGER | NOT NULL |
default_rows |
INTEGER | NOT NULL |
FINANCE
fin_accounts — CHART OF ACCOUNTS of the double-entry ledger: assets, liabilities, income and expense, nested via parent_id. Derived from the raw cash book (fin_movements), which stays untouched — see scripts/fin_ledger.py for the ledger contract.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
code |
TEXT | NOT NULL, UNIQUE |
kind |
TEXT | NOT NULL |
name |
TEXT | NOT NULL |
parent_id |
INTEGER | → fin_accounts |
currency |
TEXT | — |
source_account_id |
INTEGER | → fin_source_accounts |
category_code |
INTEGER | → fin_categories |
is_active |
INTEGER | NOT NULL |
fin_tax_lots — Tax lots (basis of the capital-gains FIFO) with costs: commission/exchange_fee/other_fees.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
security |
TEXT | — |
isin |
TEXT | — |
kind |
TEXT | — |
date |
TEXT | — |
units |
REAL | — |
amount |
REAL | — |
source |
TEXT | — |
commission |
REAL | — |
exchange_fee |
REAL | — |
other_fees |
REAL | — |
fin_categories — DIMENSION of income/expense categories (PK=code; ISO 20022 purpose_code + own subcode + merchant).
| Field | Type | Notes |
|---|---|---|
code |
INTEGER | PK |
grp |
TEXT | — |
name |
TEXT | — |
sign |
TEXT | — |
calc_concept_count |
INTEGER | — |
purpose_code |
TEXT | — |
subcode |
TEXT | — |
merchant |
TEXT | — |
fin_category_overrides — Manual corrections to automatic categorisation, keyed by the normalised concept. A human decision that beats the rule and survives re-imports — this is what makes the classifier coachable.
| Field | Type | Notes |
|---|---|---|
concept_norm |
TEXT | PK |
category |
TEXT | NOT NULL |
ts |
TEXT | — |
fin_quotes — Latest quote per ticker/broker. price=fundamental (market); calc_value_eur=derived (shares×price×fx).
| Field | Type | Notes |
|---|---|---|
ticker |
TEXT | PK |
broker |
TEXT | PK |
date |
TEXT | PK |
calc_value_eur |
REAL | — |
price |
REAL | — |
source |
TEXT | — |
isin |
TEXT | — |
fin_quote_history — Close-price history downloaded from Yahoo (external source, not computed).
| Field | Type | Notes |
|---|---|---|
ticker |
TEXT | — |
date |
TEXT | — |
close |
REAL | — |
currency |
TEXT | — |
source |
TEXT | — |
fin_crypto_trades — Crypto trades. Generic exchange (Kraken today; extensible to other exchanges).
| Field | Type | Notes |
|---|---|---|
txid |
TEXT | PK |
date |
TEXT | — |
pair |
TEXT | — |
kind |
TEXT | — |
ordertype |
TEXT | — |
price |
REAL | — |
cost |
REAL | — |
fee |
REAL | — |
vol |
REAL | — |
quote |
TEXT | — |
exchange |
TEXT | — |
fin_account_aliases — Crosswalk: statement text → fin_source_accounts (per source).
| Field | Type | Notes |
|---|---|---|
source_account_id |
INTEGER | NOT NULL, → fin_source_accounts |
source |
TEXT | NOT NULL, PK |
text |
TEXT | NOT NULL, PK |
fin_source_accounts — DIMENSION of own accounts (bank|broker, IBAN, currency).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
institution |
TEXT | NOT NULL |
alias |
TEXT | — |
iban |
TEXT | — |
kind |
TEXT | — |
currency |
TEXT | — |
note |
TEXT | — |
fin_documents — Ingested financial documents (dedupe by sha).
| Field | Type | Notes |
|---|---|---|
sha |
text | PK |
source |
text | — |
kind |
text | — |
fin_invoices — Utility invoices (provider/period/amount/kwh).
| Field | Type | Notes |
|---|---|---|
id |
integer | PK |
provider |
text | — |
date |
text | — |
period_start |
text | — |
period_end |
text | — |
amount |
real | — |
kwh |
real | — |
source |
text | — |
sha |
text | — |
fin_manual_entries — One-off income/expense facts with no fin_movements row at all (e.g. a freelance invoice paid outside the tracked accounts, an estimated tax contribution) — a transaction-shaped fact pointed at a real category, generic enough for any such one-off, not modeled around any specific source.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
occurred_on |
TEXT | NOT NULL |
amount |
REAL | NOT NULL |
category_code |
INTEGER | NOT NULL, → fin_categories |
note |
TEXT | — |
fin_movements — UNIFIED bank cash book (every connected account/source merged; a source's internal envelope, if any, goes in source) — permanent raw import layer, unchanged by the double-entry ledger built downstream of it (fin_accounts/fin_transactions/fin_postings). Internal-transfer/broker classification is structural there now, not a stored code.
| Field | Type | Notes |
|---|---|---|
id |
integer | PK |
bank |
text | — |
date |
text | — |
description |
text | — |
amount |
real | — |
balance |
real | — |
source |
text | — |
sha |
text | — |
fin_broker_operations — Broker operations (BUY/SELL of securities), canonical (import_ops_broker.py).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | — |
bank |
TEXT | — |
operation |
TEXT | — |
value |
TEXT | — |
shares |
REAL | — |
unit_price |
REAL | — |
market |
TEXT | — |
amount_eur |
REAL | — |
source |
TEXT | — |
note |
TEXT | — |
fin_positions — Current portfolio positions (from connected broker/bank captures).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
broker |
text | — |
name |
text | — |
ticker |
text | — |
value |
real | — |
date |
text | — |
source |
text | — |
shares |
real | — |
fin_positions_hist — DERIVED: monthly valuation of the portfolio (today's shares × that month's close) — what draws the net-worth chart. calc_close is the monthly rollup of fin_quote_history (Yahoo's daily closes). Was calc_pos_hist: calc_ marks derived FIELDS, not a domain, and this is finance.
| Field | Type | Notes |
|---|---|---|
broker |
text | PK |
ticker |
text | PK |
month |
text | PK |
calc_value_eur |
real | — |
calc_close |
real | — |
symbol |
text | — |
fin_postings — The lines of each transaction: amount (in minor units — cents, never floats) against an account. The double entry itself; a transaction's postings always balance.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
transaction_id |
INTEGER | NOT NULL, → fin_transactions |
account_id |
INTEGER | NOT NULL, → fin_accounts |
amount_minor |
INTEGER | NOT NULL |
currency |
TEXT | NOT NULL |
note |
TEXT | — |
fin_rules — Concept→category classification rules.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
pattern |
TEXT | NOT NULL |
category_code |
INTEGER | NOT NULL, → fin_categories |
priority |
INTEGER | NOT NULL |
note |
TEXT | — |
fin_balances — Balance snapshots per account (available/booked) — from bank captures.
| Field | Type | Notes |
|---|---|---|
id |
integer | PK |
account |
text | — |
date |
text | — |
available |
real | — |
booked |
real | — |
source |
text | — |
category |
text | — |
fin_splits — Stock splits (ratio per date) to adjust historical share counts.
| Field | Type | Notes |
|---|---|---|
asset_id |
INTEGER | NOT NULL, → fin_assets, PK |
date |
TEXT | NOT NULL, PK |
ratio |
REAL | NOT NULL |
note |
TEXT | — |
fin_sweden_stocks — Sweden years: stock capital gains per year (K4). calc_result_sek=sale−cost.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
year |
INTEGER | — |
value |
TEXT | — |
shares |
REAL | — |
sale_sek |
REAL | — |
cost_sek |
REAL | — |
calc_result_sek |
REAL | — |
fin_sweden_income — Sweden years: ANNUAL tax summary from that jurisdiction's own tax authority. sek fundamental; calc_eur derived (×fx).
| Field | Type | Notes |
|---|---|---|
year |
INTEGER | PK |
gross_sek |
REAL | — |
tax_sek |
REAL | — |
net_sek |
REAL | — |
capital_sek |
REAL | — |
capital_tax_sek |
REAL | — |
pensionsgrundande_sek |
REAL | — |
fx_eur_sek |
REAL | — |
calc_gross_eur |
REAL | — |
calc_net_eur |
REAL | — |
fin_sweden_balances — Sweden years: balance snapshots (SEB/Avanza) at Dec-31.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | — |
institution |
TEXT | — |
account |
TEXT | — |
num |
TEXT | — |
balance_sek |
REAL | — |
fin_transactions — One row per economic EVENT of the ledger (date, description, origin). The amounts are not here: they live in its postings, which must sum to zero.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | NOT NULL |
description |
TEXT | — |
source |
TEXT | NOT NULL |
source_ref |
TEXT | NOT NULL |
sha |
TEXT | NOT NULL, UNIQUE |
fin_asset_aliases — Crosswalk: statement text → fin_assets (per source).
| Field | Type | Notes |
|---|---|---|
asset_id |
INTEGER | NOT NULL, → fin_assets |
source |
TEXT | NOT NULL, PK |
text |
TEXT | NOT NULL, PK |
fin_assets — DIMENSION of securities (name/ticker/isin/currency/market).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
name |
TEXT | NOT NULL |
ticker |
TEXT | — |
isin |
TEXT | — |
currency |
TEXT | — |
market |
TEXT | — |
TAXES
tax_es_income_tax — Spain IRPF returns (Modelo 100) — one row per fiscal year, dynamic casilla columns (c0xxx). Skatteverket lives in fin_sweden_*.
| Field | Type | Notes |
|---|---|---|
fiscal_year |
INTEGER | PK |
is_filed |
INTEGER | — |
filing_date |
TEXT | — |
region |
TEXT | — |
receipt_ref |
TEXT | — |
note |
TEXT | — |
c0041 |
REAL | — |
c0339 |
REAL | — |
c0340 |
REAL | — |
c0422 |
REAL | — |
c0423 |
REAL | — |
c0424 |
REAL | — |
c0429 |
REAL | — |
c0460 |
REAL | — |
c0435 |
REAL | — |
c0510 |
REAL | — |
c0595 |
REAL | — |
c0670 |
REAL | — |
c0025 |
REAL | — |
c0235 |
REAL | — |
c0386 |
REAL | — |
c0500 |
REAL | — |
c0505 |
REAL | — |
c0545 |
REAL | — |
c0546 |
REAL | — |
c0610 |
REAL | — |
tax_non_filings — Fiscal years with no filing (e.g. Andorra residency): country_code + reason.
| Field | Type | Notes |
|---|---|---|
fiscal_year |
INTEGER | PK |
country_code |
TEXT | NOT NULL |
reason |
TEXT | — |
note |
TEXT | — |
HEALTH
health_conditions — Diagnosed conditions, with date, current status and who diagnosed them.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
name |
TEXT | — |
diagnosis_date |
TEXT | — |
status |
TEXT | — |
doctor |
TEXT | — |
notes |
TEXT | — |
source |
TEXT | — |
health_documents — Index of health documents (reports, tests) — the path on disk, never the content.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | — |
title |
TEXT | — |
kind |
TEXT | — |
path |
TEXT | — |
notes |
TEXT | — |
source |
TEXT | — |
health_measurements — Time series of every measurement (weight, blood pressure, glucose…): metric says which, value/value2 hold it (two for pairs like systolic/diastolic).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | — |
metric |
TEXT | — |
value |
REAL | — |
value2 |
REAL | — |
note |
TEXT | — |
health_prescriptions — Prescribed medication: dose, schedule and whether it is still active.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | — |
medication |
TEXT | — |
dose |
TEXT | — |
schedule |
TEXT | — |
doctor |
TEXT | — |
is_active |
INTEGER | — |
notes |
TEXT | — |
source |
TEXT | — |
health_profile — Key/value with the basics of the health profile (blood type, allergies…). One row per fact, so adding one needs no migration.
| Field | Type | Notes |
|---|---|---|
key |
text | PK |
value |
text | — |
health_screen_time — Screen time per app and day, from Apple Screen Time. Seconds, per device.
| Field | Type | Notes |
|---|---|---|
date |
text | PK |
app |
text | PK |
seconds |
integer | — |
device |
text | — |
health_visits — Medical appointments: specialty, doctor, place and reason.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
date |
TEXT | — |
specialty |
TEXT | — |
doctor |
TEXT | — |
place |
TEXT | — |
reason |
TEXT | — |
status |
TEXT | — |
PEOPLE & GENEALOGY
people_docs — The person wiki documents (fiches): one markdown doc per slug, kind = person | collection | template | chronology. Formerly loose .md files; see scripts/person_docs.py.
| Field | Type | Notes |
|---|---|---|
slug |
TEXT | PK |
kind |
TEXT | NOT NULL |
title |
TEXT | — |
body_md |
TEXT | NOT NULL |
updated_at |
TEXT | NOT NULL |
people_email_stats — RAW pool: person↔addresses with mail counts (to curate → people_person_emails).
| Field | Type | Notes |
|---|---|---|
person |
TEXT | — |
kind |
TEXT | — |
addresses |
TEXT | — |
sent_by_me |
TEXT | — |
received |
TEXT | — |
total |
TEXT | — |
first_at |
TEXT | — |
last_at |
TEXT | — |
people_entities — RAW pool: entities (people/companies) extracted from mail.
| Field | Type | Notes |
|---|---|---|
candidate |
TEXT | PK |
normalized |
TEXT | — |
suggested_kind |
TEXT | — |
hit_count |
TEXT | — |
approx_size_bytes |
TEXT | — |
sources |
TEXT | — |
example_1 |
TEXT | — |
example_2 |
TEXT | — |
example_3 |
TEXT | — |
status |
TEXT | — |
people_faces — RAW pool: detected-face index (idx ↔ Immich person id).
| Field | Type | Notes |
|---|---|---|
idx |
TEXT | PK |
immich_person_id |
TEXT | PK |
people_immich_counts — RAW pool: Immich person id with photo count.
| Field | Type | Notes |
|---|---|---|
immich_person_id |
TEXT | PK |
photo_count |
TEXT | — |
people_name_contexts — RAW pool: name contexts.
| Field | Type | Notes |
|---|---|---|
context_id |
TEXT | PK |
term |
TEXT | — |
aliases |
TEXT | — |
kind |
TEXT | — |
canonical_context |
TEXT | — |
confidence |
TEXT | — |
classification_behavior |
TEXT | — |
notes |
TEXT | — |
people_person_emails — 1:N dimension — a person's email addresses.
| Field | Type | Notes |
|---|---|---|
person_id |
TEXT | PK, → people_persons |
email |
TEXT | PK |
people_person_faces — 1:N dimension — Immich faces (person_id) linked to a person.
| Field | Type | Notes |
|---|---|---|
person_id |
TEXT | PK, → people_persons |
immich_person_id |
TEXT | PK |
people_person_phones — 1:N dimension — a person's phone numbers.
| Field | Type | Notes |
|---|---|---|
person_id |
TEXT | PK, → people_persons |
phone |
TEXT | PK |
people_persons — MASTER of persons (family tree). Data: birth/death (DATE + city), profession. Aliases: main_alias + other_aliases. Tree: father_id/mother_id (self-FK). Derived: calc_main_email, calc_age (years, (death or today)−birth).
| Field | Type | Notes |
|---|---|---|
id |
TEXT | PK |
name |
TEXT | — |
kind |
TEXT | — |
source |
TEXT | — |
note |
TEXT | — |
calc_main_email |
TEXT | — |
birth_date |
DATE | — |
death_date |
DATE | — |
birth_city |
TEXT | — |
death_city |
TEXT | — |
profession |
TEXT | — |
calc_age |
INTEGER | — |
main_alias |
TEXT | — |
other_aliases |
TEXT | — |
father_id |
TEXT | → people_persons |
mother_id |
TEXT | → people_persons |
surname_1 |
TEXT | — |
surname_2 |
TEXT | — |
people_work_contexts — RAW pool: work contexts.
| Field | Type | Notes |
|---|---|---|
context_id |
TEXT | PK |
name |
TEXT | — |
aliases |
TEXT | — |
classification |
TEXT | — |
confidence |
TEXT | — |
default_document_target |
TEXT | — |
notes |
TEXT | — |
HOME (house + network)
home_devices — Network/home-automation devices (MAC, IP, kind, room).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
name |
TEXT | NOT NULL |
kind |
TEXT | — |
maker |
TEXT | — |
model |
TEXT | — |
mac |
TEXT | UNIQUE |
ip |
TEXT | — |
link |
TEXT | — |
room_id |
INTEGER | → home_rooms |
is_active |
INTEGER | — |
note |
TEXT | — |
home_plan_arcs — Arcs of a circle on the plan — a door's swing, mostly.
| Field | Type | Notes |
|---|---|---|
id |
TEXT | PK |
kind |
TEXT | NOT NULL |
cx |
REAL | — |
cy |
REAL | — |
r |
REAL | — |
start_deg |
REAL | — |
end_deg |
REAL | — |
room_id |
INTEGER | → home_rooms |
description |
TEXT | — |
home_plan_areas — Polygons filled on the plan (rooms and zones drawn as an area, not as walls).
| Field | Type | Notes |
|---|---|---|
id |
TEXT | PK |
kind |
TEXT | NOT NULL |
polygon |
TEXT | NOT NULL |
fill |
TEXT | — |
description |
TEXT | — |
home_plan_categories — DIMENSION of what a plan line can be (wall, door, window…), grouped by grp. Drives its colour and meaning.
| Field | Type | Notes |
|---|---|---|
code |
TEXT | PK |
slug |
TEXT | NOT NULL, UNIQUE |
name |
TEXT | NOT NULL |
grp |
TEXT | — |
home_plan_circles — Circles on the plan (columns, round elements).
| Field | Type | Notes |
|---|---|---|
id |
TEXT | PK |
kind |
TEXT | NOT NULL |
cx |
REAL | — |
cy |
REAL | — |
r |
REAL | — |
room_id |
INTEGER | → home_rooms |
description |
TEXT | — |
home_plan_hinges — Hinge points: where an arc pivots, i.e. which side a door opens from.
| Field | Type | Notes |
|---|---|---|
id |
TEXT | PK |
x |
REAL | NOT NULL |
y |
REAL | NOT NULL |
arc_id |
TEXT | → home_plan_arcs |
note |
TEXT | — |
home_plan_lines — Plan SEGMENTS between two nodes: walls, doors, windows… cat_code says what it is and layer which layer it is drawn on. calc_orientation is derived from its angle.
| Field | Type | Notes |
|---|---|---|
id |
TEXT | PK |
layer |
TEXT | NOT NULL |
node_a |
INTEGER | NOT NULL, → home_plan_nodes |
node_b |
INTEGER | NOT NULL, → home_plan_nodes |
cat_code |
TEXT | → home_plan_categories |
room_id |
INTEGER | → home_rooms |
description |
TEXT | — |
calc_orientation |
INTEGER | → home_plan_orientations |
home_plan_nodes — The plan's VERTICES (x/y in px). Everything else references these, so moving a corner moves every wall that touches it.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
x |
REAL | NOT NULL |
y |
REAL | NOT NULL |
home_plan_orientations — The plan's dominant directions (degrees), used to snap walls to the flat's real orthogonal grid. is_dominant marks the main one.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
degrees |
REAL | — |
name |
TEXT | — |
is_dominant |
INTEGER | — |
home_plan_points — Points/icons positioned on the plan (px).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
num |
INTEGER | UNIQUE |
label |
TEXT | — |
kind |
TEXT | — |
x |
REAL | — |
y |
REAL | — |
room_id |
INTEGER | → home_rooms |
device_id |
INTEGER | → home_devices |
home_property — The home (global plan/surface metadata).
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
development |
TEXT | — |
unit |
TEXT | — |
address |
TEXT | — |
usable_m2 |
REAL | — |
built_m2 |
REAL | — |
parking |
TEXT | — |
scale_px_m |
REAL | — |
note |
TEXT | — |
home_room_sides — Which lines make up each room's outline, in order. calc_rms is derived (fit against the orientation grid).
| Field | Type | Notes |
|---|---|---|
room_id |
INTEGER | → home_rooms, PK |
sort_order |
INTEGER | PK |
line_id |
TEXT | → home_plan_lines |
calc_rms |
REAL | — |
home_rooms — Rooms with plan polygon. plan_area_m2=FUNDAMENTAL (brochure); calc_area_m2/calc_area_delta_pct=derived.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
name |
TEXT | NOT NULL, UNIQUE |
kind |
TEXT | — |
polygon |
TEXT | — |
note |
TEXT | — |
calc_area_m2 |
REAL | — |
plan_area_m2 |
REAL | — |
calc_area_delta_pct |
REAL | — |
plan_name |
TEXT | — |
PHOTOS (incl. dating + Immich mirror)
photo_assets — The photo/video INVENTORY: one row per file, with its path, size, kind and the folder it came from. The base layer everything else in the domain points at.
| Field | Type | Notes |
|---|---|---|
rel_path |
TEXT | — |
name |
TEXT | — |
ext |
TEXT | — |
size |
INT | — |
kind |
TEXT | — |
category |
TEXT | — |
subfolder |
TEXT | — |
fb_album |
TEXT | — |
fb_album_name |
TEXT | — |
folder_year |
TEXT | — |
fs_created |
TEXT | — |
fs_modified |
TEXT | — |
name_date |
TEXT | — |
name_date_pattern |
TEXT | — |
exif_datetime |
TEXT | — |
exif_make |
TEXT | — |
exif_model |
TEXT | — |
has_camera_exif |
INT | — |
gps_lat |
REAL | — |
gps_lon |
REAL | — |
has_gps |
INT | — |
location_hint |
TEXT | — |
location_source |
TEXT | — |
width |
INT | — |
height |
INT | — |
megapixels |
REAL | — |
aspect |
REAL | — |
orientation |
TEXT | — |
is_panorama |
INT | — |
is_lowres |
INT | — |
is_hires |
INT | — |
is_screenshot |
INT | — |
is_whatsapp |
INT | — |
is_facebook |
INT | — |
media_source |
TEXT | — |
best_date |
TEXT | — |
best_date_source |
TEXT | — |
date_confidence |
TEXT | — |
year |
INT | — |
burst_id |
TEXT | — |
saturation |
REAL | — |
is_bw |
INT | — |
fb_id_year |
INT | — |
time_is_midnight |
INT | — |
immich_local_date |
TEXT | — |
immich_year |
INT | — |
person_names |
TEXT | — |
immich_albums |
TEXT | — |
immich_favorite |
INT | — |
sha256 |
TEXT | — |
photo_date_applied — The date actually APPLIED to each photo, with its source and confidence — and prev_date/prev_xmp_b64, the previous state, which is what makes it reversible.
| Field | Type | Notes |
|---|---|---|
asset_id |
TEXT | — |
rel_path |
TEXT | — |
prev_date |
TEXT | — |
prev_xmp_b64 |
TEXT | — |
new_date |
TEXT | — |
source |
TEXT | — |
confidence |
TEXT | — |
photo_dating_evidence — All the date EVIDENCE gathered per photo, each source in its own column (EXIF, Takeout, email, filename, Immich, filesystem…). Nothing decided here — this is the raw material for the rule of the minimum.
| Field | Type | Notes |
|---|---|---|
asset_id |
text | PK |
rel_path |
text | — |
immich_date |
text | — |
takeout_ts |
int | — |
email_date |
text | — |
exif_dt |
text | — |
name_date |
text | — |
fb_year |
int | — |
fs_min |
text | — |
person_cap |
text | — |
new_date |
text | — |
source |
text | — |
confidence |
text | — |
flag |
text | — |
photo_dedup — Duplicate detection by sha256: which copy is kept and which zone each one lives in.
| Field | Type | Notes |
|---|---|---|
status |
TEXT | — |
zone |
TEXT | — |
kind |
TEXT | — |
path |
TEXT | — |
bytes |
TEXT | — |
sha256 |
TEXT | — |
photo_email — Photos found as email attachments: sender, date and subject of the message that carried them — often the only surviving date for old ones.
| Field | Type | Notes |
|---|---|---|
saved_path |
TEXT | — |
sender |
TEXT | — |
date |
TIMESTAMP | — |
subject |
TEXT | — |
original_name |
TEXT | — |
bytes |
INTEGER | — |
sha12 |
TEXT | — |
maildir |
TEXT | — |
photo_fb_album_names — Facebook album id → its name. Kept apart because the export splits them.
| Field | Type | Notes |
|---|---|---|
fbid |
TEXT | — |
name |
TEXT | — |
photo_fb_albums — Facebook albums as exported: folder, id and representative photo.
| Field | Type | Notes |
|---|---|---|
idx |
TEXT | — |
folder |
TEXT | — |
fbid |
TEXT | — |
count |
TEXT | — |
rep |
TEXT | — |
w |
TEXT | — |
h |
TEXT | — |
mp |
TEXT | — |
guess |
TEXT | — |
photo_ocr — Text read from images (OCR). What lets a screenshot be searchable by its content.
| Field | Type | Notes |
|---|---|---|
file |
TEXT | — |
text |
TEXT | — |
photo_takeout_json — RAW layer of the Google Takeout sidecars (photoTakenTime, coordinates). Google's own claim, imported as-is and never edited.
| Field | Type | Notes |
|---|---|---|
title |
TEXT | — |
photoTakenTime_ts |
TEXT | — |
lat |
TEXT | — |
lon |
TEXT | — |
json_path |
TEXT | — |
photo_timeline — Each photo's assigned period/category, with confidence. The curated result of the dating.
| Field | Type | Notes |
|---|---|---|
asset_id |
TEXT | — |
rel_path |
TEXT | → photo_assets |
category |
TEXT | — |
confidence |
TEXT | — |
photo_triage — Photos assigned to a review album — the working queue of what still needs a human eye.
| Field | Type | Notes |
|---|---|---|
album |
TEXT | — |
asset_id |
TEXT | — |
rel_path |
TEXT | → photo_assets |
CHAT / MESSAGING (Matrix-normalised)
chat_events — Every message as an EVENT, the Matrix way: an append-only log rather than an editable table, so a chat's history is what happened, in order.
| Field | Type | Notes |
|---|---|---|
event_id |
TEXT | PK |
room_id |
TEXT | NOT NULL, → chat_rooms |
sender |
TEXT | NOT NULL |
origin_ts |
INTEGER | NOT NULL |
type |
TEXT | NOT NULL |
msgtype |
TEXT | — |
content |
TEXT | NOT NULL |
media_sha |
TEXT | — |
source |
TEXT | NOT NULL |
sha |
TEXT | NOT NULL |
chat_family_prompted — (no description yet)
| Field | Type | Notes |
|---|---|---|
room_id |
TEXT | PK |
prompted_at |
TEXT | — |
chat_rooms — The CONVERSATIONS (Matrix room model): one row per chat, individual or group. person_id links a room to a person in people_persons — the only place that link is stored.
| Field | Type | Notes |
|---|---|---|
room_id |
TEXT | PK |
platform |
TEXT | NOT NULL |
kind |
TEXT | NOT NULL |
name |
TEXT | — |
person_id |
INTEGER | — |
chat_senders — Who sends in each room. Kept apart from people_persons because a sender is a phone number until someone decides which person it is.
| Field | Type | Notes |
|---|---|---|
sender_id |
TEXT | PK |
platform |
TEXT | NOT NULL |
display_name |
TEXT | — |
person_id |
INTEGER | — |
INVENTORY
inv_inventory — Filesystem INVENTORY: one row per file with its path, size, dates and probable type. The raw scan the archive's curation works from.
| Field | Type | Notes |
|---|---|---|
absolute_path |
TEXT | PK |
root_path |
TEXT | — |
relative_path |
TEXT | — |
name |
TEXT | — |
extension |
TEXT | — |
size |
TEXT | — |
created_at |
TEXT | — |
modified_at |
TEXT | — |
probable_type |
TEXT | — |
mime_type |
TEXT | — |
sha256 |
TEXT | — |
hash_status |
TEXT | — |
width |
TEXT | — |
height |
TEXT | — |
status |
TEXT | — |
reason |
TEXT | — |
DECLOUD PROGRESS
decloud_areas — The decloudification areas (email, photos, calendar…), each with its weight and status. What the global percentage is computed from.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
area |
TEXT | NOT NULL, UNIQUE |
category |
TEXT | NOT NULL |
weight |
INTEGER | NOT NULL |
percent |
INTEGER | NOT NULL |
status |
TEXT | — |
sort_order |
INTEGER | NOT NULL |
decloud_snapshots — Historical snapshots of that percentage, to see the trend over time.
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
ts |
TEXT | NOT NULL |
global_pct |
REAL | NOT NULL |
areas_json |
TEXT | — |
DB EXPLORER (own bookkeeping)
dbexp_tables — DB Explorer's own map: row count per table and which apps own/read/write it. Recomputed from the manifests; it holds no data of yours.
| Field | Type | Notes |
|---|---|---|
table_name |
TEXT | PK |
calc_num_rows |
INTEGER | — |
calc_last_refreshed |
TEXT | — |
calc_read_apps |
TEXT | — |
calc_write_apps |
TEXT | — |
calc_own_apps |
TEXT | — |
calc_is_system |
INTEGER | NOT NULL |
META
_dominios — Legend: domain prefix → description and source DB.
| Field | Type | Notes |
|---|---|---|
prefijo |
TEXT | PK |
dominio |
TEXT | — |
source |
TEXT | — |
n_tablas |
INTEGER | — |
OTHER
_migrations — Which migrations each app has already applied. Prevents re-running one and makes an install idempotent.
| Field | Type | Notes |
|---|---|---|
app_slug |
TEXT | NOT NULL, PK |
migration_id |
TEXT | NOT NULL, PK |
applied_at |
TEXT | NOT NULL |
aplexp_bookmarks — (no description yet)
| Field | Type | Notes |
|---|---|---|
url |
TEXT | PK |
title |
TEXT | — |
folder |
TEXT | — |
added_at |
TEXT | — |
source |
TEXT | — |
aplexp_calendar — (no description yet)
| Field | Type | Notes |
|---|---|---|
uid |
TEXT | PK |
kind |
TEXT | — |
summary |
TEXT | — |
starts_at |
TEXT | — |
ends_at |
TEXT | — |
all_day |
INTEGER | — |
completed |
INTEGER | — |
location |
TEXT | — |
source |
TEXT | — |
aplexp_contacts — (no description yet)
| Field | Type | Notes |
|---|---|---|
uid |
TEXT | PK |
full_name |
TEXT | — |
org |
TEXT | — |
emails |
TEXT | — |
phones |
TEXT | — |
note |
TEXT | — |
source |
TEXT | — |
mail_matches — (no description yet)
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
rule_id |
INTEGER | NOT NULL, → mail_rules |
message_id |
TEXT | NOT NULL |
from_addr |
TEXT | — |
subject |
TEXT | — |
date_iso |
TEXT | — |
matched_at |
TEXT | NOT NULL |
mail_rules — (no description yet)
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
from_pattern |
TEXT | — |
subject_pattern |
TEXT | — |
label |
TEXT | NOT NULL |
priority |
INTEGER | NOT NULL |
created_at |
TEXT | NOT NULL |
created_by |
TEXT | — |
sync_applied_ops — Queue requests from the home server already applied on the workstation. The server replica cannot write the authoritative database, so it queues intent for the workstation to apply — this table stops one request being applied twice.
| Field | Type | Notes |
|---|---|---|
op_id |
TEXT | PK |
kind |
TEXT | — |
applied_at |
TEXT | — |
sys_journal_ops — (no description yet)
| Field | Type | Notes |
|---|---|---|
id |
INTEGER | PK |
op_run |
TEXT | NOT NULL |
seq |
INTEGER | NOT NULL |
ts |
TEXT | NOT NULL |
kind |
TEXT | NOT NULL |
target |
TEXT | — |
before |
TEXT | — |
after |
TEXT | — |
because |
TEXT | — |
status |
TEXT | NOT NULL |
sys_journal_runs — (no description yet)
| Field | Type | Notes |
|---|---|---|
op_run |
TEXT | PK |
ts |
TEXT | NOT NULL |
tool |
TEXT | — |
descr |
TEXT | — |
status |
TEXT | NOT NULL |