From 0fe4bcdb39396afa4b78df15dde9d3967b0c64f0 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 08:56:31 +0300 Subject: [PATCH 01/16] Add BookStack-based internal docs Docker setup Introduce a containerized local environment for the internal "The Mariana" documentation using BookStack. Adds docker-compose.yml (BookStack + MariaDB), .env.example with recommended defaults (APP_URL, DB creds, APP_PUBLIC=false), .gitignore to protect .env and persisted data (config/, db_data/), and a README with setup, access, security guidance, IA conventions, and persistence notes. Intended for local development on port 6875; remember to copy .env.example -> .env and update default credentials and secrets before use. --- src/internal-docs/.env.example | 43 +++++++++++++++ src/internal-docs/.gitignore | 8 +++ src/internal-docs/README.md | 80 ++++++++++++++++++++++++++++ src/internal-docs/docker-compose.yml | 53 ++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 src/internal-docs/.env.example create mode 100644 src/internal-docs/.gitignore create mode 100644 src/internal-docs/README.md create mode 100644 src/internal-docs/docker-compose.yml diff --git a/src/internal-docs/.env.example b/src/internal-docs/.env.example new file mode 100644 index 0000000000..b11e27a3bd --- /dev/null +++ b/src/internal-docs/.env.example @@ -0,0 +1,43 @@ +# ------------------------------------------------------------------------- +# BookStack Environment Configuration +# ------------------------------------------------------------------------- +# Copy this file to `.env` before running `docker-compose up -d`. +# Do not commit the `.env` file to version control. +# ------------------------------------------------------------------------- + +# The base URL of your BookStack installation. +# Must include the protocol (http:// or https://) +APP_URL=http://localhost:6875 + +# The name of the application (Shows in the header and emails) +APP_NAME="The Mariana" + +# Disable public access to enforce authentication for all pages +# Set to 'true' if you want anonymous users to read documentation +APP_PUBLIC=false + +# Application Key (Required for sessions and encryption) +# Generate a new one for production using: docker run --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:latest appkey +APP_KEY=base64:3SzJmwPFgbSN2g4q7WvJAZ0uhimQxrJ/RQK4awlgDP4= + +# ------------------------------------------------------------------------- +# Database Configuration +# ------------------------------------------------------------------------- +# Ensure these match the values used in docker-compose.yml. +DB_HOST=bookstack_db +DB_DATABASE=bookstackapp +DB_USER=bookstack +DB_PASSWORD=your_secure_db_password +DB_ROOT_PASSWORD=your_secure_root_password + +# ------------------------------------------------------------------------- +# Mail Settings (Optional but recommended for user invitations/resets) +# ------------------------------------------------------------------------- +# MAIL_DRIVER=smtp +# MAIL_HOST=smtp.mailtrap.io +# MAIL_PORT=2525 +# MAIL_USERNAME=null +# MAIL_PASSWORD=null +# MAIL_ENCRYPTION=null +# MAIL_FROM=docs@yourdomain.com +# MAIL_FROM_NAME="Internal Docs" diff --git a/src/internal-docs/.gitignore b/src/internal-docs/.gitignore new file mode 100644 index 0000000000..dfa33769ae --- /dev/null +++ b/src/internal-docs/.gitignore @@ -0,0 +1,8 @@ +# Ignore environment variables file +.env + +# Ignore Docker volumes for BookStack application state (uploads, themes, etc.) +config/ + +# Ignore Docker volumes for MariaDB database files +db_data/ diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md new file mode 100644 index 0000000000..bf842da249 --- /dev/null +++ b/src/internal-docs/README.md @@ -0,0 +1,80 @@ +# The Mariana - Internal Documentation + +This directory contains the containerized local development environment for "The Mariana," our internal documentation platform powered by [BookStack](https://www.bookstackapp.com/). + +## Local Setup Instructions + +To spin up the documentation platform locally, follow these steps: + +1. **Configure the Environment** + Duplicate the provided example environment file: + + **macOS / Linux (Bash):** + ```bash + cp .env.example .env + ``` + **Windows (Command Prompt / PowerShell):** + ```cmd + copy .env.example .env + ``` + *(You can leave the default values in `.env` for local testing. If you change passwords, ensure they match in both the BookStack and Database sections.)* + +2. **Start the Containers** + Use Docker Compose to build and start the environment in the background: + ```bash + docker-compose up -d + ``` + +3. **Access the Application** + Open your browser and navigate to `http://localhost:6875`. + +4. **Default Administrator Credentials** + On the very first run, BookStack creates a default admin account: + - **Email:** `admin@admin.com` + - **Password:** `password` + + > [!WARNING] + > Immediately change these credentials upon your first login. + +## Security & Access Control + +As per our security standards, this documentation is strictly internal. + +- **Public Access is Disabled**: The `.env` file explicitly sets `APP_PUBLIC=false`. This ensures that unauthenticated users cannot view any pages, shelves, or books. They will be immediately redirected to the login screen. +- **Authentication**: We use BookStack's standard **Email & Password** authentication. +- **User Management**: Open registration is disabled by default. Administrators must manually create accounts or invite new team members via the BookStack Settings > Users panel. + +## Information Architecture (Product-Focused) + +We organize all of our documentation using a **Product-focused approach**. Whether it's a mobile app, a microservice, or a data pipeline, every major initiative is treated as a Product. + +When writing or organizing documentation, strictly adhere to the following mapping of BookStack's hierarchy: + +### 1. Shelves (High-Level Domains) +Use Shelves to group related products under a larger domain or suite. +*Examples: AirQo Platform, Data Pipelines, Mobile Apps, Infrastructure.* + +### 2. Books (The Products) +Use Books to represent a specific Product, Microservice, or distinct Tool. +*Examples: Netmanager, Beacon, AirQo API, Ingestion Pipeline.* + +### 3. Chapters (Major Components) +Use Chapters to group related documentation topics within a specific Product. +*Examples: Architecture, API Reference, Deployment Guides, Runbooks, Onboarding.* + +### 4. Pages (Specific Documents) +Use Pages for the granular, individual pieces of documentation. +*Examples: Authentication Flow Diagram, GET /v1/devices, How to run the calibration script.* + +**Example Flow:** +If a new developer joins the Netmanager team, they navigate to: +`Shelves (AirQo Platform) -> Book (Netmanager) -> Chapter (API Reference) -> Page (Authentication Endpoint)` + +## Stopping and Data Persistence + +To stop the containers: +```bash +docker-compose down +``` + +All data (uploaded images, files, themes) is persisted in the `./config` folder, and the MariaDB database is persisted in the `./db_data` folder. These folders are ignored by git to prevent sensitive data leakage. diff --git a/src/internal-docs/docker-compose.yml b/src/internal-docs/docker-compose.yml new file mode 100644 index 0000000000..096b8a4beb --- /dev/null +++ b/src/internal-docs/docker-compose.yml @@ -0,0 +1,53 @@ +version: "3.8" + +services: + bookstack: + image: lscr.io/linuxserver/bookstack:latest + container_name: bookstack + environment: + - PUID=1000 + - PGID=1000 + - TZ=UTC + - APP_NAME=${APP_NAME:-"The Mariana"} + - APP_URL=${APP_URL:-http://localhost:6875} + - APP_KEY=${APP_KEY:-} + - DB_HOST=bookstack_db + - DB_PORT=3306 + - DB_USER=${DB_USER:-bookstack} + - DB_PASS=${DB_PASSWORD:-bookstack_secure_password} + - DB_USERNAME=${DB_USER:-bookstack} + - DB_PASSWORD=${DB_PASSWORD:-bookstack_secure_password} + - DB_DATABASE=${DB_DATABASE:-bookstackapp} + # Security & Access Control phase settings: + - APP_PUBLIC=${APP_PUBLIC:-false} # Disable public viewing by default + volumes: + - ./config:/config + ports: + - "6875:80" + restart: unless-stopped + depends_on: + - bookstack_db + networks: + - internal-docs-network + + bookstack_db: + image: lscr.io/linuxserver/mariadb:latest + container_name: bookstack_db + environment: + - PUID=1000 + - PGID=1000 + - TZ=UTC + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:-root_secure_password} + - MYSQL_DATABASE=${DB_DATABASE:-bookstackapp} + - MYSQL_USER=${DB_USER:-bookstack} + - MYSQL_PASSWORD=${DB_PASSWORD:-bookstack_secure_password} + volumes: + - ./db_data:/config + restart: unless-stopped + networks: + - internal-docs-network + +networks: + internal-docs-network: + name: internal-docs-network + driver: bridge From 4d91f6f27517586b271dce3b31bd825e3fee0fbb Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 09:09:51 +0300 Subject: [PATCH 02/16] Add Helm chart for internal-docs (Mariana) Introduce a new Helm chart for AirQo internal docs (The Mariana). Adds Chart.yaml, template helpers, deployments for app (BookStack) and DB (MariaDB), services, and PVCs. Includes environment-specific values files for production and staging with image defaults (linuxserver/bookstack, linuxserver/mariadb), resource and autoscaling settings, nodeSelector/affinity, unique NodePorts, configmap references, DB env vars, and 5Gi persistent storage for both app and DB. --- src/internal-docs/k8s/Chart.yaml | 10 +++ src/internal-docs/k8s/templates/_helpers.tpl | 49 ++++++++++++ .../k8s/templates/deployment-app.yaml | 58 +++++++++++++++ .../k8s/templates/deployment-db.yaml | 53 +++++++++++++ src/internal-docs/k8s/templates/pvc.yaml | 23 ++++++ .../k8s/templates/service-app.yaml | 19 +++++ .../k8s/templates/service-db.yaml | 16 ++++ src/internal-docs/k8s/values-prod.yaml | 74 +++++++++++++++++++ src/internal-docs/k8s/values-stage.yaml | 74 +++++++++++++++++++ 9 files changed, 376 insertions(+) create mode 100644 src/internal-docs/k8s/Chart.yaml create mode 100644 src/internal-docs/k8s/templates/_helpers.tpl create mode 100644 src/internal-docs/k8s/templates/deployment-app.yaml create mode 100644 src/internal-docs/k8s/templates/deployment-db.yaml create mode 100644 src/internal-docs/k8s/templates/pvc.yaml create mode 100644 src/internal-docs/k8s/templates/service-app.yaml create mode 100644 src/internal-docs/k8s/templates/service-db.yaml create mode 100644 src/internal-docs/k8s/values-prod.yaml create mode 100644 src/internal-docs/k8s/values-stage.yaml diff --git a/src/internal-docs/k8s/Chart.yaml b/src/internal-docs/k8s/Chart.yaml new file mode 100644 index 0000000000..2bd7e9b4df --- /dev/null +++ b/src/internal-docs/k8s/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +appVersion: "1.0.0" +description: AirQo Internal Docs (The Mariana) Helm Chart +name: airqo-internal-docs +home: https://airqo.net +version: 0.1.0 +maintainers: + - name: AirQo + email: support@airqo.net + url: https://airqo.net diff --git a/src/internal-docs/k8s/templates/_helpers.tpl b/src/internal-docs/k8s/templates/_helpers.tpl new file mode 100644 index 0000000000..75f1964af3 --- /dev/null +++ b/src/internal-docs/k8s/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "internal-docs.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "internal-docs.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "internal-docs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "internal-docs.labels" -}} +helm.sh/chart: {{ include "internal-docs.chart" . }} +{{ include "internal-docs.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "internal-docs.selectorLabels" -}} +app.kubernetes.io/name: {{ include "internal-docs.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/src/internal-docs/k8s/templates/deployment-app.yaml b/src/internal-docs/k8s/templates/deployment-app.yaml new file mode 100644 index 0000000000..9bb0265db5 --- /dev/null +++ b/src/internal-docs/k8s/templates/deployment-app.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.app.name }} + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ .Values.app.label }} + template: + metadata: + labels: + app: {{ .Values.app.label }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Values.app.label }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.targetPort }} + protocol: TCP + env: + - name: DB_HOST + value: {{ .Values.dbApp.name }} + - name: APP_URL + value: {{ .Values.app.url | quote }} + envFrom: + - configMapRef: + name: {{ .Values.app.configmap }} + volumeMounts: + - name: bookstack-config + mountPath: /config + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumes: + - name: bookstack-config + persistentVolumeClaim: + claimName: {{ .Values.app.name }}-pvc + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/src/internal-docs/k8s/templates/deployment-db.yaml b/src/internal-docs/k8s/templates/deployment-db.yaml new file mode 100644 index 0000000000..6f1220ed29 --- /dev/null +++ b/src/internal-docs/k8s/templates/deployment-db.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.dbApp.name }} + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Values.dbApp.label }} + template: + metadata: + labels: + app: {{ .Values.dbApp.label }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Values.dbApp.label }} + image: "{{ .Values.dbImage.repository }}:{{ .Values.dbImage.tag }}" + imagePullPolicy: {{ .Values.dbImage.pullPolicy }} + ports: + - name: mysql + containerPort: {{ .Values.dbService.targetPort }} + protocol: TCP + envFrom: + - configMapRef: + name: {{ .Values.app.configmap }} + volumeMounts: + - name: mariadb-config + mountPath: /config + resources: + {{- toYaml .Values.dbResources | nindent 12 }} + volumes: + - name: mariadb-config + persistentVolumeClaim: + claimName: {{ .Values.dbApp.name }}-pvc + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/src/internal-docs/k8s/templates/pvc.yaml b/src/internal-docs/k8s/templates/pvc.yaml new file mode 100644 index 0000000000..d3317f1dd5 --- /dev/null +++ b/src/internal-docs/k8s/templates/pvc.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Values.app.name }}-pvc + namespace: {{ .Values.app.namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Values.dbApp.name }}-pvc + namespace: {{ .Values.app.namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/src/internal-docs/k8s/templates/service-app.yaml b/src/internal-docs/k8s/templates/service-app.yaml new file mode 100644 index 0000000000..594d4a3ccb --- /dev/null +++ b/src/internal-docs/k8s/templates/service-app.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.name }} + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: http + {{- if eq .Values.service.type "NodePort" }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + selector: + app: {{ .Values.app.label }} diff --git a/src/internal-docs/k8s/templates/service-db.yaml b/src/internal-docs/k8s/templates/service-db.yaml new file mode 100644 index 0000000000..034b9a85b1 --- /dev/null +++ b/src/internal-docs/k8s/templates/service-db.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.dbApp.name }} + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +spec: + type: {{ .Values.dbService.type }} + ports: + - port: {{ .Values.dbService.port }} + targetPort: {{ .Values.dbService.targetPort }} + protocol: TCP + name: mysql + selector: + app: {{ .Values.dbApp.label }} diff --git a/src/internal-docs/k8s/values-prod.yaml b/src/internal-docs/k8s/values-prod.yaml new file mode 100644 index 0000000000..72f017d359 --- /dev/null +++ b/src/internal-docs/k8s/values-prod.yaml @@ -0,0 +1,74 @@ +replicaCount: 2 +image: + repository: lscr.io/linuxserver/bookstack + tag: latest + pullPolicy: IfNotPresent +dbImage: + repository: lscr.io/linuxserver/mariadb + tag: latest + pullPolicy: IfNotPresent +imagePullSecrets: [] +nameOverride: '' +fullnameOverride: '' + +service: + type: NodePort + port: 6875 + targetPort: 80 + nodePort: 31197 # Unique NodePort for production + +dbService: + type: ClusterIP + port: 3306 + targetPort: 3306 + +ingress: + enabled: false + +resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 100m + memory: 512Mi + +dbResources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 100m + memory: 512Mi + +autoscaling: + minReplicas: 2 + maxReplicas: 5 + targetCPUUtilizationPercentage: 80 + +nodeSelector: + role: high-mem + +tolerations: [] + +affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: role + operator: In + values: + - high-mem + weight: 1 + +app: + name: airqo-prod-internal-docs + label: prod-internal-docs + namespace: production + configmap: env-internal-docs-prod + url: "https://platform.airqo.net/mariana" + +dbApp: + name: airqo-prod-internal-docs-db + label: prod-internal-docs-db diff --git a/src/internal-docs/k8s/values-stage.yaml b/src/internal-docs/k8s/values-stage.yaml new file mode 100644 index 0000000000..1601eea063 --- /dev/null +++ b/src/internal-docs/k8s/values-stage.yaml @@ -0,0 +1,74 @@ +replicaCount: 1 +image: + repository: lscr.io/linuxserver/bookstack + tag: latest + pullPolicy: IfNotPresent +dbImage: + repository: lscr.io/linuxserver/mariadb + tag: latest + pullPolicy: IfNotPresent +imagePullSecrets: [] +nameOverride: '' +fullnameOverride: '' + +service: + type: NodePort + port: 6875 + targetPort: 80 + nodePort: 31196 # Unique NodePort for staging + +dbService: + type: ClusterIP + port: 3306 + targetPort: 3306 + +ingress: + enabled: false + +resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 50m + memory: 256Mi + +dbResources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 50m + memory: 256Mi + +autoscaling: + minReplicas: 1 + maxReplicas: 2 + targetCPUUtilizationPercentage: 80 + +nodeSelector: + role: high-mem + +tolerations: [] + +affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: role + operator: In + values: + - high-mem + weight: 1 + +app: + name: airqo-stage-internal-docs + label: sta-internal-docs + namespace: staging + configmap: env-internal-docs-staging + url: "https://staging-platform.airqo.net/mariana" + +dbApp: + name: airqo-stage-internal-docs-db + label: sta-internal-docs-db From f2d106fb07e73b9ea8543ccc111daf9bc5523411 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 09:11:02 +0300 Subject: [PATCH 03/16] Update README.md --- src/internal-docs/README.md | 104 ++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 40 deletions(-) diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md index bf842da249..5884a88fb3 100644 --- a/src/internal-docs/README.md +++ b/src/internal-docs/README.md @@ -1,23 +1,30 @@ # The Mariana - Internal Documentation -This directory contains the containerized local development environment for "The Mariana," our internal documentation platform powered by [BookStack](https://www.bookstackapp.com/). +This repository contains the containerized environment and Kubernetes Helm charts for **The Mariana**, AirQo's internal documentation platform powered by [BookStack](https://www.bookstackapp.com/). -## Local Setup Instructions +## Table of Contents +- [Local Setup & Testing](#local-setup--testing) +- [Kubernetes Deployment](#kubernetes-deployment) +- [Creating & Editing Documentation](#creating--editing-documentation) +- [Information Architecture](#information-architecture-product-focused) +- [Contributing Guidelines](#contributing-guidelines) +- [Security & Data Persistence](#security--data-persistence) -To spin up the documentation platform locally, follow these steps: +## Local Setup & Testing + +To spin up the documentation platform locally for testing or local development: 1. **Configure the Environment** Duplicate the provided example environment file: - **macOS / Linux (Bash):** + *macOS / Linux:* ```bash cp .env.example .env ``` - **Windows (Command Prompt / PowerShell):** + *Windows (Command Prompt / PowerShell):* ```cmd copy .env.example .env ``` - *(You can leave the default values in `.env` for local testing. If you change passwords, ensure they match in both the BookStack and Database sections.)* 2. **Start the Containers** Use Docker Compose to build and start the environment in the background: @@ -27,54 +34,71 @@ To spin up the documentation platform locally, follow these steps: 3. **Access the Application** Open your browser and navigate to `http://localhost:6875`. + *(Default credentials on first run: `admin@admin.com` / `password`)* -4. **Default Administrator Credentials** - On the very first run, BookStack creates a default admin account: - - **Email:** `admin@admin.com` - - **Password:** `password` - - > [!WARNING] - > Immediately change these credentials upon your first login. +## Kubernetes Deployment -## Security & Access Control +The project uses Helm charts located in the `k8s/` directory to deploy to our staging and production clusters. -As per our security standards, this documentation is strictly internal. +### Environments +- **Staging**: Accessible at `https://staging-platform.airqo.net/mariana` +- **Production**: Accessible at `https://platform.airqo.net/mariana` -- **Public Access is Disabled**: The `.env` file explicitly sets `APP_PUBLIC=false`. This ensures that unauthenticated users cannot view any pages, shelves, or books. They will be immediately redirected to the login screen. -- **Authentication**: We use BookStack's standard **Email & Password** authentication. -- **User Management**: Open registration is disabled by default. Administrators must manually create accounts or invite new team members via the BookStack Settings > Users panel. +### Deployment Commands +To deploy or upgrade the cluster, run the following Helm commands from the root of this project: -## Information Architecture (Product-Focused) +**Staging:** +```bash +helm upgrade --install airqo-internal-docs k8s/ -f k8s/values-stage.yaml -n staging +``` + +**Production:** +```bash +helm upgrade --install airqo-internal-docs k8s/ -f k8s/values-prod.yaml -n production +``` + +## Creating & Editing Documentation -We organize all of our documentation using a **Product-focused approach**. Whether it's a mobile app, a microservice, or a data pipeline, every major initiative is treated as a Product. +BookStack features an intuitive WYSIWYG editor, making it incredibly easy for any technical contributor to document features, APIs, and runbooks without fighting markdown syntax (though Markdown is fully supported!). -When writing or organizing documentation, strictly adhere to the following mapping of BookStack's hierarchy: +### How to Create Content +1. **Navigate to the appropriate Book**: Look at the Information Architecture below to find exactly where your document belongs. +2. **Add a Chapter or Page**: Click the "New Page" or "New Chapter" button in the right sidebar menu. +3. **Use the Editor**: Write your documentation. You can drag-and-drop images directly into the editor. If you prefer raw markdown, you can switch the editor type in your user settings. +4. **Link Internal Content**: Use the "Link" button to easily search and interlink to other existing internal documents. -### 1. Shelves (High-Level Domains) -Use Shelves to group related products under a larger domain or suite. -*Examples: AirQo Platform, Data Pipelines, Mobile Apps, Infrastructure.* +### Best Practices for Documentation +- **Keep it Concise**: Use bullet points, clear headings, and avoid massive walls of text. Scannability is key. +- **Keep it Updated**: The Boy Scout Rule applies—if you change a system's behavior, update its documentation in the exact same sprint. +- **Use Code Blocks**: When documenting CLI commands, scripts, or JSON payloads, use properly formatted code blocks. +- **Tagging**: Use tags on your pages (e.g., `api`, `deprecated`, `v2`) to make them highly searchable across the platform. -### 2. Books (The Products) -Use Books to represent a specific Product, Microservice, or distinct Tool. -*Examples: Netmanager, Beacon, AirQo API, Ingestion Pipeline.* +## Information Architecture (Product-Focused) -### 3. Chapters (Major Components) -Use Chapters to group related documentation topics within a specific Product. -*Examples: Architecture, API Reference, Deployment Guides, Runbooks, Onboarding.* +We organize all of our documentation using a **Product-focused approach**. Whether it's a mobile app, a microservice, or a data pipeline, every major initiative is treated as a Product. Strictly adhere to the following hierarchy: -### 4. Pages (Specific Documents) -Use Pages for the granular, individual pieces of documentation. -*Examples: Authentication Flow Diagram, GET /v1/devices, How to run the calibration script.* +1. **Shelves (High-Level Domains)**: Groups related products under a larger domain or suite. + *(Examples: AirQo Platform, Data Pipelines, Mobile Apps, Infrastructure)* +2. **Books (The Products)**: Represents a specific Product, Microservice, or distinct Tool. + *(Examples: Netmanager, Beacon, AirQo API, Ingestion Pipeline)* +3. **Chapters (Major Components)**: Groups related documentation topics within a specific Product. + *(Examples: Architecture, API Reference, Deployment Guides, Runbooks)* +4. **Pages (Specific Documents)**: The granular, individual pieces of documentation. + *(Examples: Authentication Flow Diagram, GET /v1/devices, How to run the calibration script)* **Example Flow:** -If a new developer joins the Netmanager team, they navigate to: `Shelves (AirQo Platform) -> Book (Netmanager) -> Chapter (API Reference) -> Page (Authentication Endpoint)` -## Stopping and Data Persistence +## Contributing Guidelines -To stop the containers: -```bash -docker-compose down -``` +We encourage all engineers to actively contribute to The Mariana. If you see something wrong, fix it! + +- **Typos and Minor Fixes**: Fix them immediately using the BookStack web interface. No review needed. +- **Major Architectural Documentation**: Draft the documentation in a Page and request a review (via Slack or email link) from the Lead Engineer of that specific product before finalizing. +- **Infrastructure Changes**: If you are modifying the Helm charts or Docker Compose configurations in this repository, please create a feature branch, test locally using Docker Compose, and open a standard Pull Request on GitHub. + +## Security & Data Persistence -All data (uploaded images, files, themes) is persisted in the `./config` folder, and the MariaDB database is persisted in the `./db_data` folder. These folders are ignored by git to prevent sensitive data leakage. +- **Public Access**: Explicitly disabled (`APP_PUBLIC=false`). Unauthenticated users cannot view any pages and will be immediately redirected to the login screen. +- **User Management**: Open registration is disabled. Administrators manually provision access. +- **Data Persistence**: In Kubernetes, Persistent Volume Claims (PVCs) ensure uploaded images and database state survive pod restarts. Locally, data is stored in the git-ignored `./config` and `./db_data` folders. From 2b06a968283339247c477ba2c543281d2cc76396 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 09:35:32 +0300 Subject: [PATCH 04/16] Rename docs to Mariana Deep; update DB setup Rebrand internal docs from "The Mariana" to "Mariana Deep" across .env.example, README, docker-compose.yml, and Chart.yaml. Standardize MariaDB usage by switching to the official mariadb:10.6 image, changing the DB data mount to /var/lib/mysql, switching to a named Docker volume (bookstack_db_data) and adding the volume block in docker-compose. Mirror the image/tag change in Helm values and adjust the k8s deployment volume mount. Also add db_data_v2/ to .gitignore. --- src/internal-docs/.env.example | 2 +- src/internal-docs/.gitignore | 1 + src/internal-docs/README.md | 6 +++--- src/internal-docs/docker-compose.yml | 9 ++++++--- src/internal-docs/k8s/Chart.yaml | 2 +- src/internal-docs/k8s/templates/deployment-db.yaml | 2 +- src/internal-docs/k8s/values-prod.yaml | 4 ++-- src/internal-docs/k8s/values-stage.yaml | 4 ++-- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/internal-docs/.env.example b/src/internal-docs/.env.example index b11e27a3bd..faca3f58f8 100644 --- a/src/internal-docs/.env.example +++ b/src/internal-docs/.env.example @@ -10,7 +10,7 @@ APP_URL=http://localhost:6875 # The name of the application (Shows in the header and emails) -APP_NAME="The Mariana" +APP_NAME="Mariana Deep" # Disable public access to enforce authentication for all pages # Set to 'true' if you want anonymous users to read documentation diff --git a/src/internal-docs/.gitignore b/src/internal-docs/.gitignore index dfa33769ae..41813ebc80 100644 --- a/src/internal-docs/.gitignore +++ b/src/internal-docs/.gitignore @@ -6,3 +6,4 @@ config/ # Ignore Docker volumes for MariaDB database files db_data/ +db_data_v2/ diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md index 5884a88fb3..b0d389066d 100644 --- a/src/internal-docs/README.md +++ b/src/internal-docs/README.md @@ -1,6 +1,6 @@ -# The Mariana - Internal Documentation +# Mariana Deep - Internal Documentation -This repository contains the containerized environment and Kubernetes Helm charts for **The Mariana**, AirQo's internal documentation platform powered by [BookStack](https://www.bookstackapp.com/). +This repository contains the containerized environment and Kubernetes Helm charts for **Mariana Deep**, AirQo's internal documentation platform powered by [BookStack](https://www.bookstackapp.com/). ## Table of Contents - [Local Setup & Testing](#local-setup--testing) @@ -91,7 +91,7 @@ We organize all of our documentation using a **Product-focused approach**. Wheth ## Contributing Guidelines -We encourage all engineers to actively contribute to The Mariana. If you see something wrong, fix it! +We encourage all engineers to actively contribute to Mariana Deep. If you see something wrong, fix it! - **Typos and Minor Fixes**: Fix them immediately using the BookStack web interface. No review needed. - **Major Architectural Documentation**: Draft the documentation in a Page and request a review (via Slack or email link) from the Lead Engineer of that specific product before finalizing. diff --git a/src/internal-docs/docker-compose.yml b/src/internal-docs/docker-compose.yml index 096b8a4beb..4d5f7919a4 100644 --- a/src/internal-docs/docker-compose.yml +++ b/src/internal-docs/docker-compose.yml @@ -8,7 +8,7 @@ services: - PUID=1000 - PGID=1000 - TZ=UTC - - APP_NAME=${APP_NAME:-"The Mariana"} + - APP_NAME=${APP_NAME:-"Mariana Deep"} - APP_URL=${APP_URL:-http://localhost:6875} - APP_KEY=${APP_KEY:-} - DB_HOST=bookstack_db @@ -31,7 +31,7 @@ services: - internal-docs-network bookstack_db: - image: lscr.io/linuxserver/mariadb:latest + image: mariadb:10.6 container_name: bookstack_db environment: - PUID=1000 @@ -42,7 +42,7 @@ services: - MYSQL_USER=${DB_USER:-bookstack} - MYSQL_PASSWORD=${DB_PASSWORD:-bookstack_secure_password} volumes: - - ./db_data:/config + - bookstack_db_data:/var/lib/mysql restart: unless-stopped networks: - internal-docs-network @@ -51,3 +51,6 @@ networks: internal-docs-network: name: internal-docs-network driver: bridge + +volumes: + bookstack_db_data: diff --git a/src/internal-docs/k8s/Chart.yaml b/src/internal-docs/k8s/Chart.yaml index 2bd7e9b4df..f06cdc7298 100644 --- a/src/internal-docs/k8s/Chart.yaml +++ b/src/internal-docs/k8s/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 appVersion: "1.0.0" -description: AirQo Internal Docs (The Mariana) Helm Chart +description: AirQo Internal Docs (Mariana Deep) Helm Chart name: airqo-internal-docs home: https://airqo.net version: 0.1.0 diff --git a/src/internal-docs/k8s/templates/deployment-db.yaml b/src/internal-docs/k8s/templates/deployment-db.yaml index 6f1220ed29..40d69e41f2 100644 --- a/src/internal-docs/k8s/templates/deployment-db.yaml +++ b/src/internal-docs/k8s/templates/deployment-db.yaml @@ -32,7 +32,7 @@ spec: name: {{ .Values.app.configmap }} volumeMounts: - name: mariadb-config - mountPath: /config + mountPath: /var/lib/mysql resources: {{- toYaml .Values.dbResources | nindent 12 }} volumes: diff --git a/src/internal-docs/k8s/values-prod.yaml b/src/internal-docs/k8s/values-prod.yaml index 72f017d359..dec8f77e22 100644 --- a/src/internal-docs/k8s/values-prod.yaml +++ b/src/internal-docs/k8s/values-prod.yaml @@ -4,8 +4,8 @@ image: tag: latest pullPolicy: IfNotPresent dbImage: - repository: lscr.io/linuxserver/mariadb - tag: latest + repository: mariadb + tag: 10.6 pullPolicy: IfNotPresent imagePullSecrets: [] nameOverride: '' diff --git a/src/internal-docs/k8s/values-stage.yaml b/src/internal-docs/k8s/values-stage.yaml index 1601eea063..bd66c95629 100644 --- a/src/internal-docs/k8s/values-stage.yaml +++ b/src/internal-docs/k8s/values-stage.yaml @@ -4,8 +4,8 @@ image: tag: latest pullPolicy: IfNotPresent dbImage: - repository: lscr.io/linuxserver/mariadb - tag: latest + repository: mariadb + tag: 10.6 pullPolicy: IfNotPresent imagePullSecrets: [] nameOverride: '' From 61fe431fb5e28689d10184c12fa96cacce70bed0 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 09:55:25 +0300 Subject: [PATCH 05/16] Remove staging Helm values and update README Delete k8s/values-stage.yaml and update src/internal-docs/README.md to remove staging references and the staging Helm command. The README now states Helm charts deploy to the production cluster and retains the production deploy command (-f k8s/values-prod.yaml -n production). This cleans up stale staging configuration and documentation. --- src/internal-docs/README.md | 8 +-- src/internal-docs/k8s/values-stage.yaml | 74 ------------------------- 2 files changed, 1 insertion(+), 81 deletions(-) delete mode 100644 src/internal-docs/k8s/values-stage.yaml diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md index b0d389066d..03579de3bc 100644 --- a/src/internal-docs/README.md +++ b/src/internal-docs/README.md @@ -38,20 +38,14 @@ To spin up the documentation platform locally for testing or local development: ## Kubernetes Deployment -The project uses Helm charts located in the `k8s/` directory to deploy to our staging and production clusters. +The project uses Helm charts located in the `k8s/` directory to deploy to our production cluster. ### Environments -- **Staging**: Accessible at `https://staging-platform.airqo.net/mariana` - **Production**: Accessible at `https://platform.airqo.net/mariana` ### Deployment Commands To deploy or upgrade the cluster, run the following Helm commands from the root of this project: -**Staging:** -```bash -helm upgrade --install airqo-internal-docs k8s/ -f k8s/values-stage.yaml -n staging -``` - **Production:** ```bash helm upgrade --install airqo-internal-docs k8s/ -f k8s/values-prod.yaml -n production diff --git a/src/internal-docs/k8s/values-stage.yaml b/src/internal-docs/k8s/values-stage.yaml deleted file mode 100644 index bd66c95629..0000000000 --- a/src/internal-docs/k8s/values-stage.yaml +++ /dev/null @@ -1,74 +0,0 @@ -replicaCount: 1 -image: - repository: lscr.io/linuxserver/bookstack - tag: latest - pullPolicy: IfNotPresent -dbImage: - repository: mariadb - tag: 10.6 - pullPolicy: IfNotPresent -imagePullSecrets: [] -nameOverride: '' -fullnameOverride: '' - -service: - type: NodePort - port: 6875 - targetPort: 80 - nodePort: 31196 # Unique NodePort for staging - -dbService: - type: ClusterIP - port: 3306 - targetPort: 3306 - -ingress: - enabled: false - -resources: - limits: - cpu: 200m - memory: 512Mi - requests: - cpu: 50m - memory: 256Mi - -dbResources: - limits: - cpu: 200m - memory: 512Mi - requests: - cpu: 50m - memory: 256Mi - -autoscaling: - minReplicas: 1 - maxReplicas: 2 - targetCPUUtilizationPercentage: 80 - -nodeSelector: - role: high-mem - -tolerations: [] - -affinity: - nodeAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - preference: - matchExpressions: - - key: role - operator: In - values: - - high-mem - weight: 1 - -app: - name: airqo-stage-internal-docs - label: sta-internal-docs - namespace: staging - configmap: env-internal-docs-staging - url: "https://staging-platform.airqo.net/mariana" - -dbApp: - name: airqo-stage-internal-docs-db - label: sta-internal-docs-db From 630b88b15190093a881f9d489c3c5618d9b2c9be Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 09:58:00 +0300 Subject: [PATCH 06/16] Update .env.example --- src/internal-docs/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal-docs/.env.example b/src/internal-docs/.env.example index faca3f58f8..b1189bc60b 100644 --- a/src/internal-docs/.env.example +++ b/src/internal-docs/.env.example @@ -18,7 +18,7 @@ APP_PUBLIC=false # Application Key (Required for sessions and encryption) # Generate a new one for production using: docker run --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:latest appkey -APP_KEY=base64:3SzJmwPFgbSN2g4q7WvJAZ0uhimQxrJ/RQK4awlgDP4= +APP_KEY= # ------------------------------------------------------------------------- # Database Configuration From d594d662f824e126aaf09a6206fc2a4a57413f3b Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:05:38 +0300 Subject: [PATCH 07/16] Remove redundant database environment variables. --- src/internal-docs/docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/internal-docs/docker-compose.yml b/src/internal-docs/docker-compose.yml index 4d5f7919a4..47c4d65918 100644 --- a/src/internal-docs/docker-compose.yml +++ b/src/internal-docs/docker-compose.yml @@ -15,8 +15,6 @@ services: - DB_PORT=3306 - DB_USER=${DB_USER:-bookstack} - DB_PASS=${DB_PASSWORD:-bookstack_secure_password} - - DB_USERNAME=${DB_USER:-bookstack} - - DB_PASSWORD=${DB_PASSWORD:-bookstack_secure_password} - DB_DATABASE=${DB_DATABASE:-bookstackapp} # Security & Access Control phase settings: - APP_PUBLIC=${APP_PUBLIC:-false} # Disable public viewing by default From c33038e497bc03e3e72dd26c861b7fa8a4bf9a06 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:07:15 +0300 Subject: [PATCH 08/16] Remove PUID/PGID from MariaDB service. --- src/internal-docs/docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/internal-docs/docker-compose.yml b/src/internal-docs/docker-compose.yml index 47c4d65918..3c556e3f0c 100644 --- a/src/internal-docs/docker-compose.yml +++ b/src/internal-docs/docker-compose.yml @@ -32,8 +32,6 @@ services: image: mariadb:10.6 container_name: bookstack_db environment: - - PUID=1000 - - PGID=1000 - TZ=UTC - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:-root_secure_password} - MYSQL_DATABASE=${DB_DATABASE:-bookstackapp} From 36d3e9c5aa0e65bd86a25c2235c0f5cdb22c2c7d Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:09:01 +0300 Subject: [PATCH 09/16] Pin the image tag instead of using latest in production. --- src/internal-docs/docker-compose.yml | 2 +- src/internal-docs/k8s/values-prod.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal-docs/docker-compose.yml b/src/internal-docs/docker-compose.yml index 3c556e3f0c..c07c985d64 100644 --- a/src/internal-docs/docker-compose.yml +++ b/src/internal-docs/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.8" services: bookstack: - image: lscr.io/linuxserver/bookstack:latest + image: lscr.io/linuxserver/bookstack:24.05.2 container_name: bookstack environment: - PUID=1000 diff --git a/src/internal-docs/k8s/values-prod.yaml b/src/internal-docs/k8s/values-prod.yaml index dec8f77e22..00634be4a7 100644 --- a/src/internal-docs/k8s/values-prod.yaml +++ b/src/internal-docs/k8s/values-prod.yaml @@ -1,7 +1,7 @@ replicaCount: 2 image: repository: lscr.io/linuxserver/bookstack - tag: latest + tag: 24.05.2 pullPolicy: IfNotPresent dbImage: repository: mariadb From 54ebf735a39ef61f36d438449688049824fec619 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:10:46 +0300 Subject: [PATCH 10/16] Fix missing ConfigMap referenced by deployment --- .../k8s/templates/configmap.yaml | 23 +++++++++++++++++++ src/internal-docs/k8s/values-prod.yaml | 9 ++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/internal-docs/k8s/templates/configmap.yaml diff --git a/src/internal-docs/k8s/templates/configmap.yaml b/src/internal-docs/k8s/templates/configmap.yaml new file mode 100644 index 0000000000..2592689e9e --- /dev/null +++ b/src/internal-docs/k8s/templates/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.app.configmap }} + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +data: + # BookStack Specific + APP_NAME: {{ .Values.env.APP_NAME | quote }} + APP_KEY: {{ .Values.env.APP_KEY | quote }} + APP_PUBLIC: {{ .Values.env.APP_PUBLIC | quote }} + + # Shared Database Configuration (Used by BookStack container) + DB_USER: {{ .Values.env.DB_USER | quote }} + DB_PASS: {{ .Values.env.DB_PASSWORD | quote }} + DB_DATABASE: {{ .Values.env.DB_DATABASE | quote }} + + # MariaDB Specific (Used by MariaDB container) + MYSQL_USER: {{ .Values.env.DB_USER | quote }} + MYSQL_PASSWORD: {{ .Values.env.DB_PASSWORD | quote }} + MYSQL_DATABASE: {{ .Values.env.DB_DATABASE | quote }} + MYSQL_ROOT_PASSWORD: {{ .Values.env.MYSQL_ROOT_PASSWORD | quote }} diff --git a/src/internal-docs/k8s/values-prod.yaml b/src/internal-docs/k8s/values-prod.yaml index 00634be4a7..c60bb706e3 100644 --- a/src/internal-docs/k8s/values-prod.yaml +++ b/src/internal-docs/k8s/values-prod.yaml @@ -72,3 +72,12 @@ app: dbApp: name: airqo-prod-internal-docs-db label: prod-internal-docs-db + +env: + APP_NAME: "Mariana Deep" + APP_KEY: "" # Must be securely injected via CI/CD or secrets management + APP_PUBLIC: "false" + DB_USER: "bookstack" + DB_PASSWORD: "" # Must be securely injected + DB_DATABASE: "bookstackapp" + MYSQL_ROOT_PASSWORD: "" # Must be securely injected From c469887bea37a0730eaae008111bc4c846a8d078 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:11:53 +0300 Subject: [PATCH 11/16] Add liveness and readiness probes for database reliability. --- .../k8s/templates/deployment-db.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/internal-docs/k8s/templates/deployment-db.yaml b/src/internal-docs/k8s/templates/deployment-db.yaml index 40d69e41f2..786045041d 100644 --- a/src/internal-docs/k8s/templates/deployment-db.yaml +++ b/src/internal-docs/k8s/templates/deployment-db.yaml @@ -33,6 +33,26 @@ spec: volumeMounts: - name: mariadb-config mountPath: /var/lib/mysql + livenessProbe: + exec: + command: + - sh + - -c + - mysqladmin ping -h localhost + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + exec: + command: + - sh + - -c + - mysql -h localhost -e 'SELECT 1' + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 2 resources: {{- toYaml .Values.dbResources | nindent 12 }} volumes: From 2d7bbffa6319c29da53cb8a933df207244f6cff0 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:13:34 +0300 Subject: [PATCH 12/16] larger database storage and explicit storageClassName for production --- src/internal-docs/k8s/templates/pvc.yaml | 10 ++++++++-- src/internal-docs/k8s/values-prod.yaml | 8 ++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/internal-docs/k8s/templates/pvc.yaml b/src/internal-docs/k8s/templates/pvc.yaml index d3317f1dd5..7139a8a19a 100644 --- a/src/internal-docs/k8s/templates/pvc.yaml +++ b/src/internal-docs/k8s/templates/pvc.yaml @@ -6,9 +6,12 @@ metadata: spec: accessModes: - ReadWriteOnce + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass }} + {{- end }} resources: requests: - storage: 5Gi + storage: {{ .Values.persistence.size }} --- apiVersion: v1 kind: PersistentVolumeClaim @@ -18,6 +21,9 @@ metadata: spec: accessModes: - ReadWriteOnce + {{- if .Values.dbPersistence.storageClass }} + storageClassName: {{ .Values.dbPersistence.storageClass }} + {{- end }} resources: requests: - storage: 5Gi + storage: {{ .Values.dbPersistence.size }} diff --git a/src/internal-docs/k8s/values-prod.yaml b/src/internal-docs/k8s/values-prod.yaml index c60bb706e3..0593a9bbdc 100644 --- a/src/internal-docs/k8s/values-prod.yaml +++ b/src/internal-docs/k8s/values-prod.yaml @@ -73,6 +73,14 @@ dbApp: name: airqo-prod-internal-docs-db label: prod-internal-docs-db +persistence: + size: 5Gi + storageClass: "fast-ssd" + +dbPersistence: + size: 20Gi + storageClass: "fast-ssd" + env: APP_NAME: "Mariana Deep" APP_KEY: "" # Must be securely injected via CI/CD or secrets management From e9aa717c1def36447151bd9e4e1c5d3eeac691d8 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:14:05 +0300 Subject: [PATCH 13/16] Create hpa.yaml --- src/internal-docs/k8s/templates/hpa.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/internal-docs/k8s/templates/hpa.yaml diff --git a/src/internal-docs/k8s/templates/hpa.yaml b/src/internal-docs/k8s/templates/hpa.yaml new file mode 100644 index 0000000000..9803305c14 --- /dev/null +++ b/src/internal-docs/k8s/templates/hpa.yaml @@ -0,0 +1,23 @@ +{{- if .Values.autoscaling }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.app.name }} + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Values.app.name }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} +{{- end }} From f0183e6e4fc29676b4df0297a36088c4adaa8ea2 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:15:39 +0300 Subject: [PATCH 14/16] Update README.md --- src/internal-docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md index 03579de3bc..728d85dceb 100644 --- a/src/internal-docs/README.md +++ b/src/internal-docs/README.md @@ -95,4 +95,4 @@ We encourage all engineers to actively contribute to Mariana Deep. If you see so - **Public Access**: Explicitly disabled (`APP_PUBLIC=false`). Unauthenticated users cannot view any pages and will be immediately redirected to the login screen. - **User Management**: Open registration is disabled. Administrators manually provision access. -- **Data Persistence**: In Kubernetes, Persistent Volume Claims (PVCs) ensure uploaded images and database state survive pod restarts. Locally, data is stored in the git-ignored `./config` and `./db_data` folders. +- **Data Persistence**: In Kubernetes, Persistent Volume Claims (PVCs) ensure uploaded images and database state survive pod restarts. Locally, BookStack configuration and uploads are stored in the bind-mounted `./config` directory, while database data persists in the Docker-managed `bookstack_db_data` volume. From 991cee8a99c8ae268aeed305dee03b64831d0728 Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 10:16:33 +0300 Subject: [PATCH 15/16] Update README.md --- src/internal-docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md index 728d85dceb..284f8027a0 100644 --- a/src/internal-docs/README.md +++ b/src/internal-docs/README.md @@ -33,6 +33,7 @@ To spin up the documentation platform locally for testing or local development: ``` 3. **Access the Application** + Wait approximately 20 seconds for database migrations to complete. Open your browser and navigate to `http://localhost:6875`. *(Default credentials on first run: `admin@admin.com` / `password`)* From 66165aae72ed842a8db7972432f76f9afdb0805b Mon Sep 17 00:00:00 2001 From: Codebmk Date: Sat, 6 Jun 2026 11:46:58 +0300 Subject: [PATCH 16/16] Move sensitive env to Secret; bump chart & docs Introduce a Kubernetes Secret for sensitive BookStack environment variables and stop storing secrets in the ConfigMap. Added templates/secret.yaml and removed APP_KEY, DB_PASS, MYSQL_PASSWORD and MYSQL_ROOT_PASSWORD from the ConfigMap; deployments for app and db now load secrets via secretRef. Update MariaDB readiness/liveness checks to use 127.0.0.1 and authenticate with MYSQL_ROOT_PASSWORD. Bumped Helm Chart appVersion and updated docs/.env example to use the newer `docker compose up -d` command. This improves security by requiring secret injection via CI/CD or cluster secrets. --- src/internal-docs/.env.example | 2 +- src/internal-docs/README.md | 2 +- src/internal-docs/k8s/Chart.yaml | 2 +- src/internal-docs/k8s/templates/configmap.yaml | 4 ---- .../k8s/templates/deployment-app.yaml | 2 ++ src/internal-docs/k8s/templates/deployment-db.yaml | 6 ++++-- src/internal-docs/k8s/templates/secret.yaml | 14 ++++++++++++++ 7 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 src/internal-docs/k8s/templates/secret.yaml diff --git a/src/internal-docs/.env.example b/src/internal-docs/.env.example index b1189bc60b..fcadf84287 100644 --- a/src/internal-docs/.env.example +++ b/src/internal-docs/.env.example @@ -1,7 +1,7 @@ # ------------------------------------------------------------------------- # BookStack Environment Configuration # ------------------------------------------------------------------------- -# Copy this file to `.env` before running `docker-compose up -d`. +# Copy this file to `.env` before running `docker compose up -d`. # Do not commit the `.env` file to version control. # ------------------------------------------------------------------------- diff --git a/src/internal-docs/README.md b/src/internal-docs/README.md index 284f8027a0..4b8fa284e6 100644 --- a/src/internal-docs/README.md +++ b/src/internal-docs/README.md @@ -29,7 +29,7 @@ To spin up the documentation platform locally for testing or local development: 2. **Start the Containers** Use Docker Compose to build and start the environment in the background: ```bash - docker-compose up -d + docker compose up -d ``` 3. **Access the Application** diff --git a/src/internal-docs/k8s/Chart.yaml b/src/internal-docs/k8s/Chart.yaml index f06cdc7298..1210342f67 100644 --- a/src/internal-docs/k8s/Chart.yaml +++ b/src/internal-docs/k8s/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: "1.0.0" +appVersion: "24.05.2" description: AirQo Internal Docs (Mariana Deep) Helm Chart name: airqo-internal-docs home: https://airqo.net diff --git a/src/internal-docs/k8s/templates/configmap.yaml b/src/internal-docs/k8s/templates/configmap.yaml index 2592689e9e..ee4e549c61 100644 --- a/src/internal-docs/k8s/templates/configmap.yaml +++ b/src/internal-docs/k8s/templates/configmap.yaml @@ -8,16 +8,12 @@ metadata: data: # BookStack Specific APP_NAME: {{ .Values.env.APP_NAME | quote }} - APP_KEY: {{ .Values.env.APP_KEY | quote }} APP_PUBLIC: {{ .Values.env.APP_PUBLIC | quote }} # Shared Database Configuration (Used by BookStack container) DB_USER: {{ .Values.env.DB_USER | quote }} - DB_PASS: {{ .Values.env.DB_PASSWORD | quote }} DB_DATABASE: {{ .Values.env.DB_DATABASE | quote }} # MariaDB Specific (Used by MariaDB container) MYSQL_USER: {{ .Values.env.DB_USER | quote }} - MYSQL_PASSWORD: {{ .Values.env.DB_PASSWORD | quote }} MYSQL_DATABASE: {{ .Values.env.DB_DATABASE | quote }} - MYSQL_ROOT_PASSWORD: {{ .Values.env.MYSQL_ROOT_PASSWORD | quote }} diff --git a/src/internal-docs/k8s/templates/deployment-app.yaml b/src/internal-docs/k8s/templates/deployment-app.yaml index 9bb0265db5..e41a9f4441 100644 --- a/src/internal-docs/k8s/templates/deployment-app.yaml +++ b/src/internal-docs/k8s/templates/deployment-app.yaml @@ -35,6 +35,8 @@ spec: envFrom: - configMapRef: name: {{ .Values.app.configmap }} + - secretRef: + name: {{ .Values.app.configmap }}-secret volumeMounts: - name: bookstack-config mountPath: /config diff --git a/src/internal-docs/k8s/templates/deployment-db.yaml b/src/internal-docs/k8s/templates/deployment-db.yaml index 786045041d..9060bedd09 100644 --- a/src/internal-docs/k8s/templates/deployment-db.yaml +++ b/src/internal-docs/k8s/templates/deployment-db.yaml @@ -30,6 +30,8 @@ spec: envFrom: - configMapRef: name: {{ .Values.app.configmap }} + - secretRef: + name: {{ .Values.app.configmap }}-secret volumeMounts: - name: mariadb-config mountPath: /var/lib/mysql @@ -38,7 +40,7 @@ spec: command: - sh - -c - - mysqladmin ping -h localhost + - mysqladmin ping -h 127.0.0.1 -uroot -p"$MYSQL_ROOT_PASSWORD" initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 @@ -48,7 +50,7 @@ spec: command: - sh - -c - - mysql -h localhost -e 'SELECT 1' + - mysql -h 127.0.0.1 -uroot -p"$MYSQL_ROOT_PASSWORD" -e 'SELECT 1' initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 3 diff --git a/src/internal-docs/k8s/templates/secret.yaml b/src/internal-docs/k8s/templates/secret.yaml new file mode 100644 index 0000000000..c2e4d895aa --- /dev/null +++ b/src/internal-docs/k8s/templates/secret.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.app.configmap }}-secret + namespace: {{ .Values.app.namespace }} + labels: + {{- include "internal-docs.labels" . | nindent 4 }} +type: Opaque +stringData: + APP_KEY: {{ required "env.APP_KEY must be set (inject via CI/CD/Secrets)" .Values.env.APP_KEY | quote }} + DB_PASS: {{ required "env.DB_PASSWORD must be set" .Values.env.DB_PASSWORD | quote }} + DB_PASSWORD: {{ .Values.env.DB_PASSWORD | quote }} + MYSQL_PASSWORD: {{ .Values.env.DB_PASSWORD | quote }} + MYSQL_ROOT_PASSWORD: {{ required "env.MYSQL_ROOT_PASSWORD must be set" .Values.env.MYSQL_ROOT_PASSWORD | quote }}