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
5 changes: 5 additions & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Kopier til .env og fyll inn. .env skal IKKE committes.
PORT=3001
# Eksempel med innlogging: mongodb://bruker:passord@localhost:27017/?authSource=admin
MONGODB_URI=mongodb://localhost:27017
MONGODB_DB=cities
3 changes: 3 additions & 0 deletions server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
.env
5 changes: 5 additions & 0 deletions server/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": false,
"semi": true,
"printWidth": 90
}
77 changes: 77 additions & 0 deletions server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Server (GraphQL-backend)

Node + TypeScript + Apollo Server 5 mot MongoDB. Lytter på port 3001.

## Kjøre lokalt

```bash
cd server
npm install
cp .env.example .env # MONGODB_URI og MONGODB_DB
npm run indexes # oppretter indekser (trygt å kjøre flere ganger)
npm run dev # http://localhost:3001/
```

Produksjon (på VM-en): `npm run build && npm start`. Bruk gjerne systemd eller pm2
slik at prosessen starter igjen etter restart.

## Forventet datamodell

**Collection `cities`**, ett dokument per by. Feltnavnene styres av `FIELD` i
`src/db.ts`, og standardverdiene er:

```json
{ "name": "Oslo", "country": "Norway", "latitude": 59.91, "longitude": 10.75,
"population": 700000, "timezone": "Europe/Oslo" }
```

Hvis feltene i den importerte collectionen heter noe annet, endre `FIELD` og
`COLLECTION` i `src/db.ts`. Ingen andre filer trenger å endres. `population`,
`latitude` og `longitude` bør være tall (ikke tekst), ellers blir sortering og
filtrering feil.

**Collection `reviews`** opprettes automatisk når første anmeldelse lagres:

```json
{ "cityId": ObjectId, "rating": 4, "comment": "…", "author": "Anonym", "createdAt": Date }
```

By-id er MongoDBs `_id` (ObjectId), eksponert som en streng i GraphQL.

## API

| Operasjon | Beskrivelse |
| --- | --- |
| `searchCities(search, filter, sort, limit, offset)` | Case-insensitivt søk på bynavn, filtrering (land, tidssone, befolkning), sortering og paginering. Returnerer `items`, `totalCount`, `hasMore`. `limit` er maks 100. |
| `city(id)` | Detaljer for én by, inkludert anmeldelser. |
| `countries` | Alle land, til filtervalg. |
| `addReview(input)` | Lagrer en rating (1-5) og valgfri kommentar. |

Eksempel:

```graphql
query {
searchCities(
search: "trond"
filter: { country: "Norway", minPopulation: 100000 }
sort: { field: POPULATION, direction: DESC }
limit: 20
offset: 0
) {
totalCount
hasMore
items { id name country population averageRating reviewCount }
}
}
```

## Designvalg

- **Filtrering og sortering i databasen**, slik at det gjelder hele resultatsettet.
- **Sortering fra hvitliste**, og søketekst escapes før den brukes i regex.
- **Stabil paginering**: `_id` er tiebreaker i sorteringen.
- **Review-statistikk** hentes med én aggregering for kun byene på gjeldende side.
- **Indekser** på befolkning, navn, land og anmeldelser (`npm run indexes`).
- **Kjent begrensning:** Søket er et regex-treff på delstreng, som ikke kan bruke
indeks fullt ut. For 30 000–50 000 byer er det raskt nok. For en mye større
samling bør man bytte til prefikssøk på et lowercase-felt eller en tekstindeks.
Loading