Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,7 @@ short, it was used for:
Where AI contributed directly to a piece of code, there is a comment saying
so, for example in [frontend/app/api/types/index.ts](frontend/app/api/types/index.ts) and
[frontend/app/root.tsx](frontend/app/root.tsx).

## Deployment

For more details on deploying the solution on a VM, see the [deployment documentation](/docs/deployment.md).
166 changes: 166 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Deployment

## Install dependencies

Start by installing our dependencies:

- Install [node 24](https://nodejs.org/en/download)
- Install [pnpm](https://pnpm.io/installation)
- Install [PostgreSQL 18](https://www.postgresql.org/download/)
- Install [pm2](https://pm2.keymetrics.io/)

The binaries provided by PostgreSQL may not be added to path automatically.
If the commands `pg_ctl` and `initdb` fail, do the following:

```sh
cd ~
touch .profile
nano .profile
# And add the following line: PATH=$PATH:/usr/lib/postgresql/18/bin/

# Apply the changes
source .profile
```

## Clone the project and set it up

Clone the project:

```sh
git clone https://git.ntnu.no/IT2810-H26/T37-Project-2.git
cd T37-Project-2
```

### Environment variables

This step needs to be done only whenever environment variables are updated (`.env`).

Set the correct environment values for the frontend:

```sh
cd frontend
cp .env.example .env
nano .env # and change the VITE_API_URL
```

And do the same for the backend:

```sh
cd backend
cp .env.example .env
nano .env # and change variables if needed
```

### Build the frontend

Build the frontend and move the content to the correct folder:

```sh
cd frontend
pnpm build
sudo mv build/client/ /var/www/html/project2
```

> [!CAUTION]
> We only move the `client/` folder from the build!
> We do not use React Router's server-side functionality, because our frontend does not use server-side rendering (SSR).
> See [react-router.config.ts](./frontend/react-router.config.ts)
The move must be executed as sudo because the `/var` folders are owned by `root`.

### Building the backend

Build the backend like so:

```sh
cd backend
pnpm build
```

### Prepare the database

We need the seed book data file.
For more details, please check the [backend README.md](./backend/README.md).

Let's download the dataset, unzip and place it in the correct folder:

```sh
curl -L -o comprehensive-literary-greats-dataset.zip https://www.kaggle.com/api/v1/datasets/download/thedevastator/comprehensive-literary-greats-dataset
unzip comprehensive-literary-greats-dataset.zip
# After unzipping, a file named "books_1.Best_Books_Ever.csv" will be placed
# in the current working directory.

mv books_1.Best_Books_Ever.csv ./backend/src/db/seed/book-data.csv
rm comprehensive-literary-greats-dataset.zip
```

Set up the database as usual:

```sh
cd backend
pnpm db:setup
```

> [!NOTE]
> If you receive permission errors, add your user to the `postgres` group by running the following command:
> `sudo usermod -aG postgres $USER`
## Running the project

The frontend is already handling by the Apache web server by being placed in `/var/www/html/project2`.

In order to run the backend, we use `pm2`.

The first time project is run:

```sh
cd backend
pm2 start --name "backend" --interpreter="/bin/bash" pnpm -- start
```

Afterwards, after changing the backend and building it, it's enough to restart it:

```sh
# This command can be done in any directory on the machine!
pm2 restart backend
```

## Our VM setup

This is what is set up on our VM (`it2810-37.idi.ntnu.no`, Ubuntu 26.04).
Apache was already installed and running.

### Installed packages

```sh
# Node 24 from NodeSource
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash -
sudo apt install -y nodejs

# pnpm, installed globally
sudo npm install -g pnpm@12

# PostgreSQL 18
sudo apt install -y postgresql
```

### Apache config for client-side routes

React Router handles routes like `/project2/book/5` in the browser. Without
this config, opening such a URL directly or reloading the page gives a 404,
because Apache looks for a file with that path. `FallbackResource` makes
Apache serve `index.html` instead, so the app can load and show the right page.
It only applies to the `project2` folder.

```sh
sudo tee /etc/apache2/conf-available/project2.conf > /dev/null <<'CONF'
<Directory /var/www/html/project2>
FallbackResource /project2/index.html
</Directory>
CONF
sudo a2enconf project2
sudo apache2ctl configtest # should print "Syntax OK"
sudo systemctl reload apache2
```

This was only done once, and should only need to be run once.
2 changes: 2 additions & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Must be changed to http://it2810-37.idi.ntnu.no:3001/ for production
VITE_API_URL = http://localhost:3001
15 changes: 10 additions & 5 deletions frontend/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import { TooltipProvider } from "~/components/ui/Tooltip";

// Created outside the component tree so the cache survives re-renders.
const apolloClient = new ApolloClient({
link: new HttpLink({ uri: "http://localhost:3001/" }),
link: new HttpLink({
uri: (import.meta.env.VITE_API_URL as string) || "http://localhost:3001/",
}),
cache: new InMemoryCache(),
});

Expand All @@ -36,21 +38,24 @@ export function Layout({ children }: { children: React.ReactNode }) {
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon.png"
href={`${import.meta.env.BASE_URL}favicon/apple-touch-icon.png`}
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png"
href={`${import.meta.env.BASE_URL}favicon/favicon-32x32.png`}
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon/favicon-16x16.png"
href={`${import.meta.env.BASE_URL}favicon/favicon-16x16.png`}
/>
<link
rel="manifest"
href={`${import.meta.env.BASE_URL}favicon/site.webmanifest`}
/>
<link rel="manifest" href="/favicon/site.webmanifest" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
Expand Down
8 changes: 4 additions & 4 deletions frontend/public/favicon/site.webmanifest
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "",
"short_name": "",
"name": "Readr",
"short_name": "Readr",
"icons": [
{
"src": "/android-chrome-192x192.png",
"src": "android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"src": "android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
Expand Down