Files
Art-gallery/Documentation/DB_structure.md
T
Danila KhodjaefandCursor 4eead54062 Add production deployment, photorealistic movement walls, and fix duplicate influence links.
Configure hosting for gallery.mysuperlab.netcraze.pro and LAN access, enhance movement gallery textures with period-appropriate painted materials, dedupe influenced-by API responses via painting_influence_sources, and refresh several painting image files.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 23:00:13 +03:00

9.9 KiB
Raw Blame History

Art Gallery — database structure

PostgreSQL schema for the virtual gallery. Canonical DDL is intended to live in db/schema.sql when checked in; this document describes the logical model either way.

Connection settings come from .env (see setup.md).

Overview

Item Typical value
Engine PostgreSQL 14+
Database Gallery
App user gallery
Time fields Integer years (negative = BCE)

Entity relationship

erDiagram
  historical_eras ||--o{ art_movements : contains
  art_movements ||--o{ artists : groups
  artists ||--o{ artist_periods : has
  artists ||--o{ paintings : created
  artist_periods ||--o{ paintings : groups
  paintings ||--o{ painting_influences : influenced_by
  paintings ||--o{ painting_influences : influences
  paintings ||--o{ painting_influence_sources : influenced_by
  artists ||--o{ painting_influence_sources : artist_source
  art_movements ||--o{ painting_influence_sources : movement_source

Tables

historical_eras

Broad chronological buckets (Ancient, Medieval, Renaissance, …).

Column Type Notes
id SERIAL PK
name VARCHAR(100) Display label
start_year, end_year INTEGER Inclusive range
start_definite, end_definite BOOLEAN false → render as gradient edge on timeline
description TEXT Tooltip / sidebar copy
sort_order INTEGER Display order

art_movements

Finer-grained styles (Impressionism, Cubism, Suprematism, …).

Column Type Notes
id SERIAL PK
name VARCHAR(150)
start_year, end_year INTEGER
start_definite, end_definite BOOLEAN Same visual semantics as eras
era_id FK → historical_eras Optional parent era
description TEXT
color VARCHAR(20) Hex colour for movement stream in the flow diagram

artists

Column Type Notes
id SERIAL PK
name VARCHAR(200)
birth_year, death_year INTEGER Nullable; used for timeline portrait placement
movement_id FK → art_movements Primary movement
portrait_path VARCHAR(500) Relative to data/images/; nullable after debug Clear
bio_short, bio_full TEXT Wikipedia lead section (npm run fetch-artist-bios)
wikipedia_title VARCHAR(300) Source page title
century INTEGER Rounded century bucket for seeding limits
checkup_checked BOOLEAN NOT NULL DEFAULT false Portrait reviewed in debug workflow (gold border on bio when true)
checkup_fixed BOOLEAN NOT NULL DEFAULT false Portrait replaced, cleared, or uploaded via debug

Applied by npm run migrate:artist-checkup-flags (db/migrate-artist-checkup-flags.sql).

artist_periods

Phases within an artists career (e.g. “Blue Period”, “Roman Period”).

Column Type Notes
id SERIAL PK
artist_id FK → artists ON DELETE CASCADE
name VARCHAR(200)
start_year, end_year INTEGER
description TEXT
sort_order INTEGER Wall order in 3D gallery

paintings

Column Type Notes
id SERIAL PK
artist_id FK → artists ON DELETE CASCADE
period_id FK → artist_periods Optional grouping
title VARCHAR(300)
year, year_end INTEGER Creation date(s)
description TEXT
image_path VARCHAR(500) Full-size local file; nullable after debug Clear
thumbnail_path VARCHAR(500) Smaller variant for lists / 3D; nullable after Clear
wikipedia_title VARCHAR(300) Used by image fetcher
sort_order INTEGER
checkup_checked BOOLEAN NOT NULL DEFAULT false Reviewed in image checkup workflow (UI label: Reviewed)
checkup_fixed BOOLEAN NOT NULL DEFAULT false Image corrected, cleared, or uploaded via checkup / debug

When checkup_fixed is true, checkup_checked is set automatically and cannot be cleared until Fixed is off. A cleared painting (image_path and thumbnail_path both null, checkup_fixed true) is shown as an empty frame in detail view and is not refetched on demand.

Applied by npm run migrate:checkup-flags (db/migrate-checkup-flags.sql).

painting_annotations

Short art-history notes shown on painting detail (PaintingAnnotations.tsx).

Column Type Notes
id SERIAL PK
painting_id FK → paintings ON DELETE CASCADE
label VARCHAR(80) Optional short heading (e.g. figure name)
body TEXT Note text
category VARCHAR(30) Default subject; also technique, context, symbolism, etc.
pos_x, pos_y NUMERIC(5,2) Optional marker position on image (percent 0100)
source_author VARCHAR(200) e.g. Gombrich, Met catalog
source VARCHAR(500) Citation label
source_url VARCHAR(500) Reference link
sort_order INTEGER Display order within the painting
confidence VARCHAR(20) Default curated; Wikipedia pass uses wikipedia

Applied by npm run migrate:painting-annotations (db/migrate-painting-annotations.sql). Load data with npm run update-painting-annotations (curated entries in scripts/painting-annotations-data.js; add --wikipedia for intro sentences from each works wikipedia_title).

painting_influences

Directed edges: this painting was influenced by that painting.

Column Type Notes
id SERIAL PK
painting_id FK → paintings The work being explained
influenced_by_painting_id FK → paintings The earlier / source work
notes TEXT Curator summary
source VARCHAR(500) General attribution
aspects TEXT What was borrowed (composition, colour, …)
quote TEXT Short citation
source_author VARCHAR(200) e.g. Gombrich, Janson
source_url VARCHAR(500) Reference link

Unique constraint on (painting_id, influenced_by_painting_id).

Legacy mirror table. npm run update-influences still inserts painting-to-painting rows here when curating data. The same edges are copied into painting_influence_sources. The REST API does not read this table for painting detail or hall navigation — use painting_influence_sources as the source of truth for display.

painting_influence_sources

Polymorphic influence links: this painting was influenced by a painting, artist, or movement.

Column Type Notes
id SERIAL PK
painting_id FK → paintings The work being explained
source_type VARCHAR(20) painting, artist, or movement
source_painting_id FK → paintings When source_type = painting
source_artist_id FK → artists When source_type = artist
source_movement_id FK → art_movements When source_type = movement
period_note VARCHAR(240) Human-readable period label
period_start_year INTEGER Optional span start
period_end_year INTEGER Optional span end
notes TEXT Curator summary
source VARCHAR(500) General attribution
aspects TEXT What was borrowed
quote TEXT Short citation
source_author VARCHAR(200) e.g. Gombrich, Janson
source_url VARCHAR(500) Reference link
discovered_via VARCHAR(120) e.g. wikipedia, wikidata, web:metmuseum.org
confidence VARCHAR(20) curated (default) or discovered

Unique index on (painting_id, source_type, source_painting_id, source_artist_id, source_movement_id) with COALESCE for null FKs.

Canonical influence store. Used by all API influence queries: painting detail (influencedBy, influenced), has_influence_links, and artist hall navigation (predecessors / successors). Legacy painting_influences rows are backfilled here on migration; new curated painting edges are written to both tables by update-influences.

Indexes

  • artists(movement_id), artists(century)
  • paintings(artist_id), paintings(period_id), paintings(checkup_checked), paintings(checkup_fixed)
  • artists(checkup_checked), artists(checkup_fixed)
  • art_movements(era_id), art_movements(start_year, end_year)
  • painting_influences(painting_id), painting_influences(influenced_by_painting_id)
  • painting_influence_sources(painting_id), painting_influence_sources(source_artist_id), painting_influence_sources(source_movement_id)

First-time setup

The gallery database user needs CREATE on schema public for migrations. If tables cannot be created, run admin grants as PostgreSQL superuser before npm run migrate:

GRANT CREATE ON SCHEMA public TO gallery;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO gallery;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO gallery;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO gallery;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO gallery;

Then:

npm run migrate
npm run seed
npm run fetch-artist-bios
npm run expand-catalog

Data conventions

  • Year zero is not used; BCE years are negative integers.
  • Image paths are relative to IMAGE_DIR (default ./data/images), e.g. portraits/Claude_Monet.jpg, paintings/thumbs/Raphael_The_School_of_Athens_thumb.jpg.
  • Seeding cap: curated ingest targets at most ~100 artists per century to keep the catalog manageable.
  • Catalog expansion: scripts/famous-paintings-data.js plus npm run expand-catalog raises thin artist catalogs to at least six notable paintings (MIN_PAINTINGS, default 6).
  • Biographies: bio_short and bio_full are populated by npm run fetch-artist-bios from English Wikipedia lead sections; wikipedia_title on the artist row is the source article.