From 958e50738a27043caa8c4fb751950233eff454d9 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 6 Oct 2026 19:40:12 +0200 Subject: [PATCH] Added multiple folders & files. Added migration folders --- .gitignore | 10 +++ package-lock.json | 32 +--------- package.json | 2 +- server/src/database/connection.ts | 0 server/src/database/migrations/schema.sql | 76 +++++++++++++++++++++++ server/src/database/migrations/seed.sql | 30 +++++++++ server/src/graphQL/typeDefs.ts | 65 +++++++++++++++++++ server/tsconfig.json | 0 8 files changed, 183 insertions(+), 32 deletions(-) create mode 100644 server/src/database/connection.ts create mode 100644 server/src/database/migrations/schema.sql create mode 100644 server/src/database/migrations/seed.sql create mode 100644 server/src/graphQL/typeDefs.ts create mode 100644 server/tsconfig.json diff --git a/.gitignore b/.gitignore index a547bf3..35cf3a3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,13 @@ dist-ssr *.njsproj *.sln *.sw? + +# Backend local dataset & media caches (ETL) +server/data/raw/* +!server/data/raw/.gitkeep + +server/data/covers/* +!server/data/covers/.gitkeep + +# Environment variables +.env diff --git a/package-lock.json b/package-lock.json index 83f7220..8bf91f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/node": "^24.13.3", - "@types/react": "^19.2.18", + "@types/react": "^19.3.0", "@types/react-dom": "^19.2.7", "@vitejs/plugin-react": "^6.1.1", "eslint": "^10.10.0", @@ -678,9 +678,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -698,9 +695,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -718,9 +712,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -738,9 +729,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -758,9 +746,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -778,9 +763,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2033,9 +2015,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2057,9 +2036,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2081,9 +2057,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2105,9 +2078,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ diff --git a/package.json b/package.json index 1d42c60..635251b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/node": "^24.13.3", - "@types/react": "^19.2.18", + "@types/react": "^19.3.0", "@types/react-dom": "^19.2.7", "@vitejs/plugin-react": "^6.1.1", "eslint": "^10.10.0", diff --git a/server/src/database/connection.ts b/server/src/database/connection.ts new file mode 100644 index 0000000..e69de29 diff --git a/server/src/database/migrations/schema.sql b/server/src/database/migrations/schema.sql new file mode 100644 index 0000000..c266251 --- /dev/null +++ b/server/src/database/migrations/schema.sql @@ -0,0 +1,76 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS pg_trgm; + +-- album-tabell +CREATE TABLE IF NOT EXISTS albums ( + id VARCHAR(64) PRIMARY KEY, -- MusicBrainz release-group MBID + title VARCHAR(255) NOT NULL, + artist VARCHAR(255) NOT NULL, + release_year INT NOT NULL, + cover_url TEXT, +); + +-- sjangre (mange-til-mange relasjon) +CREATE TABLE IF NOT EXISTS genres ( + id SERIAL PRIMARY KEY, + name VARCHAR(100) UNIQUE NOT NULL +); + +CREATE TABLE IF NOT EXISTS album_genres ( + album_id VARCHAR(64) REFERENCES albums(id) ON DELETE CASCADE, + genre_id INT REFERENCES genres(id) ON DELETE CASCADE, + PRIMARY KEY (album_id, genre_id) +); + +-- tracks-tabell (en-til-mange: et album har mange spor) +CREATE TABLE IF NOT EXISTS tracks ( + id SERIAL PRIMARY KEY, + album_id VARCHAR(64) NOT NULL REFERENCES albums(id) ON DELETE CASCADE, + position INT NOT NULL, + title VARCHAR(255) NOT NULL, + duration VARCHAR(50) NOT NULL, -- f.eks. "3:45" eller millisekunder +); + +-- reviews and ratings (for UI innhold) +CREATE TABLE IF NOT EXISTS reviews ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + album_id VARCHAR(64) NOT NULL REFERENCES albums(id) ON DELETE CASCADE, + user_name VARCHAR(100) NOT NULL DEFAULT 'Anonym', + rating INT NOT NULL CHECK (rating >= 1 AND rating <= 5), + comment TEXT, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +-- for collections/favs for brukere +DO $$ BEGIN + CREATE TYPE collection_type_enum AS ENUM ('favorites', 'has_cd', 'wants_cd'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +CREATE TABLE IF NOT EXISTS user_collections ( + user_id VARCHAR(255) NOT NULL, + album_id VARCHAR(64) REFERENCES albums(id) ON DELETE CASCADE, + collection_type collection_type_enum NOT NULL, + added_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (user_id, album_id, collection_type) +); + + +-- INDEKSER FOR HØY YTELSE (Søk, filtrering, sortering og paginering) + +-- Indeks for tekstsøk på tittel og artist +CREATE INDEX IF NOT EXISTS idx_albums_title_trgm ON albums USING gin (title gin_trgm_ops); +CREATE INDEX IF NOT EXISTS idx_albums_artist_trgm ON albums USING gin (artist gin_trgm_ops); + +-- Indeks for sortering på utgivelsesår +CREATE INDEX IF NOT EXISTS idx_albums_decade ON albums ((release_year / 10 * 10)); + +-- Indeks for hurtigoppslag på spor per album +CREATE INDEX IF NOT EXISTS idx_tracks_album_id ON tracks(album_id); + +-- Indeks for anmeldelser per album +CREATE INDEX IF NOT EXISTS idx_reviews_album_id ON reviews(album_id); + + + diff --git a/server/src/database/migrations/seed.sql b/server/src/database/migrations/seed.sql new file mode 100644 index 0000000..4136720 --- /dev/null +++ b/server/src/database/migrations/seed.sql @@ -0,0 +1,30 @@ +-- Labels +INSERT INTO labels (id, name) VALUES (1, 'Columbia Records'), (2, 'Harvest Records') ON CONFLICT DO NOTHING; + +-- Albumer +INSERT INTO albums (id, title, artist, release_year, cover_path, label_id) VALUES +('mbid-1', 'Abbey Road', 'The Beatles', 1969, '/covers/abbey-road.webp', 1), +('mbid-2', 'The Dark Side of the Moon', 'Pink Floyd', 1973, '/covers/dark-side.webp', 2), +('mbid-3', 'Thriller', 'Michael Jackson', 1982, '/covers/thriller.webp', 1), +('mbid-4', 'Back in Black', 'AC/DC', 1980, '/covers/back-in-black.webp', 1) +ON CONFLICT DO NOTHING; + +-- Sjangre +INSERT INTO genres (id, name) VALUES (1, 'Rock'), (2, 'Progressive Rock'), (3, 'Pop') ON CONFLICT DO NOTHING; + +-- Koble albumer og sjangre +INSERT INTO album_genres (album_id, genre_id) VALUES +('mbid-1', 1), +('mbid-2', 1), +('mbid-2', 2), +('mbid-3', 3), +('mbid-4', 1) +ON CONFLICT DO NOTHING; + +-- Sporliste (Task 6) +INSERT INTO tracks (album_id, title, duration_ms, track_number) VALUES +('mbid-1', 'Come Together', 259000, 1), +('mbid-1', 'Something', 182000, 2), +('mbid-2', 'Speak to Me', 67000, 1), +('mbid-2', 'Breathe', 163000, 2) +ON CONFLICT DO NOTHING; \ No newline at end of file diff --git a/server/src/graphQL/typeDefs.ts b/server/src/graphQL/typeDefs.ts new file mode 100644 index 0000000..d2e8532 --- /dev/null +++ b/server/src/graphQL/typeDefs.ts @@ -0,0 +1,65 @@ +export const typeDefs = `#graphql + type Label { + id: ID! + name: String! + } + + type Track { + id: ID! + title: String! + durationMs: Int + trackNumber: Int! + } + + type Album { + id: ID! + title: String! + artist: String! + releaseYear: Int! + coverPath: String + label: Label + genres: [String!]! + tracks: [Track!]! + } + + type PageInfo { + endCursor: String + hasNextPage: Boolean! + } + + type AlbumEdge { + cursor: String! + node: Album! + } + + type AlbumConnection { + edges: [AlbumEdge!]! + pageInfo: PageInfo! + totalCount: Int! + } + + enum SortOption { + TITLE_ASC + TITLE_DESC + YEAR_ASC + YEAR_DESC + } + + type Query { + # Task 2 & 5: Paginert søk, filtrering på sjanger, tiår og sortering + albums( + search: String + genre: String + decade: Int + sortBy: SortOption + first: Int = 10 + after: String + ): AlbumConnection! + + # Task 6: Detaljspørring for enkeltalbum + album(id: ID!): Album + + # Hente alle sjangre for filter-dropdown i frontend + genres: [String!]! + } +`; \ No newline at end of file diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..e69de29