diff --git a/Frontend/vite.config.ts b/Frontend/vite.config.ts index d789a7c..e6cbea0 100644 --- a/Frontend/vite.config.ts +++ b/Frontend/vite.config.ts @@ -4,6 +4,8 @@ import { defineConfig } from 'vite' // https://vite.dev/config/ export default defineConfig({ + // Served from a subfolder of the web root; must match PROJECT_NAME in deploy.sh + base: '/project2/', plugins: [ react(), babel({ presets: [reactCompilerPreset()] }) diff --git a/README.md b/README.md index c201585..9e3b103 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,10 @@ For documentation in this repository, check the `docs` folder. Each file will contain a short description of what it documents. ### Website plan (submisson 1.) + For reviewing the first submisson we recommend reading PRD.md first, then the Spec.md and the rest of the docs. + +### Backend configured (submission 2.) + +The API and database are now up and running, though without any data being loaded into the frontend (for now). +In the next handin, this will be handled. diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..a79f1d2 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +# +# This script can be triggered with a CRON job for polling. +# This will keep the webpage always up to date. +# + +# Sets the failure mode (if one command fails, dont continue) +set -euo pipefail + + +# Set to wherever the repo is stored on the server +REPO_DIR="/IT2810/T11-Project-2" +REPO_PROJECT_DIR="$REPO_DIR/Frontend" +REPO_BUILD_RESULT="$REPO_PROJECT_DIR/dist" +REPO_BACKEND_DIR="$REPO_DIR/backend" + +# /var/www/html is the web root. Each project is deployed to its own +# subfolder: project2 -> /var/www/html/project2 +PROJECT_NAME="project2" +DEST_DIR="/var/www/html/$PROJECT_NAME" + +cd "$REPO_DIR" + +echo "Fetching latest from main..." +git fetch origin main + +# Get local commit and Remote commit +LOCAL=$(git rev-parse HEAD) +REMOTE=$(git rev-parse origin/main) + +# Decreasing how often the script runs. An additional pull does no harm +# If they are the same, no new commits are in. Exit +#if [ "$LOCAL" = "$REMOTE" ]; then +# echo "Already up to date ($LOCAL). Nothing to deploy." +# exit 0 +#fi + +# Otherwise, pull from origin +#echo "Updating $LOCAL -> $REMOTE" +#git reset --hard origin/main + +cd "$REPO_PROJECT_DIR" + +echo "==== Frontend ====" + +echo "Do a clean NPM install..." +npm ci + +# Building the docker image from the new source code +echo "Building site..." +npm run build + +echo "Build complete." + +echo "Removing current web-page..." +rm -rf "$DEST_DIR" + +echo "Moving files..." +mv $REPO_BUILD_RESULT $DEST_DIR + +echo "Deployed $REMOTE frontend" + +echo "==== Backend API ====" + +# The API is only deployed once backend/ exists on main. +if [ -f "$REPO_BACKEND_DIR/package.json" ]; then + cd "$REPO_BACKEND_DIR" + + echo "Do a clean NPM install..." + npm ci + + # Run the API as a systemd service so it keeps running between + # deploys and across reboots. Needs passwordless sudo for systemctl. + echo "Installing systemd service..." + NPM_BIN="$(command -v npm)" + # systemd services get a minimal PATH, so npm's '#!/usr/bin/env node' + # shebang cannot find node. Point the service at the node this script sees. + NODE_BIN_DIR="$(dirname "$(command -v node)")" + sudo tee /etc/systemd/system/t11-api.service > /dev/null < start +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable t11-api.service +sudo systemctl restart t11-api.service +``` + +- The `PATH` line is required. systemd gives services a minimal default `PATH`, so npm's `#!/usr/bin/env node` shebang fails with `env: 'node': No such file or directory` (exit 127). The script resolves node's directory with `command -v node` in the cron environment, where node is known to be available. +- The API port comes from `backend/.env` (`GRAPHQL_PORT`, default `3001`). The deploy script does not override it. +- `enable` starts the API on boot, `Restart=on-failure` restarts it after crashes, and each deploy restarts it to pick up new code. +- The cron user needs passwordless sudo for `systemctl` and for writing the unit file. + +## Useful commands + +```bash +# Run a deploy manually +/IT2810/T11-Project-2/deploy.sh + +# API status and logs +sudo systemctl status t11-api +sudo journalctl -u t11-api -f + +# Restart the API without a full deploy +sudo systemctl restart t11-api +``` + +See also: `github-runners.md` (self-hosted runner), `postgresql-setup.md` (database on the VM). diff --git a/docs/github-runner-setup.md b/docs/github-runners.md similarity index 100% rename from docs/github-runner-setup.md rename to docs/github-runners.md diff --git a/docs/technical-choices.md b/docs/technical-choices.md index f216dbb..aab621b 100644 --- a/docs/technical-choices.md +++ b/docs/technical-choices.md @@ -38,3 +38,10 @@ The result is 12,505 releases and 268,159 tracks across 10 tables (~19 MB of SQL The subset is reproducible: one command (`bash scripts/make_subset.sh` in `Database/`) regenerates it from the raw dump and re-validates it against the schema with foreign keys enabled. The full pipeline, every decision and the pitfalls encountered are documented in `Database/AI-context.md`. There is more de-duplication that still needs to be done (e.g. the same album appearing under slightly different titles, or a 15-artist release counting towards several catalogues), but treating the different mediums of the same release (CD and Vinyl) as one already brings the data down to a workable size. + +## Deployment + +Deployment is handled by `deploy.sh` in the repo root, triggered by a cron job on the VM that polls the repository. This keeps the site up to date without a CI/CD workflow - the self-hosted runner (see `github-runners.md`) is not involved in deployment. The mechanics are documented in `deployment.md`; the choices behind them: + +- **Frontend as static files.** The Vite build output (`Frontend/dist`) is moved to `/var/www/html/project2`, where the web server serves it. The VM hosts several projects, so each gets its own subfolder of the web root. A deploy is therefore just "build, delete old, move new". +- **Backend as a systemd service.** The GraphQL API runs as the `t11-api` systemd unit, matching how PostgreSQL is already managed on the VM. `enable` starts it on boot, `Restart=on-failure` keeps it alive after crashes, and every deploy restarts it to pick up new code. We chose systemd over pm2 or Docker because the VM already uses it and it needs no extra tooling.