Data Model: Migracions Recents
Aquest document descriu les migracions de base de dades afegides recentment i els canvis corresponents al model de dades.
Migració V45: DanceSong Join Entity
Fitxer: V45__create_dance_song_join_table.sql
Data: Gener 2026
Canvi
Transforma la relació @ManyToMany entre Dance i Song en una join entity DanceSong amb camps addicionals.
Esquema
CREATE TABLE dance_songs (
id BIGSERIAL PRIMARY KEY,
dance_id BIGINT NOT NULL REFERENCES dances(id) ON DELETE CASCADE,
song_id BIGINT NOT NULL REFERENCES songs(id) ON DELETE CASCADE,
role VARCHAR(20) NOT NULL DEFAULT 'PRIMARY',
sort_order INT NOT NULL DEFAULT 0,
notes TEXT,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE(dance_id, song_id)
);
Camps nous
| Camp | Tipus | Descripció |
|---|---|---|
role | PRIMARY | ALTERNATIVE | Indica si és la cançó principal o una alternativa |
sort_order | INT | Ordre de visualització |
notes | TEXT | Notes sobre l'associació |
Regla de negoci
Si un ball té cançons associades, exactament una ha de tenir
role = PRIMARY.
Validat a DanceService.validateSongsHaveExactlyOnePrimary().
DTOs afectats
// DanceDto.songs ara conté:
record DanceSongDto(
Long id,
Long songId,
String songTitle,
String songArtist,
DanceSongRole role,
Integer sortOrder,
String notes
)
// CreateDanceRequest.songs ara espera:
record DanceSongRequest(
Long songId,
DanceSongRole role, // Obligatori
Integer sortOrder,
String notes
)
Migració V46: LineDanceSpec Model
Fitxer: V46__create_line_dance_spec_tables.sql
Data: Gener 2026
Canvi
Afegeix suport per emmagatzemar l'especificació de passos d'un ball de línia.
Esquema
-- Especificació principal (1:1 amb Dance)
CREATE TABLE line_dance_specs (
dance_id BIGINT PRIMARY KEY REFERENCES dances(id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
sequence_completeness VARCHAR(20) NOT NULL DEFAULT 'PARTIAL',
source_text TEXT,
notes TEXT,
created_by VARCHAR(255),
last_modified_by VARCHAR(255),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
-- Components (passos individuals)
CREATE TABLE line_dance_components (
id BIGSERIAL PRIMARY KEY,
spec_dance_id BIGINT NOT NULL REFERENCES line_dance_specs(dance_id) ON DELETE CASCADE,
component_type VARCHAR(20) NOT NULL,
code VARCHAR(10) NOT NULL,
counts INT,
label VARCHAR(100),
sort_order INT NOT NULL DEFAULT 0,
UNIQUE(spec_dance_id, code)
);
-- Seqüència (ordre d'execució)
CREATE TABLE line_dance_sequence_items (
id BIGSERIAL PRIMARY KEY,
spec_dance_id BIGINT NOT NULL REFERENCES line_dance_specs(dance_id) ON DELETE CASCADE,
order_index INT NOT NULL,
component_id BIGINT REFERENCES line_dance_components(id) ON DELETE SET NULL,
restart BOOLEAN NOT NULL DEFAULT FALSE,
note TEXT
);
Relacions
Dance (1) ←──── (1) LineDanceSpec
│
├──→ (N) LineDanceComponents
│
└──→ (N) LineDanceSequenceItems ───→ (1) Component
Enums
| Enum | Valors |
|---|---|
LineDanceSpecStatus | DRAFT, PUBLISHED |
SequenceCompleteness | NONE, PARTIAL, FULL |
ComponentType | STEP, TURN, TAG, BRIDGE, OTHER |
Endpoints nous
| Mètode | Endpoint | Descripció |
|---|---|---|
| GET | /api/dances/{id}/spec | Obtenir especificació |
| PUT | /api/dances/{id}/spec | Crear/actualitzar spec |
| PUT | /api/dances/{id}/spec/components | Reemplaçar components |
| PUT | /api/dances/{id}/spec/sequence | Reemplaçar seqüència |
Tots requereixen rol ADMIN.
DTO principal
record LineDanceSpecDto(
Long danceId,
String danceName,
LineDanceSpecStatus status,
SequenceCompleteness sequenceCompleteness,
String sourceText,
String notes,
List<LineDanceComponentDto> components,
List<LineDanceSequenceItemDto> sequence,
String createdBy,
String lastModifiedBy,
Instant createdAt,
Instant updatedAt
)
Diagrama ER actualitzat
┌─────────────┐ ┌─────────────────┐ ┌───────────┐
│ dances │──1:N──│ dance_songs │──N:1──│ songs │
└─────────────┘ └─────────────────┘ └───────────┘
│ │
│ ├── role (PRIMARY/ALTERNATIVE)
│ ├── sort_order
│ └── notes
│
│ 1:1
▼
┌─────────────────────┐
│ line_dance_specs │
├─────────────────────┤
│ dance_id (PK, FK) │
│ status │
│ sequence_complete. │
│ source_text │
│ notes │
└─────────────────────┘
│
├── 1:N ──┐
│ ▼
│ ┌───────────────────────┐
│ │ line_dance_components │
│ ├───────────────────────┤
│ │ id (PK) │
│ │ spec_dance_id (FK) │
│ │ type, code, counts │
│ │ label, sort_order │
│ └───────────────────────┘
│ │
│ │ N:1
│ ▼
└── 1:N ──┐ ↑
▼ │
┌──────────────────────────┐
│ line_dance_sequence_items │
├──────────────────────────┤
│ id (PK) │
│ spec_dance_id (FK) │
│ order_index │
│ component_id (FK) ────────┘
│ restart (boolean) │
│ note │
└──────────────────────────┘