diff --git a/.github/workflows/cd-deploy-docs.yaml b/.github/workflows/cd-deploy-docs.yaml new file mode 100644 index 000000000..8fa491b37 --- /dev/null +++ b/.github/workflows/cd-deploy-docs.yaml @@ -0,0 +1,91 @@ +name: Deploy Docs (Production) + +concurrency: documentation + +on: + push: + branches: [master, gql] + +jobs: + detect-changes: + name: Detect Documentation Changes + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.changed.outputs.any_changed }} + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Detect Changed Files + uses: tj-actions/changed-files@v45 + id: changed + with: + files: | + docs/** + + build-push: + name: Build and Push Docs Image + needs: [detect-changes] + runs-on: ubuntu-latest + if: needs.detect-changes.outputs.changed == 'true' + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: docs + target: docs-prod + tags: ${{ secrets.DOCKER_USERNAME }}/bt-docs:prod + cache-from: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/bt-docs:prod-cache + cache-to: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/bt-docs:prod-cache,mode=max + platforms: linux/amd64 + push: true + + deploy: + name: SSH and Deploy + needs: [build-push] + runs-on: ubuntu-latest + environment: documentation + + steps: + - name: SSH and Helm Install + uses: appleboy/ssh-action@v1.2.0 + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_KEY }} + script: | + set -e # Exit immediately if a command fails + + # Check if helm chart exists + helm status bt-prod-docs &>/dev/null && status=true || status=false + + # Upgrade helm chart, or install if not exists + helm upgrade bt-prod-docs oci://registry-1.docker.io/octoberkeleytime/bt-docs \ + --install \ + --version=1.0.0 \ + --namespace=bt \ + --set host=docs.stanfurdtime.com + + # Restart deployment if helm chart existed + if [ $status = true ]; then + kubectl rollout restart deployment bt-prod-docs-docs + fi + + # Check container status + kubectl rollout status --timeout=180s deployment bt-prod-docs-docs diff --git a/apps/frontend/src/app/Catalog/index.tsx b/apps/frontend/src/app/Catalog/index.tsx index 50073bcd4..41a6b8f75 100644 --- a/apps/frontend/src/app/Catalog/index.tsx +++ b/apps/frontend/src/app/Catalog/index.tsx @@ -2,6 +2,7 @@ import { useCallback, useMemo, useState } from "react"; import classNames from "classnames"; import { Xmark } from "iconoir-react"; +import moment from "moment"; import { useLocation, useNavigate, useParams } from "react-router-dom"; import { IconButton } from "@repo/theme"; @@ -47,14 +48,21 @@ export default function Catalog() { const term = useMemo(() => { if (!terms) return null; - const currentTerm = terms?.find( + // Default to the current term + const currentTerm = terms.find( (term) => term.temporalPosition === TemporalPosition.Current ); - // Default to the current term + // Fall back to the next term when the current term has ended + const nextTerm = terms + .filter((term) => term.startDate) + .toSorted((a, b) => moment(a.startDate).diff(moment(b.startDate))) + .find((term) => term.temporalPosition === TemporalPosition.Future); + return ( terms?.find((term) => term.year === year && term.semester === semester) ?? - currentTerm + currentTerm ?? + nextTerm ); }, [terms, year, semester]); diff --git a/docs/.dockerignore b/docs/.dockerignore new file mode 100644 index 000000000..9d9eef6e7 --- /dev/null +++ b/docs/.dockerignore @@ -0,0 +1 @@ +*.excalidraw diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..7585238ef --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 000000000..bbcad23ff --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,26 @@ +# dev +FROM rust:1.83 AS docs-dev +WORKDIR /docs + +RUN ["cargo", "install", "mdbook", "--vers", "^0.4", "--locked"] +RUN ["cargo", "install", "mdbook-alerts"] + +COPY . . +VOLUME ["/docs"] +EXPOSE 3000 +ENTRYPOINT ["mdbook", "serve", "--hostname=0.0.0.0", "--port=3000"] + +# prod +FROM rust:1.83 AS docs-builder +WORKDIR /docs + +RUN ["cargo", "install", "mdbook", "--no-default-features", "--features", "search", "--vers", "^0.4", "--locked"] +RUN ["cargo", "install", "mdbook-alerts"] + +COPY . . +RUN ["mdbook", "build"] + +FROM nginx:alpine AS docs-prod +COPY ./nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=docs-builder /docs/book /var/www/html +EXPOSE 80 diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 000000000..a29a001d8 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,13 @@ +[book] +title = "Berkeleytime Documentation" +authors = ["Berkeleytime Developers"] +description = "The Berkeleytime documentation for developers" +language = "en" +multilingual = false +src = "src" + +[output.html] +git-repository-url = "https://github.com/asuc-octo/berkeleytime/tree/gql/docs" +edit-url-template = "https://github.com/asuc-octo/berkeleytime/tree/gql/docs/{path}" + +[preprocessor.alerts] diff --git a/docs/nginx.conf b/docs/nginx.conf new file mode 100644 index 000000000..128b4190d --- /dev/null +++ b/docs/nginx.conf @@ -0,0 +1,12 @@ +server { + root /var/www/html; + + listen 80; + server_name localhost; + + location / { + add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"; + expires off; + sendfile off; + } +} diff --git a/docs/src/README.md b/docs/src/README.md new file mode 100644 index 000000000..2b83f4af9 --- /dev/null +++ b/docs/src/README.md @@ -0,0 +1,72 @@ +# Introduction + +> [!WARNING] +> The Berkeleytime Documentation is currently under construction. + +Welcome to the Berkeleytime Docs! This is the primary documentation source for developers. + +## Getting Started + +### Developing and Building Locally + +There are two options: with and without containerization (ie. Docker). + +#### With Containerization (Recommended) + +Using Docker allows us to build the docs without downloading dependencies on our host machine, greatly simplifying the build process. + +```sh +# ./berkeleytime +# Ensure you are on the latest commit +git pull + +# Build the container +docker build --target docs-dev --tag="docs:dev" ./docs + +# Run the container +docker run --publish 3000:3000 --volume ./docs:/docs "docs:dev" +``` + +The docs should be available at `http://localhost:3000/`. To change the port to port `XXXX`, modify the last command: +```sh +# Run the container and publish the docs to http://localhost:XXXX/ +docker run --publish XXXX:3000 --volume ./docs:/docs "docs:dev" +``` + +#### Without Containerization + +To build and view the docs locally, `mdBook` must be installed by following the guide [here](https://rust-lang.github.io/mdBook/guide/installation.html#build-from-source-using-rust). It is necessary to install Rust locally as there is a dependency that is installed with `cargo`. Thus, it is highly recommended to [build mdbook from Rust](https://rust-lang.github.io/mdBook/guide/installation.html#build-from-source-using-rust). + +```sh +# Install mdbook-alerts dependency with cargo +cargo install mdbook-alerts + +# ./berkeleytime +# Ensure you are on the latest commit +git pull + +# Navigate into the docs directory +cd docs + +# Build the book and serve at http://localhost:3000/ +mdbook serve --port=3000 --open +``` + +Changes in the markdown files will be shown live. + +### Creating Books with Markdown and mdBook + +As these docs are primarily written with markdown, feel free to check [this quick guide](https://www.markdownguide.org/basic-syntax/) on markdown's syntax. + +To add new pages to the docs, check out the [`mdBook` guide](https://rust-lang.github.io/mdBook/guide/creating.html). Below is a step-by-step guide on creating a new page: + +1. Create a new `.md` file in the `src` directory. For example, if you want your new page to be in the Infrastructure section, you should put the new file in `src/infrastructure`. + +2. Add this file to `SUMMARY.md`. The indentation indicates which section your file will go under. For example: + + ```md + - [Infrastructure](./infrastructure/README.md) + - [My New File's Title](./infrastructure/my-new-file.md) + ``` + +3. Add content to your file and see the results! diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 000000000..cd2dcc6b2 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,38 @@ +# Summary + +[Introduction](README.md) + +--- + +# Getting Started + +- [Local Development](./getting-started/local-development.md) +- [Deployment with CI/CD](./getting-started/deployment-with-cicd.md) + +--- + +# Core Documentation + +- [Backend](./core/backend/README.md) + +- [Datapuller](./core/datapuller/README.md) + +- [Frontend](./core/frontend/README.md) + +- [Infrastructure](./core/infrastructure/README.md) + - [Onboarding](./core/infrastructure/onboarding.md) + - [Architecture](./core/infrastructure/architecture.md) + - [Kubernetes & Helm](./core/infrastructure/kubernetes-helm.md) + - [CI/CD](./core/infrastructure/cicd.md) + +--- + +# Fall 2024 Pods + +- [Crowd Sourced Data](./fa24/crowd-sourced-data/README.md) + +- [Decals](./fa24/decals/README.md) + +- [GradTrak](./fa24/gradtrak/README.md) + +- [Semantic Search](./fa24/semantic-search/README.md) diff --git a/docs/src/core/backend/README.md b/docs/src/core/backend/README.md new file mode 100644 index 000000000..b6a4bdb78 --- /dev/null +++ b/docs/src/core/backend/README.md @@ -0,0 +1,3 @@ +# Backend + +TODO diff --git a/docs/src/core/datapuller/README.md b/docs/src/core/datapuller/README.md new file mode 100644 index 000000000..330b403b0 --- /dev/null +++ b/docs/src/core/datapuller/README.md @@ -0,0 +1,3 @@ +# Datapuller + +TODO diff --git a/docs/src/core/frontend/README.md b/docs/src/core/frontend/README.md new file mode 100644 index 000000000..7e4e1808f --- /dev/null +++ b/docs/src/core/frontend/README.md @@ -0,0 +1,3 @@ +# Frontend + +TODO diff --git a/docs/src/core/infrastructure/README.md b/docs/src/core/infrastructure/README.md new file mode 100644 index 000000000..cde0f3c53 --- /dev/null +++ b/docs/src/core/infrastructure/README.md @@ -0,0 +1,18 @@ +# Infrastructure + +> [!WARNING] +> The infrastructure section is currently under construction. + +Welcome to the infrastructure section. + +> [!NOTE] +> Infrastructure concepts tend to be more complex than application concepts. Don't be discouraged if a large amount of content in the infrastructure section is confusing! + +## What is Infrastructure? + +![application-infrastructure-layers](./assets/app-infra-layer.svg) + +Software infrastructure refers to the services and tools that create an underlying layer of abstractions that the application is developed on. Compared to the application layer, infrastructure is significantly more broad in its responsibilities, although these responsibilities are more common in software development. + +> [!IMPORTANT] +> We aim to use a **small** set of **existing** infrastructure solutions with large communities. This philosophy reduces the [cognitive load](https://thevaluable.dev/cognitive-load-theory-software-developer/) on each developer and simplifies the onboarding process, both of which are valuable for creating long-lasting software in a team where developers are typically cycled out after only ~4 years. diff --git a/docs/src/core/infrastructure/architecture.md b/docs/src/core/infrastructure/architecture.md new file mode 100644 index 000000000..b81b82205 --- /dev/null +++ b/docs/src/core/infrastructure/architecture.md @@ -0,0 +1,35 @@ +# Architecture + +Berkeleytime uses a fairly simple microservices architecture—we decouple only a few application components into separate services. Below is a high-level diagram of the current architecture (switch to a light viewing mode to see arrows). +

+ berkeleytime architecture design +

+ +Note that, other than the application services developed by us, all other services are well-known and have large communities. These services have many tutorials, guides, and issues already created online, streamlining the setup and debugging processes. + +## An HTTP Request's Life + +To better understand the roles of each component in the Berkeleytime architecture, we describe the lifecycle of an HTTP request from a user's action. + +1. An HTTP request starts from a user's browser. For example, when a user visits `https://berkeleytime.com`, a `GET` request is sent to `hozer-51`.[^1] + +2. Once the request reaches `hozer-51`, it is first encountered by `hozer-51`'s Kubernetes cluster load balancer, a [MetalLB](https://metallb.io/) instance, which balances external traffic into the cluster across nodes.[^2] + +3. Next, the request reaches the [reverse proxy](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/), an [nginx](https://nginx.org/) instance, which forwards HTTP requests to either the [backend](../backend) or [frontend](../frontend/) service based on the URL of the request. + - Requests with URLs matching `https://berkeleytime.com/api/*` are forwarded to the backend service. + - All other requests are forwarded to the frontend service. + +4. The request is processed by one of the services. + - The backend service may interact with the MongoDB database or the Redis cache while processing the request.[^3] + +5. Finally, an HTTP response is sent back through the system to the user's machine. + + +[^1]: More specifically, the user's machine first requests a DNS record of `berkeleytime.com` from a DNS server, which should return `hozer-51`'s IP address. After the user's machine knows the `hozer-51` IP address, the `GET` request is sent. + +[^2]: Currently, we only have one node: `hozer-51`. + +[^3]: Requests sent from the backend to the database or cache are *not* necessarily HTTP requests. diff --git a/docs/src/core/infrastructure/assets/app-infra-layer.excalidraw b/docs/src/core/infrastructure/assets/app-infra-layer.excalidraw new file mode 100644 index 000000000..731632342 --- /dev/null +++ b/docs/src/core/infrastructure/assets/app-infra-layer.excalidraw @@ -0,0 +1,158 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "Jg0_8RHupJOUP6u45HkRN", + "type": "rectangle", + "x": 600, + "y": 200, + "width": 400, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 356145891, + "version": 28, + "versionNonce": 567646605, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "r-xwdTAZa6i3wXGEhgIgt" + } + ], + "updated": 1733794802303, + "link": null, + "locked": false + }, + { + "id": "r-xwdTAZa6i3wXGEhgIgt", + "type": "text", + "x": 716.896666876475, + "y": 237.5, + "width": 166.20666624704995, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0V", + "roundness": null, + "seed": 1900222499, + "version": 40, + "versionNonce": 956696013, + "isDeleted": false, + "boundElements": null, + "updated": 1733794788979, + "link": null, + "locked": false, + "text": "Application Layer", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Jg0_8RHupJOUP6u45HkRN", + "originalText": "Application Layer", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "OvvEKT7IGeINYpJRGnqPw", + "type": "rectangle", + "x": 600, + "y": 320, + "width": 400, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e9ecef", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a2", + "roundness": { + "type": 3 + }, + "seed": 365087779, + "version": 29, + "versionNonce": 1316595917, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "EZd3hNM8Ek97kzWFpBC0A" + } + ], + "updated": 1733794798448, + "link": null, + "locked": false + }, + { + "id": "EZd3hNM8Ek97kzWFpBC0A", + "type": "text", + "x": 698.346666876475, + "y": 357.5, + "width": 203.30666624704998, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": null, + "seed": 1752911811, + "version": 58, + "versionNonce": 1542025219, + "isDeleted": false, + "boundElements": [], + "updated": 1733794792928, + "link": null, + "locked": false, + "text": "Infrastructure Layer", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "OvvEKT7IGeINYpJRGnqPw", + "originalText": "Infrastructure Layer", + "autoResize": true, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": true, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/docs/src/core/infrastructure/assets/app-infra-layer.svg b/docs/src/core/infrastructure/assets/app-infra-layer.svg new file mode 100644 index 000000000..5d0f73869 --- /dev/null +++ b/docs/src/core/infrastructure/assets/app-infra-layer.svg @@ -0,0 +1,10 @@ + + + + + + + + Application LayerInfrastructure Layer \ No newline at end of file diff --git a/docs/src/core/infrastructure/assets/architecture-diagram.excalidraw b/docs/src/core/infrastructure/assets/architecture-diagram.excalidraw new file mode 100644 index 000000000..1a2753b71 --- /dev/null +++ b/docs/src/core/infrastructure/assets/architecture-diagram.excalidraw @@ -0,0 +1,1400 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "lDFI7nTZOLeKX515NFRfi", + "type": "rectangle", + "x": -140, + "y": 100, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#2f9e44", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a5", + "roundness": { + "type": 3 + }, + "seed": 747572291, + "version": 107, + "versionNonce": 1604658979, + "isDeleted": false, + "boundElements": [ + { + "id": "G0Nb8qKIBE650QEH9ZUpO", + "type": "text" + }, + { + "id": "ExBfVjfb8dXSiaZHfTNCI", + "type": "arrow" + }, + { + "id": "8sW6MfACv2GjqtM7GoGkm", + "type": "arrow" + } + ], + "updated": 1733796688358, + "link": null, + "locked": false + }, + { + "id": "G0Nb8qKIBE650QEH9ZUpO", + "type": "text", + "x": -130.2233332236608, + "y": 187.5, + "width": 180.44666644732158, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a5V", + "roundness": null, + "seed": 281868269, + "version": 123, + "versionNonce": 2051394435, + "isDeleted": false, + "boundElements": [], + "updated": 1733796543347, + "link": null, + "locked": false, + "text": "Database - Mongo", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lDFI7nTZOLeKX515NFRfi", + "originalText": "Database - Mongo", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "l2MR6d1Re3LchlfRH_2Dp", + "type": "rectangle", + "x": 100, + "y": 100, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e03131", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a8", + "roundness": { + "type": 3 + }, + "seed": 96827949, + "version": 85, + "versionNonce": 2088003587, + "isDeleted": false, + "boundElements": [ + { + "id": "slgNKrEJR96CSYg1_YIvN", + "type": "text" + }, + { + "id": "miSG6GeMNB2i8D_HJSi-U", + "type": "arrow" + } + ], + "updated": 1733796681577, + "link": null, + "locked": false + }, + { + "id": "slgNKrEJR96CSYg1_YIvN", + "type": "text", + "x": 132.50000019073485, + "y": 187.5, + "width": 134.99999961853027, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e03131", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 349978285, + "version": 82, + "versionNonce": 1056644717, + "isDeleted": false, + "boundElements": [], + "updated": 1733796401683, + "link": null, + "locked": false, + "text": "Cache - Redis", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "l2MR6d1Re3LchlfRH_2Dp", + "originalText": "Cache - Redis", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "7PkUiSaDs-tG-sZI-WJ8m", + "type": "rectangle", + "x": -400, + "y": 400, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a18072", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aA", + "roundness": { + "type": 3 + }, + "seed": 1132324739, + "version": 56, + "versionNonce": 1858062243, + "isDeleted": false, + "boundElements": [], + "updated": 1733796550498, + "link": null, + "locked": false + }, + { + "id": "FflGaP-VVCm546Jmu0wHH", + "type": "rectangle", + "x": -380, + "y": 420, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a18072", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": { + "type": 3 + }, + "seed": 1734001997, + "version": 65, + "versionNonce": 1182827491, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "8Tp3Vhxp-ceX2uyJI2Pvp" + }, + { + "id": "8sW6MfACv2GjqtM7GoGkm", + "type": "arrow" + } + ], + "updated": 1733796688358, + "link": null, + "locked": false + }, + { + "id": "8Tp3Vhxp-ceX2uyJI2Pvp", + "type": "text", + "x": -373.0799997886022, + "y": 507.5, + "width": 186.1599995772044, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aD", + "roundness": null, + "seed": 1607373741, + "version": 99, + "versionNonce": 1345747683, + "isDeleted": false, + "boundElements": [], + "updated": 1733796550498, + "link": null, + "locked": false, + "text": "Datapuller CronJob", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "FflGaP-VVCm546Jmu0wHH", + "originalText": "Datapuller CronJob", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "BjisPboVmk1G1DiRMrYy9", + "type": "rectangle", + "x": -140, + "y": 400, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#228be6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aE", + "roundness": { + "type": 3 + }, + "seed": 1356722627, + "version": 21, + "versionNonce": 1778220621, + "isDeleted": false, + "boundElements": [], + "updated": 1733796547563, + "link": null, + "locked": false + }, + { + "id": "ji5g6U-kRU4J1CCi-m9CL", + "type": "rectangle", + "x": -120, + "y": 420, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#228be6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": { + "type": 3 + }, + "seed": 1893841059, + "version": 29, + "versionNonce": 2081455299, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "aJo4Zlo5Yi_mmnMmuxi5B" + }, + { + "id": "4Z_e5tvIPMufzEExgc1MF", + "type": "arrow" + }, + { + "id": "ExBfVjfb8dXSiaZHfTNCI", + "type": "arrow" + }, + { + "id": "miSG6GeMNB2i8D_HJSi-U", + "type": "arrow" + } + ], + "updated": 1733796681577, + "link": null, + "locked": false + }, + { + "id": "aJo4Zlo5Yi_mmnMmuxi5B", + "type": "text", + "x": -98.88999977906545, + "y": 507.5, + "width": 157.7799995581309, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a18072", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aH", + "roundness": null, + "seed": 1242082371, + "version": 28, + "versionNonce": 1266814733, + "isDeleted": false, + "boundElements": [], + "updated": 1733796547563, + "link": null, + "locked": false, + "text": "Backend Service", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ji5g6U-kRU4J1CCi-m9CL", + "originalText": "Backend Service", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "EHnlJISzmOV88wGyfzJZN", + "type": "rectangle", + "x": 100, + "y": 400, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fab005", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": { + "type": 3 + }, + "seed": 519846957, + "version": 42, + "versionNonce": 1763564077, + "isDeleted": false, + "boundElements": [], + "updated": 1733796333708, + "link": null, + "locked": false + }, + { + "id": "Xj8fPIMBuOk8UlX9Jpn48", + "type": "rectangle", + "x": 120, + "y": 420, + "width": 200, + "height": 200, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fab005", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aJ", + "roundness": { + "type": 3 + }, + "seed": 1440624269, + "version": 48, + "versionNonce": 1831254989, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "miRkf2Wgv6S8M-qY9a6xz" + }, + { + "id": "guaI2dafY7E6pZH483q5c", + "type": "arrow" + } + ], + "updated": 1733796673631, + "link": null, + "locked": false + }, + { + "id": "miRkf2Wgv6S8M-qY9a6xz", + "type": "text", + "x": 137.6266668955485, + "y": 507.5, + "width": 164.74666620890298, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a18072", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": null, + "seed": 345167085, + "version": 58, + "versionNonce": 2123984131, + "isDeleted": false, + "boundElements": [], + "updated": 1733796330300, + "link": null, + "locked": false, + "text": "Frontend Service", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Xj8fPIMBuOk8UlX9Jpn48", + "originalText": "Frontend Service", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "IzCicC88v3PZrlRcgQmRt", + "type": "rectangle", + "x": -140, + "y": 700, + "width": 440, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#868e96", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aO", + "roundness": { + "type": 3 + }, + "seed": 1867312675, + "version": 25, + "versionNonce": 1327651597, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "qERKczbEkOfQdZhZ_Ormr" + }, + { + "id": "sGMoNHAfCHlZOShu1uXOm", + "type": "arrow" + }, + { + "id": "4Z_e5tvIPMufzEExgc1MF", + "type": "arrow" + }, + { + "id": "guaI2dafY7E6pZH483q5c", + "type": "arrow" + } + ], + "updated": 1733796673631, + "link": null, + "locked": false + }, + { + "id": "qERKczbEkOfQdZhZ_Ormr", + "type": "text", + "x": -28.326666323343915, + "y": 737.5, + "width": 216.65333264668783, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fab005", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aP", + "roundness": null, + "seed": 1670421837, + "version": 29, + "versionNonce": 459144141, + "isDeleted": false, + "boundElements": [], + "updated": 1733796557696, + "link": null, + "locked": false, + "text": "Reverse Proxy - Nginx", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "IzCicC88v3PZrlRcgQmRt", + "originalText": "Reverse Proxy - Nginx", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "DfpvDWunIXGIv19vbFqN_", + "type": "rectangle", + "x": -140, + "y": 860, + "width": 440, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#868e96", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aQ", + "roundness": { + "type": 3 + }, + "seed": 223621229, + "version": 47, + "versionNonce": 1338439757, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "2VWKAhSNtX8JQpJgsNhEP" + }, + { + "id": "s6qPs7NRZca8-o_5nntsW", + "type": "arrow" + }, + { + "id": "P7KsXGs9NB4Zkrr1yMCvx", + "type": "arrow" + }, + { + "id": "rbtz2ZGKXuuLj2_w_reb8", + "type": "arrow" + }, + { + "id": "sGMoNHAfCHlZOShu1uXOm", + "type": "arrow" + } + ], + "updated": 1733796662068, + "link": null, + "locked": false + }, + { + "id": "2VWKAhSNtX8JQpJgsNhEP", + "type": "text", + "x": -40.72666646639506, + "y": 897.5, + "width": 241.45333293279012, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fab005", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aR", + "roundness": null, + "seed": 1437440717, + "version": 75, + "versionNonce": 349392973, + "isDeleted": false, + "boundElements": [], + "updated": 1733796560098, + "link": null, + "locked": false, + "text": "Load Balancer - MetalLB", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "DfpvDWunIXGIv19vbFqN_", + "originalText": "Load Balancer - MetalLB", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "pDWqIzbmoAtKmV5c2n5L3", + "type": "rectangle", + "x": -140, + "y": 1068.7161091182113, + "width": 100, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aY", + "roundness": { + "type": 3 + }, + "seed": 176139651, + "version": 52, + "versionNonce": 463534957, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "HtRKjDtgcAAqcw4uHkZnb" + }, + { + "id": "s6qPs7NRZca8-o_5nntsW", + "type": "arrow" + } + ], + "updated": 1733796698048, + "link": null, + "locked": false + }, + { + "id": "HtRKjDtgcAAqcw4uHkZnb", + "type": "text", + "x": -112.65999981562297, + "y": 1106.2161091182113, + "width": 45.31999963124593, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#868e96", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aZ", + "roundness": null, + "seed": 1775568163, + "version": 46, + "versionNonce": 908658125, + "isDeleted": false, + "boundElements": [], + "updated": 1733796698048, + "link": null, + "locked": false, + "text": "User", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "pDWqIzbmoAtKmV5c2n5L3", + "originalText": "User", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "fdsRfLcj3nfR6GoxTmtdh", + "type": "rectangle", + "x": 28.694195123030795, + "y": 1069.5064904930323, + "width": 100, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aa", + "roundness": { + "type": 3 + }, + "seed": 1511661997, + "version": 77, + "versionNonce": 1628550797, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "UOs3RcVf5rpB6prX49Vn9" + }, + { + "id": "P7KsXGs9NB4Zkrr1yMCvx", + "type": "arrow" + } + ], + "updated": 1733796698048, + "link": null, + "locked": false + }, + { + "id": "UOs3RcVf5rpB6prX49Vn9", + "type": "text", + "x": 56.03419530740783, + "y": 1107.0064904930323, + "width": 45.31999963124593, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#868e96", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ab", + "roundness": null, + "seed": 253977613, + "version": 71, + "versionNonce": 1400045, + "isDeleted": false, + "boundElements": [], + "updated": 1733796698048, + "link": null, + "locked": false, + "text": "User", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fdsRfLcj3nfR6GoxTmtdh", + "originalText": "User", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "xA-W9E59FyCTGDR_HC4Xb", + "type": "rectangle", + "x": 200, + "y": 1068.7161091182113, + "width": 100, + "height": 100, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ac", + "roundness": { + "type": 3 + }, + "seed": 1098084899, + "version": 53, + "versionNonce": 753583533, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "D-_mRk57we7ClJbaYVClR" + }, + { + "id": "rbtz2ZGKXuuLj2_w_reb8", + "type": "arrow" + } + ], + "updated": 1733796698048, + "link": null, + "locked": false + }, + { + "id": "D-_mRk57we7ClJbaYVClR", + "type": "text", + "x": 227.34000018437703, + "y": 1106.2161091182113, + "width": 45.31999963124593, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#868e96", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ad", + "roundness": null, + "seed": 1663514051, + "version": 47, + "versionNonce": 138381325, + "isDeleted": false, + "boundElements": [], + "updated": 1733796698048, + "link": null, + "locked": false, + "text": "User", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "xA-W9E59FyCTGDR_HC4Xb", + "originalText": "User", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "s6qPs7NRZca8-o_5nntsW", + "type": "arrow", + "x": 80, + "y": 960, + "width": 151.27327045867258, + "height": 107.7161091182113, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aj", + "roundness": { + "type": 2 + }, + "seed": 544242179, + "version": 52, + "versionNonce": 1030217709, + "isDeleted": false, + "boundElements": [], + "updated": 1733796698080, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -151.27327045867258, + 107.7161091182113 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "DfpvDWunIXGIv19vbFqN_", + "focus": -0.20618556701030927, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "pDWqIzbmoAtKmV5c2n5L3", + "focus": -0.44, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "P7KsXGs9NB4Zkrr1yMCvx", + "type": "arrow", + "x": 80, + "y": 960, + "width": 0.898651032703583, + "height": 108.50649049303229, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ak", + "roundness": { + "type": 2 + }, + "seed": 1706141891, + "version": 140, + "versionNonce": 916413005, + "isDeleted": false, + "boundElements": [], + "updated": 1733796698080, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.898651032703583, + 108.50649049303229 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "DfpvDWunIXGIv19vbFqN_", + "focus": 0.0015669051852653913, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "fdsRfLcj3nfR6GoxTmtdh", + "focus": 0.05210522520206297, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "rbtz2ZGKXuuLj2_w_reb8", + "type": "arrow", + "x": 80, + "y": 960, + "width": 151.27327045867258, + "height": 107.7161091182113, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "al", + "roundness": { + "type": 2 + }, + "seed": 1956480781, + "version": 55, + "versionNonce": 1673037997, + "isDeleted": false, + "boundElements": [], + "updated": 1733796698080, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 151.27327045867258, + 107.7161091182113 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "DfpvDWunIXGIv19vbFqN_", + "focus": 0.20618556701030927, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "xA-W9E59FyCTGDR_HC4Xb", + "focus": 0.44, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "sGMoNHAfCHlZOShu1uXOm", + "type": "arrow", + "x": 79.16053945139504, + "y": 859.6381129295164, + "width": 1.5807627496419627, + "height": 60.068984486394356, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "am", + "roundness": { + "type": 2 + }, + "seed": 549542253, + "version": 25, + "versionNonce": 1916561069, + "isDeleted": false, + "boundElements": [], + "updated": 1733796662068, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 1.5807627496419627, + -60.068984486394356 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "DfpvDWunIXGIv19vbFqN_", + "focus": -0.009781377873659012, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "IzCicC88v3PZrlRcgQmRt", + "focus": -0.009243592399825003, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "4Z_e5tvIPMufzEExgc1MF", + "type": "arrow", + "x": 75.2086325772899, + "y": 697.6099310912156, + "width": 83.78042573102368, + "height": 76.66699335763485, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "an", + "roundness": { + "type": 2 + }, + "seed": 287735075, + "version": 25, + "versionNonce": 601732067, + "isDeleted": false, + "boundElements": [], + "updated": 1733796670598, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -83.78042573102368, + -76.66699335763485 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "IzCicC88v3PZrlRcgQmRt", + "focus": 0.19101293785016035, + "gap": 2.3900689087844285, + "fixedPoint": null + }, + "endBinding": { + "elementId": "ji5g6U-kRU4J1CCi-m9CL", + "focus": 0.47248351407249933, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "guaI2dafY7E6pZH483q5c", + "type": "arrow", + "x": 75.99901395211089, + "y": 697.6099310912156, + "width": 105.91110422601116, + "height": 75.87661198281387, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ao", + "roundness": { + "type": 2 + }, + "seed": 361069251, + "version": 54, + "versionNonce": 496857453, + "isDeleted": false, + "boundElements": [], + "updated": 1733796673631, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 105.91110422601116, + -75.87661198281387 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "IzCicC88v3PZrlRcgQmRt", + "focus": -0.2661525483240286, + "gap": 2.3900689087844285, + "fixedPoint": null + }, + "endBinding": { + "elementId": "Xj8fPIMBuOk8UlX9Jpn48", + "focus": -0.43372330894024147, + "gap": 1.7333191084017017, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "ExBfVjfb8dXSiaZHfTNCI", + "type": "arrow", + "x": -39.39666677175194, + "y": 396.4746272844227, + "width": 1.5807627496419627, + "height": 97.21690910298037, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ap", + "roundness": { + "type": 2 + }, + "seed": 1873981123, + "version": 36, + "versionNonce": 1094222861, + "isDeleted": false, + "boundElements": [], + "updated": 1733796678538, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -1.5807627496419627, + -97.21690910298037 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "ji5g6U-kRU4J1CCi-m9CL", + "focus": -0.1710991413995466, + "gap": 23.525372715577305, + "fixedPoint": null + }, + "endBinding": { + "elementId": "lDFI7nTZOLeKX515NFRfi", + "focus": 0.025499141399546812, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "miSG6GeMNB2i8D_HJSi-U", + "type": "arrow", + "x": -40.18704814657292, + "y": 398.05539003406466, + "width": 192.0626740814978, + "height": 98.00729047780135, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aq", + "roundness": { + "type": 2 + }, + "seed": 862736931, + "version": 49, + "versionNonce": 1728703587, + "isDeleted": false, + "boundElements": [], + "updated": 1733796681577, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 192.0626740814978, + -98.00729047780135 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "ji5g6U-kRU4J1CCi-m9CL", + "focus": -0.8756330842478834, + "gap": 21.944609965935342, + "fixedPoint": null + }, + "endBinding": { + "elementId": "l2MR6d1Re3LchlfRH_2Dp", + "focus": -0.4998437549891734, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "8sW6MfACv2GjqtM7GoGkm", + "type": "arrow", + "x": -304.17442733678035, + "y": 399.6361527837066, + "width": 261.6162350657439, + "height": 98.79767185262233, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ar", + "roundness": { + "type": 2 + }, + "seed": 356175491, + "version": 79, + "versionNonce": 841135619, + "isDeleted": false, + "boundElements": [], + "updated": 1733796690403, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 261.6162350657439, + -98.79767185262233 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "FflGaP-VVCm546Jmu0wHH", + "focus": -0.9399613343353213, + "gap": 20.36384721629338, + "fixedPoint": null + }, + "endBinding": { + "elementId": "lDFI7nTZOLeKX515NFRfi", + "focus": -0.7249509463664329, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/docs/src/core/infrastructure/assets/architecture-diagram.svg b/docs/src/core/infrastructure/assets/architecture-diagram.svg new file mode 100644 index 000000000..c85b60dc5 --- /dev/null +++ b/docs/src/core/infrastructure/assets/architecture-diagram.svg @@ -0,0 +1,10 @@ + + + + + + + + Database - MongoCache - RedisDatapuller CronJobBackend ServiceFrontend ServiceReverse Proxy - NginxLoad Balancer - MetalLBUserUserUser \ No newline at end of file diff --git a/docs/src/core/infrastructure/assets/cicd-dev-1.png b/docs/src/core/infrastructure/assets/cicd-dev-1.png new file mode 100644 index 000000000..78bf1bc61 Binary files /dev/null and b/docs/src/core/infrastructure/assets/cicd-dev-1.png differ diff --git a/docs/src/core/infrastructure/assets/cicd-dev-2.png b/docs/src/core/infrastructure/assets/cicd-dev-2.png new file mode 100644 index 000000000..8f9c277de Binary files /dev/null and b/docs/src/core/infrastructure/assets/cicd-dev-2.png differ diff --git a/docs/src/core/infrastructure/assets/cicd-dev-3.png b/docs/src/core/infrastructure/assets/cicd-dev-3.png new file mode 100644 index 000000000..1758929b5 Binary files /dev/null and b/docs/src/core/infrastructure/assets/cicd-dev-3.png differ diff --git a/docs/src/core/infrastructure/assets/cicd-dev-4.png b/docs/src/core/infrastructure/assets/cicd-dev-4.png new file mode 100644 index 000000000..892b90936 Binary files /dev/null and b/docs/src/core/infrastructure/assets/cicd-dev-4.png differ diff --git a/docs/src/core/infrastructure/assets/cicd-dev-5.png b/docs/src/core/infrastructure/assets/cicd-dev-5.png new file mode 100644 index 000000000..132c3036c Binary files /dev/null and b/docs/src/core/infrastructure/assets/cicd-dev-5.png differ diff --git a/docs/src/core/infrastructure/cicd.md b/docs/src/core/infrastructure/cicd.md new file mode 100644 index 000000000..e18f68faf --- /dev/null +++ b/docs/src/core/infrastructure/cicd.md @@ -0,0 +1,26 @@ +# CI/CD Workflow + +We use GitHub actions to build our CI/CD workflows.[^1] All three CI/CD workflows[^2] are fairly similar to each other and can all be broken into two phases: the build and the deploy phase. + +1. **Build Phase**: An application container and Helm chart are *built* and *pushed* to a registry. We use [Docker Hub](https://hub.docker.com/). This process is what `.github/workflows/cd-build.yaml` is responsible for. + +2. **Deploy Phase**: After the container and Helm chart are built and pushed to a registry, they are *pulled* and *deployed* onto `hozer-51`. This process is what `.github/workflows/cd-deploy.yaml` is responsible for. + +## Comparing Development, Staging, and Production Environments + +The differences between the three environments are managed by each individual workflow file: `cd-dev.yaml`, `cd-stage.yaml`, and `cd-prod.yaml`. + +| | Development | Staging | Production | +| --- | --- | --- | --- | +| k8s Pod Prefix | `bt-dev-*` | `bt-stage-*` | `bt-prod-*` | +| Container Tags | `[commit hash]` | `latest` | `prod` | +| Helm Chart Versions[^3] | `0.1.0-dev.[commit hash]` | `0.1.0-stage` | `1.0.0` | +| TTL (Time to Live) | `[GitHub Action input]` | N/A | N/A | +| Deployment Count Limit | 8 | 1 | 1 | + +[^1]: In the past, we have used a self-hosted GitLab instance. However, the CI/CD pipeline was obscured behind a admin login page. Hopefully, with GitHub actions, the deployment process will be more transparent and accessible to all engineers. Please don't break anything though! + +[^2]: Development, Staging, and Production + +[^3]: Ideally, these would follow [semantic versioning](https://semver.org/), but this is rather difficult to enforce and automate. + diff --git a/docs/src/core/infrastructure/kubernetes-helm.md b/docs/src/core/infrastructure/kubernetes-helm.md new file mode 100644 index 000000000..9711cf9a8 --- /dev/null +++ b/docs/src/core/infrastructure/kubernetes-helm.md @@ -0,0 +1,158 @@ +# Kubernetes & Helm + +[Kubernetes](https://kubernetes.io/) is a container orchestrator, a fundamental piece of our microservice architecture. It is a complex system with many different components. Fortunately, the documentation is decently well-written. The [concepts page](https://kubernetes.io/docs/concepts/) is a good place to start. The [glossary](https://kubernetes.io/docs/reference/glossary/?core-object=true&fundamental=true&networking=true) is also a good place to review common jargon. + +[Helm](https://helm.sh/) is a package manager for Kubernetes. It allows us to build Kubernetes resources that are easily configurable and reusable. For simplicity, we try to keep all of our Kubernetes resources defined with helm, as opposed to some being defined with raw resource definitions and some with helm charts. + +## Useful Commands + +> [!TIP] +> On `hozer-51`, `k` is an alias for `kubectl` and `h` is an alias for `helm`. + +> [!IMPORTANT] +> The default namespace has been set as `bt`. + +- `k get pods` + + View all running pods. + +
+ Example Output + + ```bash + root@hozer-51:~ k get pods + NAME READY STATUS RESTARTS AGE + bt-cert-manager-996dd87d8-2xlbs 1/1 Running 0 36d + bt-cert-manager-cainjector-68d9974ddf-b7w84 1/1 Running 0 36d + bt-cert-manager-webhook-599cc5679-v9v4n 1/1 Running 0 36d + bt-dev-mongo-mongodb-56967b78d5-dwsk4 1/1 Running 0 14d + bt-dev-redis-master-0 1/1 Running 0 90d + bt-ingress-nginx-controller-788dfdc68d-zw5cf 1/1 Running 0 36d + bt-metallb-controller-6c6ccbb4bb-xjjm2 1/1 Running 0 36d + bt-metallb-speaker-7lqvj 4/4 Running 13 (91d ago) 264d + bt-prod-app-backend-68f984687f-bbst2 1/1 Running 0 36d + bt-prod-app-backend-68f984687f-mdbsj 1/1 Running 0 36d + bt-prod-app-frontend-6985468b46-c89fq 1/1 Running 0 36d + bt-prod-app-frontend-6985468b46-djxs6 1/1 Running 0 36d + bt-prod-app-updater-28856160-dn99p 0/1 Completed 0 2d5h + bt-prod-app-updater-28857600-4z8pw 0/1 Completed 0 29h + bt-prod-app-updater-28859040-jmzkd 0/1 Completed 0 5h33m + bt-prod-mongo-mongodb-b6b66fd69-h764l 1/1 Running 1 (14d ago) 36d + bt-prod-redis-master-0 1/1 Running 0 90d + bt-sealed-secrets-7cb5587d77-576r5 1/1 Running 0 36d + bt-stage-app-backend-77759c7b94-7rg5q 1/1 Running 0 6d7h + bt-stage-app-backend-77759c7b94-kkpbf 1/1 Running 0 6d7h + bt-stage-app-frontend-bc997f75b-9mrhn 1/1 Running 0 6d7h + bt-stage-app-frontend-bc997f75b-gsnkx 1/1 Running 0 6d7h + bt-stage-app-updater-28856160-94lgw 0/1 Completed 0 2d5h + bt-stage-app-updater-28857600-grv9r 0/1 Completed 0 29h + bt-stage-app-updater-28859040-b2mjn 0/1 Completed 0 5h33m + bt-stage-mongo-mongodb-996b5c9d8-ws5bm 1/1 Running 0 13d + bt-stage-redis-master-0 1/1 Running 0 90d + ``` + +
+ + +- `k get pods -l env=[dev|stage|prod]` + + View all running pods in a specified environment. + +- `k logs [pod name]` + + View logs of a pod. You can get a pod's name with `k get pods`. Include a `-f` flag to follow logs, which will stream logs into your terminal. + +- `k describe pod [pod name]` + + View a description of a pod. Useful for when pod is failing to startup, thus not showing any logs. + +- `k exec -it [pod name] -- [command]` + + Execute a command inside a pod. The command can be `bash`, which will start a shell inside the pod and allow for more commands. + +- `k get deploy` + + View all running deployments. + +
+ + Example Output + + ```bash + root@hozer-51:~ k get deploy + NAME READY UP-TO-DATE AVAILABLE AGE + bt-cert-manager 1/1 1 1 90d + bt-cert-manager-cainjector 1/1 1 1 90d + bt-cert-manager-webhook 1/1 1 1 90d + bt-dev-mongo-mongodb 1/1 1 1 14d + bt-ingress-nginx-controller 1/1 1 1 267d + bt-metallb-controller 1/1 1 1 264d + bt-prod-app-backend 2/2 2 2 40d + bt-prod-app-frontend 2/2 2 2 40d + bt-prod-mongo-mongodb 1/1 1 1 90d + bt-sealed-secrets 1/1 1 1 267d + bt-stage-app-backend 2/2 2 2 36d + bt-stage-app-frontend 2/2 2 2 36d + bt-stage-mongo-mongodb 1/1 1 1 14d + ``` + +
+ +- `k get deploy -l env=[dev|stage|prod]` + + View all running deployments in a specified environment. + +- `k describe deploy [deploy name]` + + View a description of a deploy. Useful for when the deploy's pods are failing to startup, thus not showing any logs. + +- `k rollout restart deploy/[deploy name]` + + Manually restart a deployment. + +- `h list` + + List helm chart installations. + +
+ + Example Output + + ```bash + root@hozer-51:~ h list + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + bt-base bt 1 2024-08-16 02:39:08.530680512 +0000 UTC deployed bt-base-0.1.0 2.0.0-alpha + bt-cert-manager bt 1 2024-08-15 09:09:57.055544133 +0000 UTC deployed cert-manager-v1.14.1 v1.14.1 + bt-dev-mongo bt 1 2024-10-30 19:39:12.342638847 +0000 UTC deployed bt-mongo-0.1.0 2.0.0-alpha + bt-dev-redis bt 1 2024-08-15 22:48:23.811538319 +0000 UTC deployed bt-redis-0.1.0 2.0.0-alpha + bt-ingress-nginx bt 2 2024-02-20 06:54:22.749755461 +0000 UTC deployed ingress-nginx-4.9.1 1.9.6 + bt-metallb bt 1 2024-02-23 22:15:39.949979855 +0000 UTC deployed metallb-0.14.3 v0.14.3 + bt-prod-app bt 1 2024-10-05 00:38:19.570732559 +0000 UTC deployed bt-app-0.1.0 2.0.0-alpha + bt-prod-mongo bt 1 2024-08-15 22:49:24.829163584 +0000 UTC deployed bt-mongo-0.1.0 2.0.0-alpha + bt-prod-redis bt 1 2024-08-15 22:49:30.646137811 +0000 UTC deployed bt-redis-0.1.0 2.0.0-alpha + bt-sealed-secrets bt 1 2024-02-20 06:31:59.188302177 +0000 UTC deployed sealed-secrets-2.15.0 0.26.0 + bt-stage-app bt 1 2024-10-09 03:17:21.69782594 +0000 UTC deployed bt-app-0.1.0 2.0.0-alpha + bt-stage-mongo bt 1 2024-10-31 05:20:36.995251245 +0000 UTC deployed bt-mongo-0.1.0 2.0.0-alpha + bt-stage-redis bt 1 2024-08-15 22:48:39.561033896 +0000 UTC deployed bt-redis-0.1.0 2.0.0-alpha + ``` + +
+ +- `h list --short | grep "^bt-dev-app" | xargs -L1 h uninstall` + + Uninstalls all development environment deploys. Specifically, list then filters for helm charts with prefix `bt-dev-app`, then uninstalls them all. As of November 14, 2024, there is no limit on the number of dev deploys. There is a noticeable amount of lag when there exceeds about 8 dev deploys. + +- `helm list --all-namespaces --all | grep 'uninstalling' | awk '{print $1}' | xargs -I {} helm delete --no-hooks {}` + + Force uninstalls all helm charts in "uninstalling" state. + +- `k create job --from cronjob/[cronjob name] [job name] -n bt` + + Creates a job from a cronjob. This is useful if you want to manually run the datapuller cronjob. + Uninstalls all development environment deploys. Specifically, list then filters for helm charts with prefix `bt-dev-app`, then uninstalls them all. + +## Common Errors + +When deploying a [sealed secret](https://github.com/bitnami-labs/sealed-secrets) and a `no key could decrypt secret` error is seen in `kubectl describe sealedsecret/*`, there are two possible solutions: +- Solution #1: During creating of sealed secret, make sure the (unsealed) secret is created in the correct namespace. +- Solution #2: Use the tag `--scope=namespace-wide` when running `kubeseal` to allow renaming of the sealed secret. More details on [the kubeseal documentation](https://github.com/bitnami-labs/sealed-secrets?tab=readme-ov-file#scopes). diff --git a/docs/src/core/infrastructure/onboarding.md b/docs/src/core/infrastructure/onboarding.md new file mode 100644 index 000000000..960cfd713 --- /dev/null +++ b/docs/src/core/infrastructure/onboarding.md @@ -0,0 +1,38 @@ +# Onboarding + +> [!WARNING] +> Running commands in `hozer-51` can break production! Please continue with caution. + +The Berkeleytime website is hosted on a machine supplied by [the OCF](https://www.ocf.berkeley.edu/). This machine will be referenced as `hozer-51` in these docs. SSH allows us to connect to `hozer-51` with a shell terminal, allowing us to infra-related tasks. + +This guide assumes basic experience with SSH. + +1. Please ensure your public SSH key has an identifying comment attached, such as your Berkeley email: + ```sh + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAq8Lwls394thisIsNotARealKey ga@github.com + ``` + You can directly modify your public key file at `~/.ssh/id_*.pub`, or you can use the following command: + ```sh + ssh-keygen -c -C "someone@berkeley.edu" -f ~/.ssh/id_* + ``` + Note that `-f` takes in the path to your *private* key file, but only modifies the *public* key file. + +2. Copy your SSH key to the `hozer` machine's `authorized_keys` file: + ``` + ssh-copy-id root@hozer-51.ocf.berkeley.edu + ``` + The SSH password can be found in the pinned messages of the \#backend staff channel in discord. + +3. (Optional) Add `hozer-51` to your `~/.ssh/config` file: + ```sh + # Begin Berkeleytime hozer config + Host hozer-?? + HostName %h.ocf.berkeley.edu + User root + # End Berkeleytime hozer config + ``` + Now, you can quickly SSH into the remote machine from your terminal: + ```sh + ssh hozer-51 + # as opposed to root@hozer-51.ocf.berkeley.edu + ``` diff --git a/docs/src/fa24/crowd-sourced-data/README.md b/docs/src/fa24/crowd-sourced-data/README.md new file mode 100644 index 000000000..3596cf66e --- /dev/null +++ b/docs/src/fa24/crowd-sourced-data/README.md @@ -0,0 +1 @@ +# Crowd Sourced Data diff --git a/docs/src/fa24/decals/README.md b/docs/src/fa24/decals/README.md new file mode 100644 index 000000000..e875bdd30 --- /dev/null +++ b/docs/src/fa24/decals/README.md @@ -0,0 +1 @@ +# Decals diff --git a/docs/src/fa24/gradtrak/README.md b/docs/src/fa24/gradtrak/README.md new file mode 100644 index 000000000..6595dad3b --- /dev/null +++ b/docs/src/fa24/gradtrak/README.md @@ -0,0 +1 @@ +# GradTrak diff --git a/docs/src/fa24/semantic-search/README.md b/docs/src/fa24/semantic-search/README.md new file mode 100644 index 000000000..95a7eed1d --- /dev/null +++ b/docs/src/fa24/semantic-search/README.md @@ -0,0 +1 @@ +# Semantic Search diff --git a/docs/src/getting-started/deployment-with-cicd.md b/docs/src/getting-started/deployment-with-cicd.md new file mode 100644 index 000000000..020fe1637 --- /dev/null +++ b/docs/src/getting-started/deployment-with-cicd.md @@ -0,0 +1,76 @@ +# Deployment with CI/CD + +The deployment process is different for [development](#development), [staging](#staging), and [production](#production) environments. + +## Development + +1. Go to the [actions page](https://github.com/asuc-octo/berkeleytime/actions). +
Image + + ![Github Actions Page](./assets/cicd-dev-1.png) + +
+ +2. Ensure "Deploy to Development" is the selected action on the left sidebar. +
Image + + ![Deploy to Development Sidebar Button](./assets/cicd-dev-2.png) + +
+ +3. Navigate to the "Run workflow" dropdown on the right. Select your branch and input a time to live in hours. Please keep this value a reasonable number. +
Image + + ![Deploy to Development Action Menu](./assets/cicd-dev-3.png) + +
+ +4. Once the action starts running, click into the action and watch the status of each step. If the deployment fails, the action will fail as well. +
Images + + ![Deploy to Development Action Running](./assets/cicd-dev-4.png) + You can view the logs of each step by navigating the left sidebar. + ![Deploy to Development Action Logs](./assets/cicd-dev-5.png) + +
+ +5. After the action succeeds, go to `www.abcdefg.dev.stanfurdtime.com`, where `abcdefg` is the first 7 characters of the latest commit's hash. This is also shown on the summary tab of an action workflow. + +
Example Success Deployment Log + + ``` + ======= CLI Version ======= + Drone SSH version 1.8.0 + =========================== + Release "bt-dev-app-69d94b6" does not exist. Installing it now. + Pulled: registry-1.docker.io/octoberkeleytime/bt-app:0.1.0-dev.69d94b6 + Digest: sha256:e3d020b8582b8b4c583f026f79e4ab2b374386ce67ea5ee43aa65c6b334f9db0 + W1204 22:20:37.827877 2103423 warnings.go:70] unknown field "spec.template.app.kubernetes.io/instance" + W1204 22:20:37.827939 2103423 warnings.go:70] unknown field "spec.template.app.kubernetes.io/managed-by" + W1204 22:20:37.827947 2103423 warnings.go:70] unknown field "spec.template.app.kubernetes.io/name" + W1204 22:20:37.827952 2103423 warnings.go:70] unknown field "spec.template.env" + W1204 22:20:37.827956 2103423 warnings.go:70] unknown field "spec.template.helm.sh/chart" + NAME: bt-dev-app-69d94b6 + LAST DEPLOYED: Wed Dec 4 22:20:36 2024 + NAMESPACE: bt + STATUS: deployed + REVISION: 1 + TEST SUITE: None + Waiting for deployment "bt-dev-app-69d94b6-backend" rollout to finish: 0 of 2 updated replicas are available... + Waiting for deployment "bt-dev-app-69d94b6-backend" rollout to finish: 1 of 2 updated replicas are available... + deployment "bt-dev-app-69d94b6-backend" successfully rolled out + deployment "bt-dev-app-69d94b6-frontend" successfully rolled out + =============================================== + ✅ Successfully executed commands to all hosts. + =============================================== + ``` + +
+ +## Staging + +The staging CI/CD pipeline is automatically run on every push to `master` (currently `gql`). The staging website can be viewed at `staging.stanfurdtime.com`. + +## Production + +The production CI/CD pipeline is manually run with a process similar to the development pipeline. However, the production pipeline can only be run on `master` and `gql`. diff --git a/docs/src/getting-started/local-development.md b/docs/src/getting-started/local-development.md new file mode 100644 index 000000000..2331b22ed --- /dev/null +++ b/docs/src/getting-started/local-development.md @@ -0,0 +1 @@ +# Local Development diff --git a/infra/docs/.helmignore b/infra/docs/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/infra/docs/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/infra/docs/Chart.yaml b/infra/docs/Chart.yaml new file mode 100644 index 000000000..bdda3ec3b --- /dev/null +++ b/infra/docs/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: bt-docs +description: A Helm chart for Berkeleytime's documentation website. + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.0.0-alpha" diff --git a/infra/docs/templates/_helpers.tpl b/infra/docs/templates/_helpers.tpl new file mode 100644 index 000000000..610f493f0 --- /dev/null +++ b/infra/docs/templates/_helpers.tpl @@ -0,0 +1,24 @@ +{{/* +Chart name and version +*/}} +{{- define "bt-docs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Labels applied to all resources. +*/}} +{{- define "bt-docs.labels" -}} +helm.sh/chart: {{ include "bt-docs.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{- define "bt-docs.docsLabels" -}} +app.kubernetes.io/name: docs +{{ include "bt-docs.labels" . }} +{{- end -}} + +{{- define "bt-docs.docsName" -}} +{{ .Release.Name }}-docs +{{- end -}} diff --git a/infra/docs/templates/docs.yaml b/infra/docs/templates/docs.yaml new file mode 100644 index 000000000..7a76dbd47 --- /dev/null +++ b/infra/docs/templates/docs.yaml @@ -0,0 +1,37 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "bt-docs.docsName" . }} + labels: + {{- include "bt-docs.docsLabels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "bt-docs.docsLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "bt-docs.docsLabels" . | nindent 8 }} + spec: + containers: + - name: docs + image: {{ printf "%s/%s:%s" .Values.docs.image.registry .Values.docs.image.repository ( toString .Values.docs.image.tag ) }} + imagePullPolicy: Always + ports: + - containerPort: {{ .Values.docs.port }} + +--- + +apiVersion: v1 +kind: Service +metadata: + name: {{ include "bt-docs.docsName" . }}-svc + labels: + {{- include "bt-docs.docsLabels" . | nindent 4 }} +spec: + selector: + {{- include "bt-docs.docsLabels" . | nindent 4 }} + ports: + - protocol: TCP + port: {{ .Values.port }} + targetPort: {{ .Values.docs.port }} diff --git a/infra/docs/templates/ingress.yaml b/infra/docs/templates/ingress.yaml new file mode 100644 index 000000000..41e73cf19 --- /dev/null +++ b/infra/docs/templates/ingress.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-ingress + labels: + {{- include "bt-docs.labels" . | nindent 4 }} + annotations: + cert-manager.io/issuer: {{ .Values.issuer }} +spec: + ingressClassName: nginx + tls: + - hosts: + - {{ .Values.host }} + secretName: bt-tls + rules: + - host: {{ .Values.host }} + http: + paths: + - path: {{ .Values.docs.path }} + pathType: Prefix + backend: + service: + name: {{ include "bt-docs.docsName" . }}-svc + port: + number: {{ .Values.port }} diff --git a/infra/docs/values.yaml b/infra/docs/values.yaml new file mode 100644 index 000000000..955b017e3 --- /dev/null +++ b/infra/docs/values.yaml @@ -0,0 +1,13 @@ +issuer: letsencrypt-prod + +host: docs.berkeleytime.com +port: 80 + +docs: + port: 80 + path: / + + image: + registry: docker.io + repository: octoberkeleytime/bt-docs + tag: prod