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
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CI

on:
pull_request:
push:
branches: [main]

jobs:
backend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: backend/package-lock.json
- run: npm ci
- run: npm run lint
- run: npm run build

frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: npm ci
- run: npm run lint
- run: npm test -- --run
- run: npm run build
35 changes: 32 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
node_modules/
dist/
dist-ssr/
# Dependencies
node_modules

# Build output
dist
dist-ssr

# Test coverage
coverage

# Environment variables (.env.example and frontend/.env.production are committed on purpose)
.env
*.local

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
10 changes: 0 additions & 10 deletions .idea/.gitignore

This file was deleted.

9 changes: 0 additions & 9 deletions .idea/T03-Project-2.iml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/misc.xml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/modules.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

159 changes: 147 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,156 @@
# T03-Project-2
# I <3 Plants

## Overview - I <3 Plants
> **Live version:** _TODO: add link to the deployed app on the VM_
See our full description and specification for the project in the PDF file, **Specifications for project 2.pdf** on git.
You can also open the PDF locally in VS Code with the extention **vscode-pdf**.
I <3 Plants offers a fun way of finding plants and reading about them! Instead of scrolling through a long catalogue, you set your preferences and get shown one plant at a time. You like the plants you want and skip the ones you don't, and your matches are saved so you can come back to them later. If you already know what you are looking for, you can also search and filter the full plant collection.

## Run locally
The full project description and specification are in [docs/Specifications for project 2.pdf](docs/Specifications%20for%20project%202.pdf).

## Link to VM

http://it2810-03.idi.ntnu.no/project2

## Core features

- **Plant Match:** Shows plants one at a time. Click ✿ to like a plant or ✖ to skip it.
- **Preferences:** Choose what kind of plants you want, for example indoor, outdoor, flowering, pet friendly or succulent. Your preferences are remembered between visits.
- **My Matches:** A list of all the plants you have matched with or have added as matches.
- **Explore Plants:** Search the plant collection and filter by watering needs, sunlight, location (indoor/outdoor) and edibility.
- **Plant details:** Each plant card shows an image, the scientific name, a description and care information (watering, sunlight and care level).
- **Profile:** Your preferences and saved plants in one place.
- **Language and theme:** The app is available in English and Norwegian, and has a light and a dark theme.

## Tech stack

| Part | Technology |
| -------- | ------------------------------------------------------------- |
| Frontend | React, TypeScript, Vite, Apollo Client, React Router, i18next |
| Backend | Node.js, TypeScript, Apollo Server (GraphQL) |
| Database | MongoDB, running on the course VM |
| Testing | Vitest, React Testing Library, jsdom |
| Tooling | ESLint, Prettier, GitHub Actions |

## Architecture

See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for how the frontend, backend and database fit together, and how the code is organised.

## API and database

### Plant data: the Perenual API

