Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
209 changes: 182 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@
Målet er å lage en oversiktlig og visuelt interessant vinkatalog hvor brukeren både kan finne bestemte viner og oppdage nye gjennom søk, filtrering og mer utforskende funksjoner basert på smak, mat og lignende viner.


Hvordan prosjektet installeres og kjøres, lokalt og på VM-en, står i [Installasjon og kjøring](#installasjon-og-kjøring).


---


## Status:
## Status (andre underveisinnlevering)


Applikasjonen kjører på gruppas VM: http://it2810-01.idi.ntnu.no/project2 (krever NTNU-nett eller VPN).


Dette fungerer nå:
- **Database:** PostgreSQL på VM-en med hele X-Wines-datasettet (100 646 viner), lastet inn med vårt eget importskript.
- **Backend:** GraphQL-backend i Node.js, TypeScript og Apollo Server på port 3001. Den kjører som en systemd-tjeneste og starter av seg selv etter omstart.
- **Klient:** en vinkatalog i React som henter viner fra backend med Apollo Client og viser 20 om gangen. Brukeren kan bla mellom sider med «Forrige» og «Neste». Hver side hentes fra backend med `limit` og `offset`, så klienten laster aldri hele datasettet.
- Backend har også spørringer for detaljer om én vin (`wine`) og for matkategorier (`foodCategories`, `winesByFoodCategory`), som klienten ikke bruker ennå.

Denne innleveringen består av en spesifikasjon av den planlagte løsningen. Vi beskriver hvilke data applikasjonen skal bruke, hvordan brukergrensesnitt og funksjonaliteten er tenkt utformet og hvordan vi planlegger database, backend og GraphQL-løsning.

Neste steg er søk, sortering og filtrering, detaljvisning av hver vin og resten av funksjonaliteten som er beskrevet under. Resten av README beskriver planen for hele applikasjonen.


## Idé
Expand Down Expand Up @@ -341,7 +354,7 @@ React-klient
## Foreløpig GraphQL-design


GraphQL-backend er ikke implementert ennå, men vi planlegger at frontend skal hente vinene gjennom vår egen backend.
Frontend henter vinene gjennom vår egen GraphQL-backend. Skjemaet under er planen for hele applikasjonen; foreløpig er `wines`, `wine`, `foodCategories` og `winesByFoodCategory` implementert (se `backend/src/index.ts`).


Søk, filtrering, sortering og paginering skal utføres i backend slik at funksjonaliteten gjelder hele datasettet og ikke bare vinene som allerede er lastet inn i klienten.
Expand Down Expand Up @@ -395,8 +408,8 @@ type WineMatch {
| Frontend | React, TypeScript, Vite | Krav i oppgaven |
| Ruting | React Router | Egne URL-er for katalog, detaljsider og undersider |
| Visualisering | React-basert visualisering / lett grafbibliotek | Brukes til Explore by taste |
| State management | Apollo Client (planlagt) | Cache for GraphQL-svar og lokal state |
| Backend | Node.js, TypeScript, Apollo Server (planlagt) | GraphQL er krav i oppgaven, og Apollo Server er godt dokumentert |
| State management | Apollo Client | Cache for GraphQL-svar og lokal state |
| Backend | Node.js, TypeScript, Apollo Server | GraphQL er krav i oppgaven, og Apollo Server er godt dokumentert |
| Database | PostgreSQL | Relasjonsdatabase som passer godt til viner, brukere og favoritter. Støtter også effektiv søking, filtrering og sortering |
| Testing | Vitest | Vitest er krav i oppgaven |
| Kodekvalitet | oxlint og Prettier | Linting og felles formatering |
Expand Down Expand Up @@ -457,37 +470,179 @@ Dette kan blant annet innebære:
- unngå unødvendig tunge biblioteker
- gjenbruke komponenter

# Lagt ttil av Sofie
## Database og backend på VM
## Installasjon og kjøring

Denne delen beskriver hvordan database, backend og frontend installeres og startes, både lokalt og på gruppas VM.

```text
Nettleser ──► Apache (port 80) ──► /var/www/html/project2 bygget frontend (statiske filer)
│
└──────► Backend (Node.js, port 3001) ──► PostgreSQL (databasen winenot)
```

| Del | Teknologi | Mappe |
|---|---|---|
| Database | PostgreSQL | `backend/db/migrations/` (tabeller og indekser), `backend/db/seeds/` (matkategorier) |
| Dataimport | Node.js-skript som leser X-Wines-filene (CSV) | `backend/scripts/import.ts` |
| Backend | Node.js, TypeScript, Apollo Server (GraphQL) | `backend/` |
| Frontend | React, TypeScript, Vite, Apollo Client, React Router | `client/` |
| Drift på VM | Bash-skript, systemd og Apache | `deploy/` |

### Kjøre lokalt

Du trenger Git, Node.js 22 eller nyere og PostgreSQL (vi bruker versjon 18). Kommandoene er for macOS og Linux; på Windows kan de kjøres i Git Bash.

**1. Hent koden og installer pakker**

```bash
git clone git@git.ntnu.no:IT2810-H26/T01-Project-2.git
cd T01-Project-2
(cd backend && npm ci)
(cd client && npm ci)
```

**2. Opprett databasen og tabellene**

```bash
createdb winenot
cd backend
for f in db/migrations/*.sql; do psql -d winenot -v ON_ERROR_STOP=1 -f "$f" || break; done
```

Migrasjonene kjøres i nummerert rekkefølge. En migrasjon som er merget, endres ikke; nye endringer legges i en ny, nummerert fil. Kommandoene bruker din egen PostgreSQL-bruker, som er standard med Homebrew på Mac. Bruker du en annen databasebruker, legg til `-U <bruker>`.

**3. Sett opp tilkoblingen til databasen** (fortsatt i `backend/`)

```bash
cp .env.example .env
```

Åpne `backend/.env` og fyll inn `DB_USER`, og `DB_PASSWORD` hvis databasen krever passord. `.env` ligger i `.gitignore` og skal aldri committes. Backend kjører på port 3001 med mindre `PORT` er satt.

**4. Last ned og importer data** (fortsatt i `backend/`)

X-Wines-filene ligger ikke i Git, fordi `backend/data/` er i `.gitignore`. Testversjonen med 100 viner holder til utvikling:

```bash
mkdir -p data
curl -L -o data/XWines_Test_100_wines.csv https://raw.githubusercontent.com/rogerioxavier/X-Wines/main/Dataset/last/XWines_Test_100_wines.csv
curl -L -o data/XWines_Test_1K_ratings.csv https://raw.githubusercontent.com/rogerioxavier/X-Wines/main/Dataset/last/XWines_Test_1K_ratings.csv
npm run import
```

Importskriptet fyller tabellene og setter matkategorier fra `db/seeds/food_categories.sql`. Det kan kjøres flere ganger, og favoritter beholdes. For hele datasettet (100 646 viner) laster du ned `XWines_Full_100K_wines.csv` og `XWines_Full_21M_ratings.csv` fra Google Drive-lenken i [X-Wines-repoet](https://github.com/rogerioxavier/X-Wines), legger dem i `backend/data/` og kjører:

```bash
npm run import -- data/XWines_Full_100K_wines.csv data/XWines_Full_21M_ratings.csv
```

**5. Start backend** (fortsatt i `backend/`)

```bash
npm run dev
```

Backend kjører nå på http://localhost:3001/. Åpner du adressen i nettleseren, får du Apollo Sandbox, der du kan prøve spørringer, for eksempel `{ wines(limit: 5) { totalCount items { name } } }`.

**6. Start frontend** i en ny terminal, fra rotmappen i repoet:

```bash
cd client
npm run dev
```

Åpne http://localhost:5173/project2/. Frontend henter data fra http://localhost:3001/. En annen adresse kan settes med `VITE_GRAPHQL_URL` (se `client/.env.example`).

### Kjøring på VM-en

Applikasjonen kjører på http://it2810-01.idi.ntnu.no/project2, og GraphQL-backend på http://it2810-01.idi.ntnu.no:3001/. VM-en kan bare nås fra NTNU-nettet eller via VPN. Hvilken commit som kjører, står i http://it2810-01.idi.ntnu.no/project2/version.txt.

Alt kjører direkte på VM-en uten Docker, og starter av seg selv etter en omstart.

| Hva | Hvor på VM-en |
|---|---|
| Koden (siste deploy av `main`) | `/opt/wine-not` |
| Bygget frontend, servert av Apache | `/var/www/html/project2` |
| Backend | systemd-tjenesten `wine-not-api`, som kjører `node dist/index.js` som brukeren `winenot` (oppsett i `deploy/wine-not-api.service`) |
| Tilkoblingsinfo og passord til databasen | `/etc/wine-not/backend.env`, kun lesbar med sudo (mal i `deploy/backend.env.example`) |
| Database | PostgreSQL 18, databasen `winenot` eid av brukeren `winenot_app`, lytter kun på localhost |
| X-Wines-data (full versjon) | `/opt/wine-not/backend/data` |
| Apache-oppsett for `/project2` | `/etc/apache2/conf-available/project2.conf` (fra `deploy/apache-project2.conf`) |

**Status, omstart og logger for backend** (på VM-en):

```bash
sudo systemctl status wine-not-api
sudo systemctl restart wine-not-api
sudo journalctl -u wine-not-api -n 50
```

**Deploye en ny versjon.** VM-en har ikke tilgang til Git-serveren, så deploy gjøres fra egen maskin etter at endringene er merget til `main`. Kjør fra repoet, på NTNU-nettet eller VPN:

```bash
bash deploy/push-to-vm.sh <ntnu-brukernavn>
```

Skriptet pakker det som ligger på `main` (bare committede filer), kopierer det til VM-en og kjører `deploy/deploy.sh` der. Det skriptet:

1. kopierer koden til `/opt/wine-not`,
2. installerer pakker og bygger backend (`tsc`) og frontend (`vite build`),
3. installerer systemd-tjenesten og Apache-oppsettet,
4. starter backend på nytt og kopierer frontend til `/var/www/html/project2`.

Begge delene bygges før noe byttes ut, så hvis et bygg feiler, fortsetter den gamle versjonen å kjøre. Du trenger sudo på VM-en. For å bygge på nytt uten ny kode kjører du `sudo bash /opt/wine-not/deploy/deploy.sh` på VM-en.

Frontend bygges som minifiserte, statiske filer med hash i filnavnet, som nettleseren kan cache i ett år (se `deploy/apache-project2.conf`). En deploy sender bare kildekoden, ikke `node_modules` eller data.

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.
**Migrasjoner og import på VM-en.** Migrasjoner kjøres aldri automatisk. Etter at en ny migrasjon er deployet:

- 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`
```bash
cd /opt/wine-not/backend
sudo bash ../deploy/with-env.sh psql -v ON_ERROR_STOP=1 -f db/migrations/<fil>.sql
sudo systemctl restart wine-not-api
```

### Starte backend
`deploy/with-env.sh` kjører kommandoen med innstillingene fra `/etc/wine-not/backend.env`. Importen kjøres på samme måte:

```bash
cd /srv/winenot/backend
npm ci
npm start
sudo bash ../deploy/with-env.sh npm run import -- data/XWines_Full_100K_wines.csv data/XWines_Full_21M_ratings.csv
```

Backend kjører på port 3001.
**Sette opp en ny VM.** Dette er allerede gjort på vår VM, men slik settes alt opp fra bunnen av på Ubuntu:

```bash
sudo apt update
sudo apt install -y rsync curl apache2 postgresql
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
sudo useradd --system --no-create-home --shell /usr/sbin/nologin winenot
sudo -u postgres psql -c "CREATE USER winenot_app WITH PASSWORD '<passord>';"
sudo -u postgres psql -c "CREATE DATABASE winenot OWNER winenot_app;"
sudo mkdir -p /etc/wine-not
sudo nano /etc/wine-not/backend.env
sudo chmod 600 /etc/wine-not/backend.env
```

### Importere data (X-Wines)
`/etc/wine-not/backend.env` får samme innhold som `deploy/backend.env.example`, med det ekte passordet. Er brannmuren på (`sudo ufw status`), åpnes portene med `sudo ufw allow 80/tcp` og `sudo ufw allow 3001/tcp`.

Deretter deployes koden med `deploy/push-to-vm.sh` fra egen maskin. Til slutt legges CSV-filene i `/opt/wine-not/backend/data` (for eksempel med `scp`), og migrasjonene og importen kjøres på VM-en:

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
cd /opt/wine-not/backend
for f in db/migrations/*.sql; do sudo bash ../deploy/with-env.sh psql -v ON_ERROR_STOP=1 -f "$f" || break; done
sudo bash ../deploy/with-env.sh 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
### Feilsøking

| Problem | Løsning |
|---|---|
| Siden laster, men ingen viner vises | Sjekk at backend kjører (`sudo systemctl status wine-not-api`), og at port 3001 er åpen i brannmuren. |
| 404 når en side lastes på nytt | Apache-oppsettet er ikke aktivt: `sudo a2enconf project2 && sudo systemctl restart apache2`. |
| `Could not resolve hostname` ved deploy | Du er ikke på NTNU-nettet eller VPN. |
| `password authentication failed` | Passordet i `/etc/wine-not/backend.env` stemmer ikke med databasebrukeren. |
| Bygget feiler på VM-en, men fungerer lokalt | Noe er ikke committet eller merget til `main`. VM-en får bare det som ligger på `main`. |

## 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
4 changes: 2 additions & 2 deletions client/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<!doctype html>
<html lang="en">
<html lang="nb">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>client</title>
<title>Wine not?</title>
</head>
<body>
<div id="root"></div>
Expand Down