Files
Art-gallery/Documentation/DB_structure.md
T
Danila KhodjaefandCursor bf7db9b25e Add influence rework, image checkup, debug mode, and fetched paintings.
Support artist and movement influence links with web discovery, a developer checkup table with gallery/detail thumbnails, and debug image search with fix-it workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-20 10:29:43 +03:00

7.5 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/
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

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
thumbnail_path VARCHAR(500) Smaller variant for lists / 3D
wikipedia_title VARCHAR(300) Used by image fetcher
sort_order INTEGER

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).

Used by the 3D gallery exit panel: predecessors are artists of influenced_by_painting_id works; successors are artists of paintings influenced by this artists works (see API.md). Legacy table; new polymorphic links live in painting_influence_sources.

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.

Used by painting detail API (influencedBy). Painting-type rows also feed has_influence_links and hall navigation (with legacy painting_influences).

Indexes

  • artists(movement_id), artists(century)
  • paintings(artist_id), paintings(period_id)
  • 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.