diff --git a/README.md b/README.md index 9b30bc7..2597c07 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # T28 - Project 2: Search for Countries +[Open the deployed app](http://it2810-28.idi.ntnu.no/project2/) — requires the NTNU network or VPN. + Repository for team IT2810-H26-T28, Project 2. ## About the Project -The application allows users to search, filter, and sort through a catalogue of countries around the world, as well as explore detailed information about each country (e.g. capital, continent, languages, population, area, and flag). Users should also be able to add their own data related to countries (whether they have visited or want to visit a country), which will be stored persistently on the server. +The application allows users to search, filter, and sort through a catalogue of countries around the world, as well as explore detailed information about each country (e.g. capital, continent, languages, population, area, and flag). Users can mark countries as visited or want to visit, with statuses stored persistently on the server. The project is being developed in stages. The frontend is built with React and TypeScript, and communicates with a GraphQL backend backed by PostgreSQL. @@ -12,7 +14,7 @@ The dataset also includes more than 34,000 cities linked to their respective cou ## Status -The project is under active development. The frontend uses Apollo Client to fetch country data from the GraphQL backend, which retrieves data from PostgreSQL. The backend is hosted on the group's NTNU VM and managed using systemd. +The project is under active development. The frontend uses Apollo Client to fetch country data from the GraphQL backend, which retrieves data from PostgreSQL. The frontend is served by Apache under `/project2/` on the group's NTNU VM, and the backend is managed using systemd. Users can mark countries as visited or want to visit. The data is stored in the database and linked to an anonymous ID per browser, so no login is required. @@ -28,7 +30,7 @@ Users can mark countries as visited or want to visit. The data is stored in the - Quiz attempts are saved in the browser's IndexedDB and can be viewed on the quiz results page. - Loading, error, and empty-result states for searches and data updates. - Apollo Client integration and cache policies for GraphQL queries and paginated results. -- PostgreSQL database and GraphQL backend hosted on the group's NTNU VM; the backend runs as a systemd service. +- Frontend hosted by Apache under `/project2/`, with PostgreSQL and the GraphQL backend on the same NTNU VM; the backend runs as a systemd service. - **Accessibility and sustainable web development**: Accessibility testing has covered keyboard navigation, VoiceOver, and Lighthouse. The app uses semantic HTML and ARIA where necessary. We also make conscious choices regarding data usage, caching, and performance to reduce unnecessary resource consumption. See our [Accessibility and Sustainability Plan](docs/planAccessibilityAndSustainability.md). ## User data and anonymous browser ID @@ -62,7 +64,7 @@ To support larger datasets, searching, filtering, and pagination are handled by The city dataset provides a larger set of records for evaluating database queries and scalability. -For deployment details, see [Backend Deployment](docs/backendDeployment.md). +For deployment details, see [Deployment on the NTNU VM](docs/backendDeployment.md). ## Pagination and Caching @@ -76,7 +78,7 @@ This is expected Apollo Client cache behavior and helps avoid unnecessary networ ### Prerequisites -- Node.js 24+ and npm +- Node.js 24 and npm - Access to the NTNU network or VPN to connect to the deployed backend To run the frontend using the deployed backend, no direct database access or SSH access to the VM is required. @@ -90,7 +92,7 @@ npm ci Connect to the NTNU network or VPN and create a `.env.local` file in the repository root: ```env -VITE_GRAPHQL_URL=http://it2810-28.idi.ntnu.no:3001/graphql +VITE_GRAPHQL_URL=http://it2810-28.idi.ntnu.no:3001/ ``` Start the frontend: @@ -99,17 +101,25 @@ Start the frontend: npm run dev ``` -Open [http://localhost:5173/](http://localhost:5173/) in your browser. The frontend uses the deployed backend, so you do not need database credentials or SSH access to the VM. +Open [http://localhost:5173/project2/](http://localhost:5173/project2/) in your browser. The frontend uses the deployed backend, so you do not need database credentials or SSH access to the VM. To develop the backend locally, see [Database Setup](docs/databaseSetup.md) for the required database configuration and SSH tunnel instructions. -### Backend Deployment (NTNU VM) +### Deployment (NTNU VM) + +Apache serves the production frontend at `/project2/` on `it2810-28.idi.ntnu.no`. The GraphQL backend and PostgreSQL database run on the same VM. -The GraphQL backend and PostgreSQL database are hosted on the group's NTNU VM (`it2810-28.idi.ntnu.no`). +The backend runs as the `t28-backend` systemd service, allowing it to continue running after SSH logout and start automatically when the VM boots. The browser connects directly to the GraphQL API on port 3001. -The backend runs as a systemd service (`t28-backend`), allowing it to continue running after SSH logout and start automatically when the VM boots. +The frontend uses `base: '/project2/'` in `vite.config.ts`. Build it with the deployed API address: -For instructions on configuring, restarting, and monitoring the backend service, see [Backend Deployment](docs/backendDeployment.md). +```bash +VITE_GRAPHQL_URL=http://it2810-28.idi.ntnu.no:3001/ npm run build +``` + +The API address is embedded at build time. Changing it requires rebuilding and uploading the frontend again. + +See [Deployment on the NTNU VM](docs/backendDeployment.md) for upload instructions, Apache configuration, backend updates, and verification from another machine. ### Other Commands @@ -191,6 +201,8 @@ Examples include working with React and TypeScript, understanding GraphQL querie AI has also been used to help troubleshoot backend deployment on the NTNU VM, configure the systemd service, resolve Git-related issues, and improve technical documentation, including the README. +For the Apache deployment in #22, ChatGPT provided step-by-step deployment guidance, suggested Apache configuration and an HTTP-compatible replacement for `crypto.randomUUID()`, and drafted deployment documentation. We applied the changes and checked them with ESLint, Prettier, the existing 34 frontend tests, a production build, Apache configuration and HTTP checks, and manual loading of the deployed app. + Using AI to explain concepts and provide feedback on our own code has helped us better understand the technologies used in this project. It has also made debugging and troubleshooting more efficient, particularly when working with unfamiliar tools and configurations. All AI-generated suggestions have been reviewed and evaluated before being applied, and the group remains responsible for the final implementation. @@ -211,10 +223,11 @@ data/ └── countries.json deploy/ +├── project2.conf # Apache configuration for /project2 └── t28-backend.service # systemd service configuration docs/ -├── backendDeployment.md # Backend deployment on NTNU VM +├── backendDeployment.md # Frontend and backend deployment on NTNU VM ├── databaseSetup.md ├── design.md └── planAccessibilityAndSustainability.md @@ -260,7 +273,7 @@ cd backend npm run db:seed ``` -The seed script can be run multiple times without creating duplicate records. The script also creates the `user_country` table for user-generated data. Existing user data is never overwritten when the script runs again. +The seed script can be run multiple times without creating duplicate records. The script also creates the `user_country` table for user-generated data. Existing rows in `user_country` are preserved, but the legacy `user_country_status` table is dropped if it exists. Review the script before reseeding an existing database; see [Deployment on the NTNU VM](docs/backendDeployment.md). ## Sustainability Measures and Evaluation diff --git a/deploy/project2.conf b/deploy/project2.conf new file mode 100644 index 0000000..3edd242 --- /dev/null +++ b/deploy/project2.conf @@ -0,0 +1,11 @@ + + Options -Indexes -MultiViews + AllowOverride None + Require all granted + DirectoryIndex index.html + FallbackResource /project2/index.html + + + + FallbackResource disabled + \ No newline at end of file diff --git a/docs/backendDeployment.md b/docs/backendDeployment.md index 6ebf23e..d74b216 100644 --- a/docs/backendDeployment.md +++ b/docs/backendDeployment.md @@ -1,214 +1,266 @@ -# Backend Deployment +# Deployment on the NTNU VM ## Overview -The application consists of a React frontend, a GraphQL backend, and a PostgreSQL database. +The application consists of a React frontend, a GraphQL backend built with Node.js, TypeScript and Apollo Server, and a PostgreSQL database. -The backend and database are hosted on the NTNU virtual machine (VM), `it2810-28.idi.ntnu.no`. +The deployed app is available at [http://it2810-28.idi.ntnu.no/project2/](http://it2810-28.idi.ntnu.no/project2/). Access requires the NTNU network or VPN. -The backend is built with Node.js, TypeScript, and Apollo Server. It processes requests from the frontend and retrieves data from PostgreSQL. +The browser downloads the frontend from Apache, then sends GraphQL requests to the backend. The backend queries PostgreSQL and returns the results. -## How the System Works +| Component | Current VM configuration | +| ------------------------- | ----------------------------------------------------------------- | +| Frontend | Apache on port 80, serving `/var/www/html/project2` | +| GraphQL API | `http://it2810-28.idi.ntnu.no:3001/` | +| Backend service | `t28-backend`, managed by systemd | +| Backend service user | `guroklo` | +| Backend working directory | `/home/guroklo/T28-Project-2/backend` | +| Backend start command | `/usr/bin/npm run start` | +| Database | PostgreSQL on the same VM. See [Database Setup](databaseSetup.md) | -When a user interacts with the application, the frontend sends GraphQL requests to the backend. +Systemd keeps the backend running after SSH logout, starts it at boot when enabled, and restarts it on failure. Do not start a second backend manually on port 3001. -The backend processes these requests, queries the PostgreSQL database, and returns the requested data to the frontend. +## Prerequisites and Command Conventions -For example, when a user opens a country page, the frontend requests information about that country. The backend retrieves the relevant data from PostgreSQL and returns it for display. +- SSH and sudo access to the VM, and access to the repository. +- Node.js 24 and npm on the build machine and VM. The systemd service uses the system installation, not a developer's local nvm installation. +- An existing backend checkout and configured `backend/.env` on the VM. Initial database setup is covered in [Database Setup](databaseSetup.md). +- Apache is already installed on the current VM. -The communication flow is: +Replace every `` below with your own NTNU username, including removing the angle brackets. Do not replace `guroklo` in the backend commands: those commands target the existing service's checkout. If the service is moved later, update the service file and this document together. - User - | - v - React Frontend - | - | GraphQL request - v - Node.js Backend (NTNU VM) - | - | SQL query - v - PostgreSQL Database (NTNU VM) +Commands are for a macOS/Linux shell. Run them one at a time and stop if a command fails. Coordinate deployments with the group so two people do not update the running application simultaneously. -The backend handles data retrieval, searching, filtering, and pagination, while the frontend handles the user interface. +Passwords, tokens, private SSH keys and `.env` contents must not be committed or included in this document. -## Backend Hosting +## 1. Update the Backend — VM -The backend runs on the NTNU VM and is managed by systemd, a Linux service manager. - -Systemd allows the backend to: - -- Continue running after SSH sessions are closed. -- Start automatically when the VM reboots. -- Restart automatically if the backend process fails. -- Be monitored through service status and logs. - -The service configuration is defined in `deploy/t28-backend.service`. -The backend is available at [http://it2810-28.idi.ntnu.no:3001/](http://it2810-28.idi.ntnu.no:3001/) when connected to the NTNU network or VPN. - -The systemd service runs under a Linux user with access to the backend directory. The `User` and `WorkingDirectory` settings must match the configuration on the VM. - -## Installing the systemd Service - -The backend is managed by systemd to ensure that it continues running after SSH logout and starts automatically when the VM boots. - -The service configuration is stored in `deploy/t28-backend.service`. - -To install the service on the VM, first ensure that the backend dependencies are installed and that `backend/.env` is configured correctly. - -The `User` and `WorkingDirectory` values in the service file must match the Linux user and project location on the VM. - -Copy the service file to the systemd configuration directory: +From your own machine, log in: ```bash -sudo cp deploy/t28-backend.service /etc/systemd/system/ +ssh @it2810-28.idi.ntnu.no ``` -Reload systemd to register the service: +The terminal prompt should now identify `it2810-28`. Check the active configuration, Node version and checkout: ```bash -sudo systemctl daemon-reload +systemctl cat t28-backend --no-pager +/usr/bin/node --version +sudo -u guroklo git -C /home/guroklo/T28-Project-2 status --short --branch ``` -Enable the service to start automatically when the VM boots: +The service should match the table above and Node should be version 24. Proceed when the checkout is on `main` with no local changes. If changes exist, inspect them and agree with their owner how to preserve them before updating. Do not reset or discard them blindly. + +Fetch and apply the latest main, then install dependencies: ```bash -sudo systemctl enable t28-backend +sudo -u guroklo git -C /home/guroklo/T28-Project-2 fetch origin +sudo -u guroklo git -C /home/guroklo/T28-Project-2 merge --ff-only origin/main +sudo -u guroklo -H /usr/bin/npm --prefix /home/guroklo/T28-Project-2/backend ci --include=dev ``` -Start the backend: +If a database update is needed, review the seeding section below before restarting. For an ordinary code update, restart and inspect the service: ```bash -sudo systemctl start t28-backend +sudo systemctl restart t28-backend +systemctl status t28-backend --no-pager +sudo -u guroklo git -C /home/guroklo/T28-Project-2 log -1 --oneline ``` -Verify that the service is running: +Expect `active (running)`. Record the backend commit in the deployment or PR notes. + +Test the API on the VM: ```bash -sudo systemctl status t28-backend +curl -sS --max-time 15 http://localhost:3001/ \ + -H 'Content-Type: application/json' \ + --data '{"query":"{ country(code: \"NO\") { code name status } }"}' ``` -The service should show `active (running)`. +Expected response: -These installation steps are only required when setting up the service for the first time or when reinstalling its configuration. +```json +{ "data": { "country": { "code": "NO", "name": "Norway", "status": null } } } +``` -## Starting and Restarting the Backend +This confirms that the API can retrieve a country and recognises `status`. Without a user ID, `status` is null; this test does not prove that status persistence works. -To access the VM through SSH, a connection to the NTNU network or NTNU VPN is required. +Return to your own machine: ```bash -ssh @it2810-28.idi.ntnu.no +exit ``` -Once connected, the backend can be managed using systemd. +## 2. Build and Upload the Frontend — Local Machine -**Start the backend:** +Run these commands in the local repository root. For a normal deployment, first check for uncommitted changes, then update `main`: ```bash -sudo systemctl start t28-backend +git status ``` -**Restart the backend:** +If the working tree is clean: ```bash -sudo systemctl restart t28-backend +git switch main +git pull --ff-only origin main ``` -**Stop the backend:** +When testing an unmerged change, stay on its feature branch instead of switching to main. Record the frontend commit and any uncommitted changes in the deployment notes. + +If using nvm, select Node 24: ```bash -sudo systemctl stop t28-backend +nvm install 24 +nvm use 24 ``` -**Check the backend status:** +Install dependencies, check the code and build: ```bash -sudo systemctl status t28-backend +npm ci --include=dev +npm run lint +npm run format:check +npm test +VITE_GRAPHQL_URL=http://it2810-28.idi.ntnu.no:3001/ npm run build ``` -**View backend logs:** +Vite must have `base: '/project2/'` in `vite.config.ts`. The generated `dist/index.html` should reference `/project2/assets/`: ```bash -sudo journalctl -u t28-backend -f +cat dist/index.html +git log -1 --oneline ``` -The backend is configured to start automatically when the VM reboots, so manual startup is normally unnecessary. - -## Updating the Backend +`VITE_GRAPHQL_URL` is embedded in the frontend at build time. Changing a VM environment variable later does not change an uploaded build. Rebuild and upload again when changing the API address. Do not put secrets in `VITE_` variables or commit `dist/`. -When changes to the backend are merged into the main branch, the running backend on the VM must be updated to use the latest code. - -Connect to the NTNU network or VPN and log in to the VM using SSH: +Upload the build and Apache configuration: ```bash +ssh @it2810-28.idi.ntnu.no 'mkdir -p ~/project2-upload' +scp -r dist/. @it2810-28.idi.ntnu.no:~/project2-upload/ +scp deploy/project2.conf @it2810-28.idi.ntnu.no:~/project2.conf ssh @it2810-28.idi.ntnu.no ``` -Navigate to the project directory on the VM: +## 3. Publish the Frontend and Configure Apache — VM + +Copy the uploaded build into the Apache directory: ```bash -cd ~/T28-Project-2 +sudo mkdir -p /var/www/html/project2 +sudo cp -r "$HOME/project2-upload/." /var/www/html/project2/ +sudo chmod -R a+rX /var/www/html/project2 ``` -Make sure you are on the main branch and pull the latest changes: +Only upload the built frontend, not the repository or `.env` files. This copy method overwrites matching files and retains older hashed assets; it does not remove stale files automatically. It does not change `/var/www/html/project1`. + +On first setup, or after changing `deploy/project2.conf`, install and enable the configuration: ```bash -git switch main -git pull origin main +sudo cp "$HOME/project2.conf" /etc/apache2/conf-available/project2.conf +sudo a2enconf project2 +sudo apache2ctl configtest ``` -Install or update backend dependencies: +Only if the check reports `Syntax OK`, reload Apache: ```bash -cd backend -npm ci +sudo systemctl reload apache2 ``` -Restart the systemd service to apply the updated backend code: +Updating static frontend files alone does not require a reload. -```bash -sudo systemctl restart t28-backend -``` +The configuration serves `index.html`, disables directory listings, and falls back to `/project2/index.html` for client-side routes. Missing files under `/project2/assets` still return 404. The frontend router must also support `/project2`; Apache does not create React routes. -Verify that the backend is running: +Check Apache: ```bash -sudo systemctl status t28-backend +curl -s -o /dev/null -w '%{http_code}\n' http://localhost/project2/ +curl -s -o /dev/null -w '%{http_code}\n' http://localhost/project2/deploy-check +curl -s -o /dev/null -w '%{http_code}\n' http://localhost/project2/assets/does-not-exist.js ``` -If the service fails to start, inspect the logs: +Expected codes: `200`, `200`, `404`. The artificial `deploy-check` path tests the fallback only, not a real application route. + +## 4. Verify from Another Machine + +Leave the SSH session with `exit`. From your own machine on NTNU or VPN, test port 3001: ```bash -sudo journalctl -u t28-backend -n 50 +curl -sS --max-time 15 http://it2810-28.idi.ntnu.no:3001/ \ + -H 'Content-Type: application/json' \ + --data '{"query":"{ country(code: \"NO\") { code name status } }"}' ``` -The backend should now be running the updated code. +Expect the same country response as on the VM. Inspect the response body for GraphQL errors; an HTTP 200 alone does not prove success. -If the systemd service configuration has also changed, copy the updated service file to `/etc/systemd/system/` and run `sudo systemctl daemon-reload` before restarting the service. +Open [the deployed app](http://it2810-28.idi.ntnu.no/project2) and check: -## Database +- The app loads and displays data without an SSH session or a local development server. +- Search and country details work. +- Marking a country as Visited survives a page reload. +- Changing it to Want to visit survives a page reload. +- Removing the status survives a page reload. +- Once frontend routing is implemented in #71, opening and refreshing an actual detail URL works. -PostgreSQL runs on the same VM as the backend. +Use the same browser profile for persistence checks. Statuses are stored in PostgreSQL and associated with the anonymous ID saved in that browser. A new profile has a different identity. -The database is only accessible locally on the VM and is not directly exposed to external networks. +Before closing #22, have a group member who has not deployed before follow this document. Record the tester, date, deployed commit(s), results and any corrections in the PR or issue. Do not mark an unperformed check as passed. -The backend connects to PostgreSQL using environment variables stored in `backend/.env`. +## Database and Seeding -This file contains database credentials and is excluded from Git to protect sensitive information. +The backend reads credentials from `/home/guroklo/T28-Project-2/backend/.env`. Database setup and local development through an SSH tunnel are documented in [Database Setup](databaseSetup.md). -For more information, see [Database Setup](databaseSetup.md). +Seeding is not required for every deployment. Run it only when schema or reference data changes require it. Inspect the current `backend/src/seed.ts` first and back up affected data before a destructive change. -## Frontend Communication +The reviewed seed script creates missing tables and upserts country/city data. It preserves rows in `user_country`, but drops the legacy `user_country_status` table. `CREATE TABLE IF NOT EXISTS` does not migrate the structure of an existing table. -The frontend uses Apollo Client to communicate with the GraphQL API. +If seeding is required after review: -The backend endpoint is configured through the `VITE_GRAPHQL_URL` environment variable. +```bash +sudo -u guroklo -H sh -c 'cd /home/guroklo/T28-Project-2/backend && /usr/bin/npm run db:seed' +``` + +Do not publish database credentials in logs, screenshots or documentation. + +## Installing or Updating the systemd Service -This allows the frontend to communicate with different backend environments without changing the application code. +The existing service definition is versioned in `deploy/t28-backend.service`. Ordinary code updates only require restarting the service. -The configured backend endpoint is [http://it2810-28.idi.ntnu.no:3001/](http://it2810-28.idi.ntnu.no:3001/). +For first installation or an intentional change to the service definition, verify its user, working directory and executable path, ensure dependencies and `.env` are configured, then run on the VM: -Users interact with the application through the frontend and do not need direct SSH access to the VM or database. +```bash +sudo cp /home/guroklo/T28-Project-2/deploy/t28-backend.service /etc/systemd/system/t28-backend.service +sudo systemctl daemon-reload +sudo systemctl enable t28-backend +sudo systemctl restart t28-backend +systemctl status t28-backend --no-pager +``` + +## Troubleshooting + +| Symptom | What to check | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| Blank page | Inspect the browser console and missing asset requests. Hard-refresh after uploading. | +| `crypto.randomUUID is not a function` | Deploy the HTTP-compatible `src/lib/userId.ts` implementation using `crypto.getRandomValues()`. Preserve existing stored IDs. | +| Browser requests localhost | Rebuild with the VM's `VITE_GRAPHQL_URL` and upload the new build. | +| API reports an unknown `status` field | Check the active service's checkout and restart it after updating. | +| API works on VM but not locally | Check NTNU/VPN access, the backend listen address and access to port 3001. | +| Status does not persist | Inspect the mutation response, user ID header and backend logs; verify database schema before considering seeding. | +| Refreshing a real route returns 404 | Check the enabled Apache fallback and the frontend router's base path. | + +Backend logs: + +```bash +sudo journalctl -u t28-backend -n 50 --no-pager +``` + +Apache configuration and error log: + +```bash +sudo apache2ctl configtest +sudo tail -n 50 /var/log/apache2/error.log +``` -The GraphQL endpoint must be reachable from the frontend. The current setup uses HTTP with CORS configured to allow frontend requests. +Do not reload Apache after a failed configuration check. diff --git a/docs/databaseSetup.md b/docs/databaseSetup.md index de03ec8..f75dd70 100644 --- a/docs/databaseSetup.md +++ b/docs/databaseSetup.md @@ -4,62 +4,116 @@ Database: PostgreSQL 18, installed directly on the VM with `apt` (not Docker). ## 1. Node.js (system-wide, required for the backend) -Node.js 24+ is required. Install it for all users (not via nvm): +Use Node.js 24. For the backend service on the VM, install it system-wide: ```bash curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - sudo apt install -y nodejs -node -v # should print v24.x +node -v ``` +The version should be `v24.x`. Skip installation if the correct version is already installed. + ## 2. PostgreSQL -1. `sudo apt install postgresql` -2. `sudo systemctl enable --now postgresql` (starts automatically after reboot) -3. Create user and database in `sudo -u postgres psql`: +1. Install PostgreSQL: + + ```bash + sudo apt install postgresql + ``` + +2. Start PostgreSQL and enable it to start automatically when the VM boots: + + ```bash + sudo systemctl enable --now postgresql + ``` + +3. Open PostgreSQL: + + ```bash + sudo -u postgres psql + ``` + + Create the database user and database if they do not already exist. Replace the example password before running: ```sql - CREATE USER t28_app WITH PASSWORD '...'; + CREATE USER t28_app WITH PASSWORD 'replace-with-a-password'; CREATE DATABASE t28_cities OWNER t28_app; ``` -4. The database only listens on `127.0.0.1:5432` and is not reachable from outside. + Exit with `\q`. + +4. Keep PostgreSQL accessible only locally on the VM. Local development uses an SSH tunnel rather than exposing the database port. ## 3. Backend connection -1. Clone the repo, go to `backend/` and run `npm install`. -2. Run `cp .env.example .env`, fill in the password (ask a group member), and run `chmod 600 .env`. -3. Test with `npm run db:check`. +In the backend checkout on the VM: -`.env` is not in git. Course staff can read it with sudo on the VM. +1. Go to `backend/` and run `npm ci`. +2. If `.env` does not already exist, run `cp .env.example .env`. +3. Fill in the database connection details. Ask a group member for the password. +4. Restrict access to the file: + + ```bash + chmod 600 .env + ``` + +5. Test the connection: + + ```bash + npm run db:check + ``` + +Do not overwrite an existing `.env` during deployment. + +`.env` is excluded from Git. Do not commit it or share its credentials in documentation or screenshots. Course staff can inspect it using sudo on the VM. + +For the existing backend service's user, directory and update instructions, see [Deployment on the NTNU VM](backendDeployment.md). ## Local development -When running the backend on a developer's machine, the backend needs access to the PostgreSQL database on the VM. +When running the backend on your own machine, it connects to PostgreSQL on the VM through an SSH tunnel. Connect to the NTNU network or VPN first. ### 1. Configure the backend +Use Node.js 24 on your own machine. + From the repository root: ```bash cd backend -npm install +npm ci +``` + +If you do not already have `backend/.env`, create it: + +```bash cp .env.example .env ``` -Configure the values in `.env` using the connection details provided by the group. Do not commit `.env` or share its credentials. +Configure `.env` using the connection details provided by the group. For the tunnel below, use `DB_HOST=localhost` and `DB_PORT=5432`. + +Do not commit `.env` or share its credentials. ### 2. Establish an SSH tunnel -If PostgreSQL is only accessible on the VM's loopback interface, open a separate terminal and run: +Open a separate terminal and run: ```bash -ssh -N -L 5432:localhost:5432 @it2810-28.idi.ntnu.no +ssh -N -L 5432:localhost:5432 @it2810-28.idi.ntnu.no ``` -Replace `` with your NTNU username. Keep this terminal open while using the database through the tunnel. +Replace `` with your NTNU username, including removing the angle brackets. -The tunnel forwards local port `5432` to port `5432` on the VM. +The tunnel forwards local port `5432` to PostgreSQL on the VM. Keep this terminal open while using the database. + +If local port `5432` is already in use, choose another local port: + +```bash +ssh -N -L 5433:localhost:5432 @it2810-28.idi.ntnu.no +``` + +In that case, set `DB_PORT=5433` in your local `backend/.env`. ### 3. Verify the database connection @@ -73,34 +127,58 @@ The command should report a successful connection and identify the `t28_cities` ### 4. Start the backend -With the SSH tunnel running and the database connection verified, run: +With the SSH tunnel running and the database connection verified, run from `backend/`: ```bash npm run dev ``` -The GraphQL server should be available at [http://localhost:3001/](http://localhost:3001/), with GraphQL requests sent to [http://localhost:3001/graphql](http://localhost:3001/graphql). +The GraphQL API is available at http://localhost:3001/. + +This starts a backend on your own machine. The deployed backend on the VM is managed separately by systemd. ### 5. Start the frontend +In the repository root, create or update `.env.local`: + +```env +VITE_GRAPHQL_URL=http://localhost:3001/ +``` + +This connects the frontend to your local backend instead of the deployed backend on the VM. + In a separate terminal, from the repository root, run: ```bash -npm install +npm ci npm run dev ``` -Open [http://localhost:5173/](http://localhost:5173/). +Open http://localhost:5173/project2/. + +Restart the frontend development server after changing `.env.local`. -The frontend and backend run as separate processes. The SSH tunnel must remain active while the backend needs the remote database. +The frontend and backend run as separate processes. Keep the SSH tunnel open while the local backend uses the database on the VM. + +The local backend uses the shared VM database, so changes to data also affect that database. Use the project's separate API test setup for automated tests; see [Testing](../README.md#testing). ## Seeding the database -Run on the VM (or locally with a configured `backend/.env`): +Seeding creates missing tables and imports the country and city dataset. It is not required for every deployment. + +Before running it, review `backend/src/seed.ts` and confirm which database your `.env` points to. Back up any data that could be affected. + +From the repository root: ```bash cd backend npm run db:seed ``` -The script creates the tables `country`, `city` and `user_country` if they do not exist, then loads `data/countries.json` and `data/cities.json`. It can be run any number of times: rows are upserted by primary key, so nothing is duplicated, and `user_country` (user-generated data) is never modified. The old `user_country_status` table is removed if it exists. To refresh the dataset first, run `npm run fetch-data` in the repository root. +When running locally against the VM database, keep the SSH tunnel open. For running the script as the existing backend service user on the VM, follow [Deployment on the NTNU VM](backendDeployment.md#database-and-seeding). + +The script creates missing tables (`country`, `city` and `user_country`) and loads `data/countries.json` and `data/cities.json`. Country and city rows are upserted by primary key, avoiding duplicates. Existing rows in `user_country` are preserved. + +The legacy `user_country_status` table is dropped if it exists. Creating missing tables does not update the structure of tables that already exist. + +To refresh the source dataset first, run `npm run fetch-data` from the repository root. diff --git a/src/lib/userId.ts b/src/lib/userId.ts index dad3d72..2716e57 100644 --- a/src/lib/userId.ts +++ b/src/lib/userId.ts @@ -1,5 +1,24 @@ const STORAGE_KEY = 'userId'; +/** Generates a UUID v4, including on the VM's HTTP origin. */ +function createUserId(): string { + const bytes = crypto.getRandomValues(new Uint8Array(16)); + + // Set the UUID version (4) and variant bits. + bytes[6] = (bytes[6]! & 0x0f) | 0x40; + bytes[8] = (bytes[8]! & 0x3f) | 0x80; + + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join(''); + + return [ + hex.slice(0, 8), + hex.slice(8, 12), + hex.slice(12, 16), + hex.slice(16, 20), + hex.slice(20), + ].join('-'); +} + /** Reuses a browser-local UUID so status mutations map to the same anonymous user. */ export function getUserId(): string { const existingId = localStorage.getItem(STORAGE_KEY); @@ -8,7 +27,7 @@ export function getUserId(): string { return existingId; } - const newId = crypto.randomUUID(); + const newId = createUserId(); localStorage.setItem(STORAGE_KEY, newId); return newId; } diff --git a/vite.config.ts b/vite.config.ts index 590efda..f2133d2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,6 +3,7 @@ import { defineConfig } from 'vitest/config'; // https://vite.dev/config/ export default defineConfig({ + base: '/project2/', plugins: [react()], test: { environment: 'jsdom',