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
237 changes: 233 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Repository for team IT2810-H26-T27 i IT2810-H26.

> **Status: Første underveisinnlevering.** Dette er en spesifikasjon og et første designutkast. Ingenting er implementert ennå, og alt kan endres. Vi tar gjerne imot tilbakemeldinger på idé, data, flyt og design.
> **Status: Andre underveisinnlevering.** Backend med GraphQL (Apollo Server) og PostgreSQL er satt opp, og varer fra Kassalapp importeres til databasen. Frontend henter og viser varer via Apollo Client. Handlelister kan opprettes og fylles med varer gjennom API-et. Se [Kjøre prosjektet lokalt](#kjøre-prosjektet-lokalt) for oppsett.
## Idé

Expand Down Expand Up @@ -99,7 +99,74 @@ ListItem (id, listId, productId, quantity, note, checked)

Handlelister, varer på lista, antall, notater og avkrysninger er de brukergenererte dataene. Appen har ingen innlogging. Hver nettleser får en anonym bruker-ID som lagres lokalt og sendes med til backend.

## GraphQL-API (utkast)
## GraphQL-API

Backenden kjører på port 3001. Når backenden kjører lokalt, kan du åpne http://localhost:3001/ i nettleseren og teste spørringene i Apollo Sandbox.

### Implementert til innlevering 2

| Type | Navn | Hva den gjør |
| --- | --- | --- |
| Query | `products(search, category, limit = 20, offset = 0)` | Søker i varenavn uten å skille mellom store og små bokstaver (`ILIKE`). Kan filtreres på kategori og pagineres med `limit` og `offset`. Sortert på navn. |
| Query | `product(ean)` | Henter én vare med strekkode. |
| Query | `categories` | Henter alle kategorier, sortert på navn. |
| Query | `shoppingList(id)` | Henter en handleliste med varene på den. |
| Mutation | `createShoppingList(name)` | Lager en ny handleliste. |
| Mutation | `addItemToList(listId, ean, quantity = 1)` | Legger en vare på lista. Ligger varen der fra før, økes antallet. |

En `Product` har feltene `ean`, `name`, `brand`, `imageUrl`, `categoryId`, `category` og `prices`. Hver pris har `storeCode`, `price`, `unitPrice` og `url`.

**Eksempel: søk etter melk**

```graphql
query {
products(search: "melk", limit: 5) {
ean
name
brand
prices {
storeCode
price
}
}
}
```

**Eksempel: lag en liste og legg til en vare**

```graphql
mutation {
createShoppingList(name: "Fredagshandel") {
id
}
}
```

```graphql
mutation {
addItemToList(listId: "1", ean: "7041013200110", quantity: 2) {
name
items {
ean
quantity
}
}
}
```

Bytt ut `listId` med id-en du fikk tilbake, og `ean` med en strekkode fra `products`.

Du kan også teste fra terminalen:

```bash
curl -s http://localhost:3001/ \
-H "Content-Type: application/json" \
-d '{"query":"{ products(search: \"melk\", limit: 3) { name } }"}'
```

### Planlagt API (utkast)

Dette er API-et vi har planlagt videre. Det kan endre seg underveis.

```graphql
type Query {
Expand Down Expand Up @@ -157,19 +224,181 @@ Lister med mange elementer, som søkeresultater og tidligere handlelister, retur
3. Komplett beta med paginering, filtrering, sortering, handlelister og handletur, pluss tilgjengelighet og bærekraft.
4. Tester, opprydding og dokumentasjon.

## Status

**Ferdig til innlevering 2**

- PostgreSQL-skjema med tabeller for kategorier, varer, priser og handlelister, med indekser for søk og filtrering.
- Import fra Kassalapp til en JSON-dump (`npm run import`), og en seed som fyller databasen fra dumpen uten API-nøkkel (`npm run seed`).
- GraphQL-backend med Apollo Server: søk, kategorifilter og paginering med `limit` og `offset`, enkeltvare, kategorier og handlelister. Se [GraphQL-API](#graphql-api).
- Frontend med React og Apollo Client som henter og viser varer med laveste pris. Søket bruker debounce (400 ms), så det sendes ikke et kall for hvert tastetrykk.
- Backend og database på VM-en (pågår, se [Kjøre på VM-en](#kjøre-på-vm-en)).

**Kommer i innlevering 3**

- Paginering i klienten («last flere» eller sider) med totalt antall treff.
- Filtrering på pris, butikk og merking, og sortering på pris og kilopris, i databasen.
- Produktside med ingredienser, allergener og næringsinnhold.
- Handlelister i grensesnittet: opprette, legge til varer, endre antall, handletur med avkrysning og tidligere lister.
- Tilgjengelighet og bærekraft som beskrevet i [Hvordan vi oppfyller kravene](#hvordan-vi-oppfyller-kravene).
- Prettier, Vitest og Playwright.

## Bruk av KI

README-en til første innlevering er skrevet med hjelp fra Claude (KI), basert på gruppas egen skjermflyt, design, møtereferater og valg av datakilde. Gruppa har gått gjennom innholdet. Vi fortsetter å dokumentere bruken av KI her gjennom prosjektet.

## Kjøre prosjektet lokalt

### Krav

- **Node.js 22.12 eller nyere** og npm. Vite 8 krever minst denne versjonen. Sjekk med `node -v`.
- **PostgreSQL 14 eller nyere** med utvidelsen `pg_trgm`, som brukes til søk. Den følger med vanlige installasjoner, for eksempel Homebrew på Mac og pakken `postgresql-contrib` på Ubuntu.
- **Git**.
- **Kassalapp API-nøkkel** trengs bare hvis du skal hente nye data. En ferdig dump ligger i `backend/data/kassalapp-dump.json`, så du kan sette opp databasen uten nøkkel.

### 1. Klon repoet

```bash
git clone git@git.ntnu.no:IT2810-H26/T27-Project-2.git
cd T27-Project-2
git switch dev
```

Vi jobber på `dev`. `main` oppdateres bare ved innleveringene.

### 2. Installer avhengigheter

Frontend og backend har hver sin `package.json`, så du må installere begge:

```bash
cd backend && npm install && cd ..
cd frontend && npm install && cd ..
```

Kjør `npm install` på nytt i mappa det gjelder hvis noen har lagt til nye pakker. Feilen `Failed to resolve import` i nettleseren betyr som regel at du mangler en pakke.

### 3. Miljøvariabler

Begge mappene har en `.env.example`. Kopier den til `.env` og fyll inn verdiene. `.env`-filene er ignorert av git og skal aldri sjekkes inn.

```bash
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env
```

**`backend/.env`**

| Variabel | Eksempel | Beskrivelse |
| --- | --- | --- |
| `PORT` | `3001` | Porten GraphQL-serveren kjører på. |
| `DATABASE_URL` | `postgres://localhost:5432/handlelapp` | Tilkobling til PostgreSQL. Legg til brukernavn og passord om databasen krever det: `postgres://bruker:passord@localhost:5432/handlelapp`. |
| `KASSALAPP_API_KEY` | | Brukes bare av `npm run import`. Kan stå tom ellers. |

**`frontend/.env`**

| Variabel | Eksempel | Beskrivelse |
| --- | --- | --- |
| `VITE_GRAPHQL_URL` | `http://localhost:3001/` | Adressen til GraphQL-backenden. Uten denne viser frontend bare en hvit side. |

Vite leser `.env` bare ved oppstart, så start frontend på nytt etter at du har endret den.

### 4. Sett opp databasen

Start PostgreSQL, lag databasen og kjør skjemaet. Kommandoene kjøres fra `backend/`:

```bash
cd backend
createdb handlelapp
psql handlelapp -f db/migrations/001_init.sql
npm run seed
```

- `001_init.sql` lager tabellene `categories`, `products`, `prices`, `shopping_lists` og `list_items`, med indekser for søk, filtrering og sortering. Skjemaet bruker `IF NOT EXISTS` og kan kjøres flere ganger.
- `npm run seed` fyller databasen fra `data/kassalapp-dump.json`. Den kan også kjøres flere ganger, siden eksisterende varer og priser oppdateres i stedet for å dupliseres. Den må kjøres fra `backend/`, fordi filstien er relativ.

Når seeden er ferdig, skriver den ut hvor mange kategorier, varer og priser som ble lagt inn.

### 5. Kjør backend og frontend

Backend og frontend må kjøre samtidig, i hver sin terminal.

**Terminal 1, backend:**

```bash
cd backend
npm run dev
```

Serveren starter på http://localhost:3001/. Der kan du også teste spørringer i Apollo Sandbox.

**Terminal 2, frontend:**

```bash
cd frontend
npm install
npm run dev
```

Instruksjoner for backend og database kommer til andre innlevering.
Åpne http://localhost:5173/ i nettleseren. Stopp serverne med `Ctrl + C`.

### Hente nye data fra Kassalapp (valgfritt)

Dette trengs bare hvis dataene skal oppdateres. Legg inn `KASSALAPP_API_KEY` i `backend/.env` og kjør:

```bash
cd backend
npm run import # henter fra Kassalapp og skriver data/kassalapp-dump.json
npm run seed # legger de nye dataene inn i databasen
```

Gratisnøkkelen tillater 60 kall i minuttet, så importen tar litt tid.

### Skript

| Mappe | Kommando | Hva den gjør |
| --- | --- | --- |
| `backend/` | `npm run dev` | Starter GraphQL-serveren og restarter ved endringer. |
| `backend/` | `npm run build` | Kompilerer TypeScript til `dist/`. |
| `backend/` | `npm start` | Kjører den kompilerte serveren fra `dist/`. |
| `backend/` | `npm run import` | Henter data fra Kassalapp til `data/kassalapp-dump.json`. |
| `backend/` | `npm run seed` | Fyller databasen fra dumpen. |
| `frontend/` | `npm run dev` | Starter utviklingsserveren til Vite. |
| `frontend/` | `npm run build` | Typesjekker og bygger frontend til `dist/`. |
| `frontend/` | `npm run lint` | Kjører ESLint. |
| `frontend/` | `npm run preview` | Viser det bygde resultatet lokalt. |

### Vanlige feil

| Feil | Løsning |
| --- | --- |
| Hvit side i nettleseren | `frontend/.env` mangler. Se steg 3, og start frontend på nytt. |
| `Failed to resolve import "..."` | Kjør `npm install` i `frontend/`. |
| `EADDRINUSE` eller «Port 5173 is in use» | En gammel server kjører fortsatt. Stopp den med `Ctrl + C`, eller kjør `lsof -ti :3001 :5173 \| xargs kill`. |
| `DATABASE_URL mangler` | `backend/.env` mangler. Se steg 3. |
| Tom resultatliste | Databasen er tom. Kjør `npm run seed` i `backend/`. |
| `extension "pg_trgm" is not available` | Installer `postgresql-contrib` (Ubuntu) eller bruk en PostgreSQL-installasjon som inkluderer den. |

## Kjøre på VM-en

<!-- TODO (issue #16): Fyll inn når backend og database er deployet. -->

Backenden og databasen kjører på gruppas virtuelle maskin:

- **GraphQL-backend:** `http://<VM-ADRESSE>:3001/`
- **Database:** PostgreSQL på samme VM. Den er ikke tilgjengelig utenfra.

Sjekk at backenden svarer:

```bash
curl -s http://<VM-ADRESSE>:3001/ \
-H "Content-Type: application/json" \
-d '{"query":"{ categories { name } }"}'
```

For å kjøre frontend lokalt mot backenden på VM-en, sett adressen i `frontend/.env` og start frontend på nytt:

```
VITE_GRAPHQL_URL=http://<VM-ADRESSE>:3001/
```

## Arbeidsflyt

Expand Down
1 change: 1 addition & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
PORT=3001
DATABASE_URL=postgres://localhost:5432/handlelapp
# Trengs bare for `npm run import`. Seed og vanlig kjøring fungerer uten.
KASSALAPP_API_KEY=