Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9b60348
oppgave/graphql-backend
Oct 6, 2026
6ad42be
Merge pull request #12 from IT2810-H26/oppgave/graphql-backend
leaht Oct 6, 2026
072f3b2
Laget databaseskjema
leaht Oct 6, 2026
89b5ffd
Merge pull request #16 from IT2810-H26/oppgave/db-skjema
leaht Oct 6, 2026
253ab06
Påbegynn GraphQL-query for vinliste
Oct 7, 2026
ded991f
Merge pull request #19 from IT2810-H26/oppgave/wine-list-query
celinhag Oct 7, 2026
5f8674b
oppgave/Ignorer backend/data
leaht Oct 7, 2026
534376b
Merge branch 'dev' of git.ntnu.no:IT2810-H26/T01-Project-2 into oppga…
leaht Oct 7, 2026
81425df
Flyttet server til backend + skrevet importscript
leaht Oct 7, 2026
9398d44
Merge pull request #20 from IT2810-H26/oppgave/importskript
leaht Oct 7, 2026
38f58ca
Oppdater navn i backend/package-lock.json etter flytting til backend
Oct 7, 2026
d396d30
Merge pull request #22 from IT2810-H26/chore/oppdater-lockfil
sofiesty Oct 7, 2026
419c25d
Sett opp Apollo Client og legg til .env.example (#23)
Oct 7, 2026
881d3de
Merge pull request #24 from IT2810-H26/oppgave/apollo-client
sofiesty Oct 7, 2026
2da867c
Fjern Vite-mal og legg til enkel styling for vinkatalogen (#18)
Oct 7, 2026
cb28b38
Hent viner fra backend i vinkatalogen (#18)
Oct 7, 2026
5aae2c5
Merge pull request #25 from IT2810-H26/feature/vinkatalog
sofiesty Oct 7, 2026
35cd515
Dokumenter PostgreSQL-oppsett på VM (#<issue-number>)
Oct 7, 2026
1e8af71
Merge pull request #26 from IT2810-H26/oppgave/postgres-vm
sofiesty Oct 7, 2026
d3cd696
oppgave/Importere-land-vinerregioner-produsenter-#14
leaht Oct 7, 2026
446ed7c
Merge pull request #28 from IT2810-H26/oppgave/14-importskript
leaht Oct 7, 2026
f534c1e
oppgave/Endret kategorier og henter data med importscript + endring i…
leaht Oct 8, 2026
c49d8d0
Endringer i index.ts for GraphQL-spørringer til matkategorier
leaht Oct 8, 2026
407fd95
Merge pull request #29 from IT2810-H26/oppgave/14-importskript
leaht Oct 8, 2026
bb87cee
oppgave/dokumenter import av X-Wines-data på VM
Oct 8, 2026
e60bcd8
oppgave/wine-details-query
Oct 9, 2026
e6b7fb6
Merge pull request #31 from IT2810-H26/oppgave/wine-details-query
celinhag Oct 9, 2026
54ce901
feature/deploy oppsett
Oct 9, 2026
1065445
Merge pull request #34 from IT2810-H26/feature/deploy
sofiesty Oct 9, 2026
9e95754
Lagt til paginering i vinkatalogen
Oct 11, 2026
a7a7453
Merge pull request #36 from IT2810-H26/feature/paginering1
adelect Oct 11, 2026
5117d40
Deploy to VM from laptop: deploy scripts, Apollo client file, /projec…
Oct 14, 2026
386d41b
Merge pull request #37 from IT2810-H26/feature/deploy-vm
sofiesty Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
.env
.DS_Store
backend/data/
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,38 @@ Dette kan blant annet innebære:
- optimalisere bilder
- unngå unødvendig tunge biblioteker
- gjenbruke komponenter

# Lagt ttil av Sofie
## Database og backend på VM

PostgreSQL 18 er installert direkte på VM-en (it2810-01.idi.ntnu.no) med apt, uten Docker. Databasen lytter kun på localhost og er ikke tilgjengelig utenfra.

- Kode: `/srv/winenot` (klonet fra dette repoet, branch `dev`)
- Database: `winenot`, eid av brukeren `winenot_app`
- Tilkoblingsinfo og passord: `/srv/winenot/backend/.env` (kun lesbar med sudo). Se `backend/.env.example` for hvilke variabler som trengs.
- Tabeller opprettes med migrasjonene i `backend/db/migrations/`, kjørt i nummerert rekkefølge:
`psql -h localhost -U winenot_app -d winenot -v ON_ERROR_STOP=1 -f backend/db/migrations/<fil>.sql`

### Starte backend

```bash
cd /srv/winenot/backend
npm ci
npm start
```

Backend kjører på port 3001.

### Importere data (X-Wines)

1. Last ned `XWines_Full_100K_wines.csv` og `XWines_Full_21M_ratings.csv` fra Google Drive-lenken i Dataset-mappen på https://github.com/rogerioxavier/X-Wines
2. Kopier filene til `/srv/winenot/backend/data/` (mappen ligger i `.gitignore`)
3. Kjør migrasjonene i `backend/db/migrations/` som ikke er kjørt, og deretter:
```bash
cd /srv/winenot/backend
npm ci
npm run import -- data/XWines_Full_100K_wines.csv data/XWines_Full_21M_ratings.csv
```
Skriptet kan kjøres flere ganger, og favoritter beholdes. Uten argumenter bruker det testfilene (100 viner), som er nok til lokal utvikling.

Datasett: de Azambuja, R. X., Morais, A. J., & Filipe, V. (2023). X-Wines: A Wine Dataset for Recommender Systems and Machine Learning. *Big Data and Cognitive Computing*, 7(1), 20. https://doi.org/10.3390/bdcc7010020
6 changes: 6 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copy to .env and fill in your own values. .env must never be committed.
DB_HOST=localhost
DB_PORT=5432
DB_NAME=winenot
DB_USER=your_postgres_user
DB_PASSWORD=
103 changes: 103 additions & 0 deletions backend/db/migrations/001_create_tables.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
-- 001_create_tables.sql
-- Wine not? – tabeller og typer for PostgreSQL
-- Kjør med: psql -d winenot -v ON_ERROR_STOP=1 -f backend/db/migrations/001_create_tables.sql
-- En migrasjon som er merget, endres ikke. Nye endringer legges i en ny, nummerert fil.

BEGIN;

-- ---------- Typer ----------
-- Verdiene er de samme som i X-Wines, og rekkefølgen her bestemmer sorteringen.

CREATE TYPE body_level AS ENUM (
'Very light-bodied',
'Light-bodied',
'Medium-bodied',
'Full-bodied',
'Very full-bodied'
);

CREATE TYPE acidity_level AS ENUM (
'Low',
'Medium',
'High'
);

-- ---------- Oppslagstabeller ----------

CREATE TABLE countries (
code text PRIMARY KEY, -- Code fra X-Wines, f.eks. 'FR'
name text NOT NULL UNIQUE
);

CREATE TABLE regions (
id integer PRIMARY KEY, -- RegionID fra X-Wines
name text NOT NULL,
country_code text NOT NULL REFERENCES countries(code)
);

CREATE TABLE wineries (
id integer PRIMARY KEY, -- WineryID fra X-Wines
name text NOT NULL,
website text
);

CREATE TABLE grapes (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE
);

CREATE TABLE foods (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE -- verdier fra Harmonize, f.eks. 'Beef', 'Rich Fish'
);

-- ---------- Viner ----------

CREATE TABLE wines (
id integer PRIMARY KEY, -- WineID fra X-Wines
name text NOT NULL,
type text NOT NULL, -- Red, White, Rosé, Sparkling, Dessert, Dessert/Port
elaborate text, -- f.eks. 'Varietal/100%', 'Assemblage/Blend'
abv numeric(4,1), -- alkoholprosent
body body_level,
acidity acidity_level,
winery_id integer NOT NULL REFERENCES wineries(id),
region_id integer NOT NULL REFERENCES regions(id),
country_code text NOT NULL REFERENCES countries(code), -- bevisst duplisert fra regions: sparer en join ved landfilter
vintages integer[] NOT NULL DEFAULT '{}', -- 'N.V.' hoppes over i importskriptet
avg_rating numeric(3,2), -- forhåndsberegnet i importskriptet
rating_count integer NOT NULL DEFAULT 0
);

-- ---------- Mange-til-mange ----------

CREATE TABLE wine_grapes (
wine_id integer NOT NULL REFERENCES wines(id) ON DELETE CASCADE,
grape_id integer NOT NULL REFERENCES grapes(id) ON DELETE CASCADE,
PRIMARY KEY (wine_id, grape_id)
);

CREATE TABLE wine_foods (
wine_id integer NOT NULL REFERENCES wines(id) ON DELETE CASCADE,
food_id integer NOT NULL REFERENCES foods(id) ON DELETE CASCADE,
PRIMARY KEY (wine_id, food_id)
);

-- ---------- Brukere og favoritter (brukergenerert data) ----------

CREATE TABLE users (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
username text NOT NULL UNIQUE,
email text NOT NULL UNIQUE,
password_hash text NOT NULL, -- aldri klartekst; hashes med bcrypt/argon2 i backend
created_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE favorites (
user_id integer NOT NULL REFERENCES users(id) ON DELETE CASCADE,
wine_id integer NOT NULL REFERENCES wines(id) ON DELETE CASCADE,
created_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (user_id, wine_id) -- hindrer duplikater og dekker "mine favoritter"
);

COMMIT;
31 changes: 31 additions & 0 deletions backend/db/migrations/002_create_indexes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- 002_create_indexes.sql
-- Wine not? – indekser for søk, filtrering og sortering
-- Kjør med: psql -d winenot -v ON_ERROR_STOP=1 -f backend/db/migrations/002_create_indexes.sql

BEGIN;

CREATE EXTENSION IF NOT EXISTS pg_trgm; -- raskt delstreng-søk på vinnavn

-- Søk: WHERE name ILIKE '%tekst%'
CREATE INDEX wines_name_trgm_idx ON wines USING gin (name gin_trgm_ops);

-- Filtre
CREATE INDEX wines_type_idx ON wines (type);
CREATE INDEX wines_country_idx ON wines (country_code);
CREATE INDEX wines_region_idx ON wines (region_id);
CREATE INDEX wines_winery_idx ON wines (winery_id);
CREATE INDEX wines_taste_idx ON wines (body, acidity); -- Explore by taste
CREATE INDEX wines_vintages_idx ON wines USING gin (vintages); -- WHERE vintages @> ARRAY[2018]

-- Sortering (id som siste ledd gir stabil rekkefølge ved paginering)
CREATE INDEX wines_name_sort_idx ON wines (name, id);
CREATE INDEX wines_rating_idx ON wines (avg_rating DESC NULLS LAST, id);
CREATE INDEX wines_abv_idx ON wines (abv, id);

-- Primærnøklene dekker oppslag fra vin/bruker. Disse dekker motsatt vei.
CREATE INDEX wine_grapes_grape_idx ON wine_grapes (grape_id);
CREATE INDEX wine_foods_food_idx ON wine_foods (food_id);
CREATE INDEX favorites_wine_idx ON favorites (wine_id);
CREATE INDEX regions_country_idx ON regions (country_code);

COMMIT;
14 changes: 14 additions & 0 deletions backend/db/migrations/003_add_food_category.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- 003_add_food_category.sql
-- Wine not? – grovere matkategorier til Find wine by food
-- Kjør med: psql -d winenot -v ON_ERROR_STOP=1 -f backend/db/migrations/003_add_food_category.sql
--
-- Hver matverdi fra X-Wines (f.eks. 'Rich Fish', 'Shellfish') får én kategori (f.eks. 'Fish & seafood').
-- Selve grupperingen ligger i db/seeds/food_categories.sql og kjøres av importskriptet.

BEGIN;

ALTER TABLE foods ADD COLUMN category text;

CREATE INDEX foods_category_idx ON foods (category);

COMMIT;
76 changes: 76 additions & 0 deletions backend/db/seeds/food_categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
-- food_categories.sql
-- Grupperer matverdiene fra X-Wines (kolonnen Harmonize) i kategorier for Find wine by food.
--
-- Kjøres automatisk av importskriptet etter at maten er satt inn, og kan også kjøres alene:
-- psql -d winenot -1 -v ON_ERROR_STOP=1 -f backend/db/seeds/food_categories.sql
-- (-1 kjører hele filen som én transaksjon. Filen har ikke egen BEGIN/COMMIT,
-- fordi importskriptet kjører den inne i sin egen transaksjon.)
--
-- Endre en kategori: bytt navnet i høyre kolonne og kjør filen på nytt.
-- Ny matverdi uten kategori: importskriptet lister dem opp. Legg dem til her.
-- Matverdier som ikke står her, får category = NULL og vises ikke i Find wine by food.

UPDATE foods SET category = NULL;

UPDATE foods AS f
SET category = m.category
FROM (VALUES
-- Kjøtt
('Beef', 'Meat'),
('Lamb', 'Meat'),
('Veal', 'Meat'),
('Pork', 'Meat'),
('Game Meat', 'Meat'),
('Barbecue', 'Meat'),
('Grilled', 'Meat'),

-- Fjærkre
('Poultry', 'Poultry'),
('Chicken', 'Poultry'),

-- Fisk og sjømat
('Fish', 'Fish & seafood'),
('Rich Fish', 'Fish & seafood'),
('Lean Fish', 'Fish & seafood'),
('Seafood', 'Fish & seafood'),
('Shellfish', 'Fish & seafood'),

-- Ost
('Maturated Cheese', 'Cheese'),
('Soft Cheese', 'Cheese'),
('Hard Cheese', 'Cheese'),
('Blue Cheese', 'Cheese'),
('Goat Cheese', 'Cheese'),

-- Pasta, pizza og gryter
('Pasta', 'Pasta, pizza & stews'),
('Pizza', 'Pasta, pizza & stews'),
('Risotto', 'Pasta, pizza & stews'),
('Tomato Dishes', 'Pasta, pizza & stews'),
('Light Stews', 'Pasta, pizza & stews'),

-- Vegetar
('Vegetarian', 'Vegetarian'),
('Salad', 'Vegetarian'),
('Mushrooms', 'Vegetarian'),

-- Sterk mat
('Spicy Food', 'Spicy food'),

-- Småretter og aperitiff
('Appetizer', 'Snacks & starters'),
('Snack', 'Snacks & starters'),
('Aperitif', 'Snacks & starters'),
('Cured Meat', 'Snacks & starters'),
('Cold Cuts', 'Snacks & starters'),
('French Fries', 'Snacks & starters'),

-- Dessert
('Sweet Dessert', 'Dessert'),
('Fruit Dessert', 'Dessert'),
('Cake', 'Dessert'),
('Chocolate', 'Dessert'),
('Fruit', 'Dessert'),
('Cream', 'Dessert')
) AS m(food, category)
WHERE f.name = m.food;
Loading