diff --git a/README.md b/README.md index 2cf44ca..617c6a1 100644 --- a/README.md +++ b/README.md @@ -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é @@ -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 { @@ -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 + + + +Backenden og databasen kjører på gruppas virtuelle maskin: + +- **GraphQL-backend:** `http://:3001/` +- **Database:** PostgreSQL på samme VM. Den er ikke tilgjengelig utenfra. + +Sjekk at backenden svarer: + +```bash +curl -s http://: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://:3001/ +``` ## Arbeidsflyt diff --git a/backend/.env.example b/backend/.env.example index caddef9..2c9c364 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -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=