diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml index af511d0..bee3b28 100644 --- a/.github/workflows/e2e_test.yml +++ b/.github/workflows/e2e_test.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 cache: "npm" - name: Install Node.js dependencies diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 3c29cab..32db1f1 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -33,7 +33,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install Node.js dependencies run: npm ci diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7e11113 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,71 @@ +# Copied from: https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile + +FROM node:20-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry during the build. +# ENV NEXT_TELEMETRY_DISABLED 1 + +RUN \ + if [ -f yarn.lock ]; then yarn run build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production +# Uncomment the following line in case you want to disable telemetry during runtime. +# ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Set the correct permission for prerender cache +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 +# set hostname to localhost +ENV HOSTNAME "0.0.0.0" + +# server.js is created by next build from the standalone output +# https://nextjs.org/docs/pages/api-reference/next-config-js/output +CMD ["node", "server.js"] \ No newline at end of file diff --git a/README.md b/README.md index f6d9b6a..434e508 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,29 @@ This repo contains a Next.js app that randomly generates Settlers of Catan board algorithms. The app is a modern version of the original Python Kivy repo which can be found [here](https://github.com/stuart-bradley/Catan-Randomiser). +## Features + +- Generates boards for the base game, as well as Seafarers and 6 player expansions. +- Allows the saving and sharing of boards via unique URLs. + - These URLs can also be tweaked to modify the boards. +- Seafarers boards include a number of different randomisation algorithms to generate different geographical features. +- Responsive design for mobile. + +## Screenshots + +![Screenshots of various types of board generation](documentation/images/catan-randomiser-js-examples.png) + +The colours correspond as follows: + +- Wheat: ![#ccb804](https://placehold.co/15x15/ccb804/ccb804.png) +- Sheep: ![#a5c13f](https://placehold.co/15x15/a5c13f/a5c13f.png) +- Rock: ![#7f7f7f](https://placehold.co/15x15/7f7f7f/7f7f7f.png) +- Tree: ![#3a7044](https://placehold.co/15x15/3a7044/3a7044.png) +- Brick: ![#c7490a](https://placehold.co/15x15/c7490a/c7490a.png) +- Desert: ![#fceac4](https://placehold.co/15x15/fceac4/fceac4.png) +- Gold: ![#ffcf00](https://placehold.co/15x15/ffcf00/ffcf00.png) +- Ocean: ![#3daace](https://placehold.co/15x15/3daace/3daace.png) + ## Documentation Full documentation can be found in the [documentation](documentation) folder. @@ -23,8 +46,53 @@ Full documentation can be found in the [documentation](documentation) folder. - [ESLint](https://eslint.org/) `8.56.*` - [Prettier](https://prettier.io/) `3.2.*` - [pre-commit](https://pre-commit.com/) `3.5.*` -- [vitest](https://vitest.dev/) `1.2.*` +- [Vitest](https://vitest.dev/) `1.2.*` - [Cypress](https://www.cypress.io/) `13.6.*` - [start-server-and-test](https://github.com/bahmutov/start-server-and-test) `2.0.3` - [testing-library/react](https://testing-library.com/docs/react-testing-library/intro) `14.2.*` - [testing-library/user-event](https://testing-library.com/docs/user-event/intro) `14.5.*` + +### Setup Guide + +#### Development + +Make sure you have [Node JS](https://nodejs.org/en), and [pre-commit](https://pre-commit.com/) installed on your system. + +To setup for development the only commands that need to be run are: + +```bash +npm install # Or Yarn etc, installs all required node dependencies. +pre-commit install # Installs hooks for ESLint and Prettier +``` + +For development, the following commands have been setup in `package.json`: + +```bash +npm run dev # Runs the development server +npm run build # Creates the Production build +npm run start # Runs the Production server (requires a build) +npm run test # Runs Vitest Unit and Component tests +npm run cypress:open # Runs the Cypress E2E suite in the GUI +npm run cypress:ci # Runs the Cypress E2E suite in headless mode. +``` + +#### Production + +For a Production setup, both a Dockerfile and Kubernetes (K8s) configuration have been included in the repo, and are +both ready for use with various cloud providers. + +The image used by K8s can be found on Docker Hub [here](https://hub.docker.com/repository/docker/stuartbradley/catan-randomiser-js). + +To test these locally the following commands can be used: + +```bash +# Docker - Requires Docker Engine +docker build -t catan-randomiser-js . +docker run -p 3000:3000 catan-randomiser-js +# K8s - Requires Minicube or similar +kubectl apply -f kubernetes/deployment.yaml +kubectl apply -f kubernetes/service.yaml +# Either following command: +minikube service catan-randomiser-js +kubectl expose deployment catan-randomiser-js --type=LoadBalancer --port=3000 +``` diff --git a/documentation/functional_requirements_specification.md b/documentation/functional_requirements_specification.md index 92fc53d..b001cbf 100644 --- a/documentation/functional_requirements_specification.md +++ b/documentation/functional_requirements_specification.md @@ -185,9 +185,22 @@ a single user path in the application: ### 6 Containerisation +The final step of application development should be to containerise the application so it can be deployed to +different machines and cloud providers without significant alternation. + #### 6.1 Docker -#### 6.2 Kubernetes +Next.js helpfully provides an [example Dockerfile](https://nextjs.org/docs/app/building-your-application/deploying#docker-image) +for building and deploying the application. + +The image on Docker Hub can be found [here](https://hub.docker.com/repository/docker/stuartbradley/catan-randomiser-js). + +#### 6.2 Kubernetes (K8s) + +While Next.js does not provide specific instructions for K8s, a basic setup only requires two configuration files: + +- A Deployment to create the Pods and Containers. +- A Service to create the load balancer. ## Appendix diff --git a/documentation/images/catan-randomiser-js-examples.png b/documentation/images/catan-randomiser-js-examples.png new file mode 100644 index 0000000..3a454f6 Binary files /dev/null and b/documentation/images/catan-randomiser-js-examples.png differ diff --git a/documentation/product_requirements_document.md b/documentation/product_requirements_document.md index 414a034..46e3303 100644 --- a/documentation/product_requirements_document.md +++ b/documentation/product_requirements_document.md @@ -1,7 +1,7 @@ # Product Requirements Document (PRD) This document outlines the high level requirements that this project needs to be considered feature complete for -Version 1. +MVP. ## Description diff --git a/kubernetes/deployment.yaml b/kubernetes/deployment.yaml new file mode 100644 index 0000000..327f2a6 --- /dev/null +++ b/kubernetes/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: catan-randomiser-js +spec: + replicas: 3 + selector: + matchLabels: + app: catan-randomiser-js + template: + metadata: + labels: + app: catan-randomiser-js + spec: + containers: + - name: catan-randomiser-js + image: stuartbradley/catan-randomiser-js:latest + ports: + - containerPort: 3000 diff --git a/kubernetes/service.yaml b/kubernetes/service.yaml new file mode 100644 index 0000000..167e1c5 --- /dev/null +++ b/kubernetes/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: catan-randomiser-js +spec: + selector: + app: catan-randomiser-js + ports: + - name: http + port: 80 + targetPort: 3000 + type: LoadBalancer diff --git a/next.config.mjs b/next.config.mjs index 4678774..8c8bab6 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + output: "standalone", +}; export default nextConfig; diff --git a/src/app/favicon.ico b/public/favicon.ico similarity index 100% rename from src/app/favicon.ico rename to public/favicon.ico