-
Notifications
You must be signed in to change notification settings - Fork 0
feat(backend): Satt opp GraphQL-backend med PostgreSQL #4
Merged
+2,248
−0
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Kopier denne fila til .env og fyll inn verdiene. .env skal ALDRI committes. | ||
|
|
||
| # Adressen til databasen: postgres://bruker:passord@vert:port/databasenavn | ||
| DATABASE_URL=postgres://localhost:5432/framerate | ||
|
|
||
| # Porten GraphQL-serveren lytter på | ||
| PORT=3001 | ||
|
|
||
| # TMDB "API Read Access Token" (lang tekst), fra https://www.themoviedb.org/settings/api | ||
| # Brukes av importskriptet og av serveren (filmdetaljer). Sendes aldri til nettleseren. | ||
| TMDB_READ_TOKEN= | ||
|
|
||
| # Hvor mange filmer importskriptet henter (maks 10000) | ||
| IMPORT_MOVIE_COUNT=5000 | ||
|
|
||
| # Sett til "production" på VM-en, så skjuler Apollo interne feildetaljer | ||
| NODE_ENV=development |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| node_modules | ||
| .env | ||
| *.log |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| # Frame Rate – backend | ||
|
|
||
| GraphQL-server (Apollo Server) med egen PostgreSQL-database. | ||
|
|
||
| - **Søk, filtrering og sortering** går mot vår egen database. Filmene importeres én gang fra TMDB med et skript, og vi lagrer bare feltene vi trenger til dette (tittel, dato, plakat, popularitet, sjangre). | ||
| - **Detaljer** (beskrivelse, regissør, spilletid, aldersgrense) lagres ikke. De hentes fra TMDB med film-ID-en når detaljsiden ber om `details`, slik [TMDB anbefaler](https://developer.themoviedb.org/docs/search-and-query-for-details). Serveren husker svaret i 24 timer. | ||
| - **Anmeldelser, likes og lister** er våre egne data og lagres bare i databasen. | ||
|
|
||
| ## Kom i gang | ||
|
|
||
| Krever Node 24.6+ og PostgreSQL. | ||
|
|
||
| ```bash | ||
| cd backend | ||
| npm install | ||
| cp .env.example .env # fyll inn DATABASE_URL og TMDB_READ_TOKEN | ||
| createdb framerate # lager en tom database (første gang) | ||
| npm run db:migrate # lager tabellene | ||
| npm run import:movies # henter ~5000 filmer fra TMDB (under ett minutt) | ||
| npm run dev # starter serveren på http://localhost:3001 | ||
| ``` | ||
|
|
||
| Åpne http://localhost:3001 i nettleseren for å teste spørringer i Apollo Sandbox. | ||
|
|
||
| ## Skript | ||
|
|
||
| | Kommando | Hva den gjør | | ||
| | ----------------------- | -------------------------------------------------------------------------- | | ||
| | `npm run dev` | Starter serveren og restarter den når du lagrer en fil | | ||
| | `npm start` | Starter serveren (bruk denne på VM-en) | | ||
| | `npm run typecheck` | Sjekker TypeScript-typer | | ||
| | `npm run db:migrate` | Lager/oppdaterer tabellene fra `db/schema.sql`. Trygt å kjøre flere ganger | | ||
| | `npm run import:movies` | Henter filmer fra TMDB. Kan kjøres på nytt uten duplikater | | ||
|
|
||
| ## Eksempel | ||
|
|
||
| ```graphql | ||
| query { | ||
| searchMovies(search: "star", genreIds: [878], yearFrom: 1970, sort: RATING_DESC, limit: 20, offset: 0) { | ||
| totalCount | ||
| movies { | ||
| id | ||
| title | ||
| releaseYear | ||
| posterPath | ||
| averageRating | ||
| genres { name } | ||
| } | ||
| } | ||
| movie(id: 11) { | ||
| title | ||
| averageRating | ||
| details { # hentes fra TMDB, bruk bare på detaljsiden | ||
| overview | ||
| director | ||
| runtime | ||
| ageRating | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Plakater: `https://image.tmdb.org/t/p/w185{posterPath}` (liste) eller `w500` (detaljside). | ||
|
|
||
| ## Mappestruktur | ||
|
|
||
| ``` | ||
| backend/ | ||
| ├── db/schema.sql Tabeller: movies, genres, movie_genres, users, reviews, review_likes, saved_movies | ||
| ├── scripts/migrate.ts Kjører schema.sql | ||
| ├── scripts/import-movies.ts Engangsimport fra TMDB | ||
| └── src/ | ||
| ├── index.ts Starter serveren | ||
| ├── schema.ts GraphQL-typene (hva API-et tilbyr) | ||
| ├── resolvers.ts Henter data fra databasen | ||
| ├── tmdb.ts Kall mot TMDB (filmdetaljer og import) | ||
| └── db.ts Tilkobling til PostgreSQL | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| -- Databaseskjema for Frame Rate (PostgreSQL). | ||
| -- Kjøres med `npm run db:migrate`. Trygt å kjøre flere ganger (IF NOT EXISTS). | ||
|
|
||
| -- pg_trgm gjør at søk med ILIKE '%tekst%' kan bruke en indeks. | ||
| CREATE EXTENSION IF NOT EXISTS pg_trgm; | ||
|
|
||
| CREATE TABLE IF NOT EXISTS genres ( | ||
| id INTEGER PRIMARY KEY, -- TMDB sin sjanger-ID | ||
| name TEXT NOT NULL | ||
| ); | ||
|
|
||
| -- Bare feltene vi trenger for å søke, filtrere, sortere og vise filmkort. | ||
| -- Detaljer (beskrivelse, regissør, spilletid, aldersgrense ...) hentes fra TMDB | ||
| -- med film-ID-en når detaljsiden åpnes, se src/tmdb.ts. | ||
| CREATE TABLE IF NOT EXISTS movies ( | ||
| id INTEGER PRIMARY KEY, -- TMDB sin film-ID, brukes til å hente detaljer | ||
| title TEXT NOT NULL, | ||
| release_date DATE, | ||
| release_year INTEGER GENERATED ALWAYS AS (EXTRACT(YEAR FROM release_date)::INTEGER) STORED, | ||
| poster_path TEXT, | ||
| popularity REAL NOT NULL DEFAULT 0, | ||
| -- Regnes ut fra våre egne anmeldelser, ikke fra TMDB | ||
| average_rating NUMERIC(3, 2), | ||
| review_count INTEGER NOT NULL DEFAULT 0 | ||
| ); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS movies_title_trgm_idx ON movies USING gin (title gin_trgm_ops); | ||
| CREATE INDEX IF NOT EXISTS movies_release_year_idx ON movies (release_year); | ||
| CREATE INDEX IF NOT EXISTS movies_popularity_idx ON movies (popularity DESC); | ||
| CREATE INDEX IF NOT EXISTS movies_average_rating_idx ON movies (average_rating DESC NULLS LAST); | ||
|
|
||
| CREATE TABLE IF NOT EXISTS movie_genres ( | ||
| movie_id INTEGER NOT NULL REFERENCES movies (id) ON DELETE CASCADE, | ||
| genre_id INTEGER NOT NULL REFERENCES genres (id) ON DELETE CASCADE, | ||
| PRIMARY KEY (movie_id, genre_id) | ||
| ); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS movie_genres_genre_idx ON movie_genres (genre_id); | ||
|
|
||
| -- Brukere: innlogging bygges senere, men tabellen finnes så anmeldelser og lister kan peke hit. | ||
| CREATE TABLE IF NOT EXISTS users ( | ||
| id SERIAL PRIMARY KEY, | ||
| username TEXT NOT NULL UNIQUE, | ||
| password_hash TEXT NOT NULL, | ||
| avatar_url TEXT, -- profilbilde, null = standardbilde | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT now() | ||
| ); | ||
|
|
||
| CREATE TABLE IF NOT EXISTS reviews ( | ||
| id SERIAL PRIMARY KEY, | ||
| user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, | ||
| movie_id INTEGER NOT NULL REFERENCES movies (id) ON DELETE CASCADE, | ||
| rating SMALLINT NOT NULL CHECK (rating BETWEEN 1 AND 6), -- terningkast | ||
| text TEXT CHECK (char_length(text) <= 2000), | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT now(), | ||
| updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), | ||
| UNIQUE (user_id, movie_id) -- én anmeldelse per bruker per film | ||
| ); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS reviews_movie_idx ON reviews (movie_id, created_at DESC); | ||
| CREATE INDEX IF NOT EXISTS reviews_user_idx ON reviews (user_id, created_at DESC); | ||
|
|
||
| -- "Liker" på anmeldelser. Én like per bruker per anmeldelse. | ||
| CREATE TABLE IF NOT EXISTS review_likes ( | ||
| user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, | ||
| review_id INTEGER NOT NULL REFERENCES reviews (id) ON DELETE CASCADE, | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT now(), | ||
| PRIMARY KEY (user_id, review_id) | ||
| ); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS review_likes_review_idx ON review_likes (review_id); | ||
|
|
||
| DO $$ | ||
| BEGIN | ||
| CREATE TYPE list_type AS ENUM ('WATCHLIST', 'SEEN', 'FAVORITE'); | ||
| EXCEPTION | ||
| WHEN duplicate_object THEN NULL; | ||
| END | ||
| $$; | ||
|
|
||
| -- Én tabell for alle tre listene; list_type sier hvilken liste filmen ligger i. | ||
| CREATE TABLE IF NOT EXISTS saved_movies ( | ||
| user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, | ||
| movie_id INTEGER NOT NULL REFERENCES movies (id) ON DELETE CASCADE, | ||
| list_type list_type NOT NULL, | ||
| added_at TIMESTAMPTZ NOT NULL DEFAULT now(), | ||
| PRIMARY KEY (user_id, movie_id, list_type) | ||
| ); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS saved_movies_user_list_idx ON saved_movies (user_id, list_type, added_at DESC); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.