The plant data comes from the [Perenual API](https://perenual.com/docs/api), which has information about thousands of plant species, including images, care information and plant traits.

We do **not** call Perenual from the app while it is running. Instead, the script [backend/seedDataFetch.js](backend/seedDataFetch.js) has fetched the data once, cleans it and stored it in our own MongoDB database on the VM. We have keept the seedDataFetch file so you can see how this has been done. The app only talks to our own GraphQL backend. We chose this approach for three reasons:

- **Rate limits:** The free tier on the Perenual API allows about 100 requests per day, and only returns details for plants with an ID up to 3000. If the app called Perenual directly, a handful of users would use up the daily limit in minutes. This is therfore a scalable solution for using this API source as the source for our data.
- **Control over the data:** We only keep the fields we use, in the format we want. That keeps responses small, and makes searching, filtering, sorting and pagination something we decide on ourselves instead of something limited by what Perenual supports.
- **Reliability and security:** The app keeps working even if Perenual is down or changes its API, since the data is stored in our own database.

### Backend: GraphQL with Apollo Server

The backend exposes a single GraphQL endpoint. With GraphQL, the frontend asks for exactly the fields each view needs. A plant card needs more fields than a list item, and both are served by the same `Plant` type without extra endpoints. The schema also gives us one typed contract between frontend and backend.

### Database: MongoDB

We store the plants in MongoDB, a document database. It is a good fit for this data:

- **The data is already documents.** Perenual returns JSON with nested objects and lists (such as sunlight requirements and scientific names). Each plant becomes one document with almost the same shape, so there is no need to split it into several tables and join them back together. This limits the cleaning necessary.
- **Plants have different fields.** Some plants have information that others are missing. A document database handles optional fields naturally, without a lot of empty columns.
- **It is simple to update.** The seed script first inserts a basic entry for each plant, and later adds details to the same document (an upsert keyed on `perenualId`).

The trade-off in using a NoSQL databse such as MongoDB commpared to a relational database such as MySQL is that it does not enforce relationships between collections the way a relational database does. That matters little here, because the plant collection is mostly read-only, and user data such as saved matches only needs to refer to a plant by its ID.

MongoDB runs on the course VM and only listens on `127.0.0.1`, so it cannot be reached directly from the internet. During development, you reach it through an SSH tunnel (see below).

## Run the project locally

### Requirements

- Node.js v24.6.x or later
- Node.js v24.6 or later
- npm v11 or later
- Access to the NTNU network (use the NTNU VPN if you are not on campus)
- An NTNU user with access to the VM `it2810-03.idi.ntnu.no`

### 1. Install dependencies

```bash
git clone <repo-url>
cd T03-Project-2
npm run install:all
```

This installs the dependencies for the repo root, `backend` and `frontend`.

### 2. Create the backend `.env` file (in the VSC terminal window)

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

The default values work as they are. `.env` is ignored by git and must never be committed.

### 3. Open an SSH tunnel to the database (in PC terminal window)

Open a **separate terminal**, replace `<ntnu-username>` with your username and run:

```bash
ssh -N -L 27017:localhost:27017 <ntnu-username>@it2810-03.idi.ntnu.no
```

After you enter your password, the command looks like it hangs. That means the tunnel is open. Keep the terminal open while you work, and stop the tunnel with `Ctrl+C` when you are done.

### 4. Start the app (in the VSC terminal window)

From the repo root:

```bash
npm run dev
```

This starts both the backend (http://localhost:4000) and the frontend. Open http://localhost:5173/project2/ in your browser. The frontend forwards `/graphql` requests to the backend, so both must be running.

See [backend/README.md](backend/README.md) for more details about the backend setup (in Norwegian).

### Available scripts - kan slettes?

The project has three `package.json` files: one in the repo root, one in `backend` and one in `frontend`. The root `package.json` contains no app code. It only holds scripts that run the matching script in `backend` and `frontend` for you, so you don't have to switch between folders. Run these from the repo root:

| Command | What it does | When to use it |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `npm run install:all` | Runs `npm install` in the root, `backend` and `frontend`. | After cloning, and after pulling changes to any `package.json`. |
| `npm run dev` | Starts the backend (`tsx watch`, port 4000) and the frontend (Vite, port 5173) in the same terminal with [concurrently](https://www.npmjs.com/package/concurrently). Output is prefixed with `[backend]` (blue) and `[frontend]` (green). Both restart or reload automatically when you save a file. Stop both with `Ctrl+C`. | Day-to-day development. The SSH tunnel must be open first. |
| `npm run build` | Compiles the backend with `tsc` to `backend/dist`, then type checks and builds the frontend with Vite to `frontend/dist`. Stops at the first error. | To check that everything compiles, and before deploying. |
| `npm run lint` | Runs ESLint in `backend`, then in `frontend`. | Before you push or open a pull request. |
| `npm test` | Runs the frontend tests once with Vitest and exits. | Before you push or open a pull request. |

`npm run lint`, `npm test` and `npm run build` are the same checks GitHub Actions runs on every pull request, so running them locally first saves you a failed CI run.

#### Scripts in `backend` and `frontend`

You can also run scripts in one part of the project only, either with `cd backend` / `cd frontend` or with `--prefix` from the root (for example `npm run dev --prefix backend`). This is useful if you only work on one side, or want the backend and frontend output in separate terminals.

| Folder | Command | What it does |
| ---------- | ----------------- | ----------------------------------------------------------------------------- |
| `backend` | `npm run dev` | Starts the GraphQL server and restarts it when you change a file. |
| `backend` | `npm start` | Runs the compiled server from `dist/`. Run `npm run build` first. |
| `frontend` | `npm run dev` | Starts the Vite dev server on http://localhost:5173/project2/. |
| `frontend` | `npm test` | Runs Vitest in watch mode, so the tests run again every time you save a file. |
| `frontend` | `npm run preview` | Serves the production build from `dist/` locally. Run `npm run build` first. |

## Testing

See [frontend/src/tests/README.md](frontend/src/tests/README.md) for what we test, how the tests are organised and how to run them.

To run all tests from the repo root:

```bash
npm test
```

Lint, tests and build also run automatically on every pull request through GitHub Actions ([.github/workflows/ci.yml](.github/workflows/ci.yml)).

TODO! The testing coverage is:

### Setup
## Known issues

- Clone the repo: `git clone <link>`
- `cd frontend`
- `npm install`
- `npm run dev`

TODO!
3 changes: 0 additions & 3 deletions backend/.gitignore

This file was deleted.

Loading
Loading