Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/helmfile-linter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
shell: bash
run: |
set -e
HELMFILE=src/helm/helmfile.yaml.gotmpl
HELMFILE=deploy/kubernetes/helm/helmfile.yaml.gotmpl
environments=$(awk 'BEGIN {in_env=0} /^environments:/ {in_env=1; next} /^---/ {in_env=0} in_env && /^ [^ ]/ {gsub(/^ /,""); gsub(/:.*$/,""); print}' "$HELMFILE")
for env in $environments; do
echo "################### $env lint ###################"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-helm-chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ run-name: Release Chart
on:
push:
paths:
- src/helm/impress/**
- deploy/kubernetes/helm/impress/**

jobs:
release:
Expand All @@ -20,7 +20,7 @@ jobs:
fetch-depth: 0

- name: Cleanup
run: rm -rf ./src/helm/extra
run: rm -rf ./deploy/kubernetes/helm/extra

- name: Install Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
Expand All @@ -30,5 +30,5 @@ jobs:
- name: Publish Helm charts
uses: numerique-gouv/helm-gh-pages@2cf477ae49d7c70037ceb1685803f4f7bad9b981 # add-overwrite-option
with:
charts_dir: ./src/helm
charts_dir: ./deploy/kubernetes/helm
token: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ and this project adheres to

## [Unreleased]

- ♻️ (deploy) harmonize prod deployment layout under deploy/ #2425

### Added

- ✨(frontend) add top parent on sub docs search #1952
Expand Down
2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
web: bin/buildpack_start.sh
web: deploy/paas/buildpack_start.sh
postdeploy: python manage.py migrate
2 changes: 1 addition & 1 deletion bin/Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ k8s_resource('impress-docs-backend-migrate', resource_deps=['dev-backend-postgre
k8s_resource('impress-docs-backend-createsuperuser', resource_deps=['impress-docs-backend-migrate'])
k8s_resource('dev-backend-keycloak', resource_deps=['dev-backend-keycloak-pg'])
k8s_resource('impress-docs-backend', resource_deps=['impress-docs-backend-migrate', 'dev-backend-redis', 'dev-backend-keycloak', 'dev-backend-postgres', 'dev-backend-minio:statefulset'])
k8s_yaml(local('cd ../src/helm && helmfile -n impress -e dev template .'))
k8s_yaml(local('cd ../deploy/kubernetes/helm && helmfile -n impress -e dev template .'))

migration = '''
set -eu
Expand Down
43 changes: 43 additions & 0 deletions deploy/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Docs — Docker Compose deployment

Prod-oriented Docker Compose layout for [Docs](https://github.com/suitenumerique/docs).

> The root `compose.yml` of the repository is the **development** stack. Use the files in this folder to deploy Docs in production.

## Layout

```
deploy/docker/
├── compose.yml # Main production compose file
├── env.d/ # (you provide) postgres / backend / yprovider / common env files
└── examples/
├── keycloak/ # Sample OIDC provider
├── minio/ # Sample S3-compatible object storage
└── nginx-proxy/ # Sample reverse proxy with Let's Encrypt
```

## Getting started

See the [installation walkthrough](../../docs/installation/compose.md) — it covers env files, OIDC, S3, Postgres, Redis, mail and reverse-proxy setup end to end.

Quick setup:

```bash
mkdir -p docs/env.d && cd docs

# Fetch the compose file and example env files
curl -o compose.yml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/compose.yml
curl -o env.d/common https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/common
curl -o env.d/backend https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/backend
curl -o env.d/yprovider https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/yprovider
curl -o env.d/postgresql https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/postgresql
Comment on lines +25 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

urls=(
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/compose.yml"
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/common"
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/backend"
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/yprovider"
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/postgresql"
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/keycloak/compose.yaml"
  "https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/minio/compose.yaml"
)

for url in "${urls[@]}"; do
  code="$(curl -sS -L -o /dev/null -w '%{http_code}' "$url")"
  printf '%s -> %s\n' "$url" "$code"
done

Repository: suitenumerique/docs

Length of output: 839


Fix broken compose download URLs (404s).

In deploy/docker/README.md (lines 25-33), the raw.githubusercontent.com/.../refs/heads/main/... URL format works for env.d/production.dist/* (200), but the compose files return 404, so the bootstrap will fail:

  • deploy/docker/compose.yml -> 404
  • deploy/docker/examples/keycloak/compose.yaml -> 404
  • deploy/docker/examples/minio/compose.yaml -> 404

Update the paths/filenames (or branch) for those compose artifacts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/docker/README.md` around lines 25 - 33, The README's curl targets for
the compose files are pointing to nonexistent URLs causing 404s; update the curl
lines that fetch "compose.yml" and the example compose files so they reference
the actual raw file locations and correct filenames/branch (replace the broken
refs/heads/main paths and/or ".yml" names with the real
raw.githubusercontent.com paths and correct filenames like compose.yaml for the
main compose and the examples/keycloak/compose.yaml and
examples/minio/compose.yaml), verify each URL returns 200 and commit the
corrected README.md.


# Pin to a tagged release before going to production
docker compose up -d
docker compose run --rm backend python manage.py migrate
```

## Other deployments

* Kubernetes/Helm: see [`deploy/kubernetes/`](../kubernetes/).
* PaaS (Scalingo, Clever Cloud, …): see [`deploy/paas/`](../paas/).
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

```bash
mkdir keycloak
curl -o keycloak/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docs/examples/compose/keycloak/compose.yaml
curl -o keycloak/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/keycloak/compose.yaml
curl -o keycloak/env.d/kc_postgresql https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/kc_postgresql
curl -o keycloak/env.d/keycloak https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/keycloak
Comment on lines 10 to 14

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Create keycloak/env.d before downloading the env files.

Step 1 only creates keycloak/, but Lines 13-14 write into keycloak/env.d/. On a clean machine those curl -o commands fail because the parent directory does not exist.

Suggested change
-mkdir keycloak
+mkdir -p keycloak/env.d
 curl -o keycloak/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/keycloak/compose.yaml
 curl -o keycloak/env.d/kc_postgresql https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/kc_postgresql
 curl -o keycloak/env.d/keycloak https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/keycloak
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
mkdir keycloak
curl -o keycloak/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docs/examples/compose/keycloak/compose.yaml
curl -o keycloak/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/keycloak/compose.yaml
curl -o keycloak/env.d/kc_postgresql https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/kc_postgresql
curl -o keycloak/env.d/keycloak https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/keycloak
mkdir -p keycloak/env.d
curl -o keycloak/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/keycloak/compose.yaml
curl -o keycloak/env.d/kc_postgresql https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/kc_postgresql
curl -o keycloak/env.d/keycloak https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/keycloak
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/docker/examples/keycloak/README.md` around lines 10 - 14, Update the
README snippet so the env.d directory exists before the curl commands: replace
or augment the existing "mkdir keycloak" step so it creates "keycloak/env.d"
(e.g., use a single command that creates parent and env.d) so the subsequent
curl lines that write to "keycloak/env.d/kc_postgresql" and
"keycloak/env.d/keycloak" will not fail on a clean machine.

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

```bash
mkdir minio
curl -o minio/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docs/examples/compose/minio/compose.yaml
curl -o minio/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/minio/compose.yaml
```

### Step 2:. Update compose file with your own values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Acme-companion is a lightweight companion container for nginx-proxy. It handles

```bash
mkdir nginx-proxy
curl -o nginx-proxy/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docs/examples/compose/nginx-proxy/compose.yaml
curl -o nginx-proxy/compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/examples/nginx-proxy/compose.yaml
```

### Step 2: Edit `DEFAULT_EMAIL` in the compose file.
Expand Down
File renamed without changes.
File renamed without changes.
31 changes: 31 additions & 0 deletions deploy/paas/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Docs — PaaS deployment

Buildpack scripts and nginx template for deploying [Docs](https://github.com/suitenumerique/docs) on a PaaS (Scalingo, Clever Cloud, …).

## Layout

```
deploy/paas/
├── buildpack_postcompile.sh # Build-time: cleanup unused files to reduce slug size
├── buildpack_postfrontend.sh # Build-time: assemble frontend/backend/nginx into slug
├── buildpack_start.sh # Runtime: starts uvicorn + y-provider + nginx
└── servers.conf.erb # Nginx routing template (ERB → consumed by buildpack)
```
Comment on lines +7 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the layout fence.

The bare fenced block trips markdownlint (MD040). text is enough here.

Suggested fix
-```
+```text
 deploy/paas/
 ├── buildpack_postcompile.sh   # Build-time: cleanup unused files to reduce slug size
 ├── buildpack_postfrontend.sh  # Build-time: assemble frontend/backend/nginx into slug
 ├── buildpack_start.sh         # Runtime: starts uvicorn + y-provider + nginx
 └── servers.conf.erb           # Nginx routing template (ERB → consumed by buildpack)
-```
+```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 7-7: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/paas/README.md` around lines 7 - 13, The fenced code block listing the
directory contents lacks a language tag and triggers MD040; update the README
fenced block that contains the lines starting with "deploy/paas/" and the
filenames (e.g., buildpack_postcompile.sh, buildpack_postfrontend.sh,
buildpack_start.sh, servers.conf.erb) by adding the language tag "text"
immediately after the opening triple backticks (i.e., replace ``` with ```text)
and keep the closing triple backticks unchanged.

Source: Linters/SAST tools


The root `Procfile` references `deploy/paas/buildpack_start.sh` for the `web` process.

## Getting started

See the [Scalingo walkthrough](../../docs/installation/scalingo.md) — it covers the full env-var setup (buildpack URL, OIDC, S3, theme customization, etc.).

The two build-time hooks are wired via the [La Suite buildpack](https://github.com/suitenumerique/buildpack) env vars:

```bash
scalingo env-set LASUITE_SCRIPT_POSTCOMPILE="deploy/paas/buildpack_postcompile.sh"
scalingo env-set LASUITE_SCRIPT_POSTFRONTEND="deploy/paas/buildpack_postfrontend.sh"
```

## Other deployments

* Docker Compose: see [`deploy/docker/`](../docker/).
* Kubernetes/Helm: see [`deploy/kubernetes/`](../kubernetes/).
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ if [ -n "$THEME_CUSTOMIZATION_LOGO_URL" ]; then
fi

mv src/backend/* ./
mv deploy/paas/* ./
mv deploy/paas/servers.conf.erb ./

# Inject custom theme JSON
if [ -n "$THEME_CUSTOMIZATION_JSON" ]; then
Expand Down
File renamed without changes.
32 changes: 28 additions & 4 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,28 @@ Then, set the `FRONTEND_JS_URL` environment variable to the URL of your custom J

----

## **Providing theme customization** ⚙️

The theme customization configuration can be provided in two ways. Pick the one that fits your deployment:

* **Inline JSON via env var (recommended for PaaS / Docker / Kubernetes)** — set `THEME_CUSTOMIZATION_JSON` to the JSON string itself. No file mount required.

```shellscript
THEME_CUSTOMIZATION_JSON='{"header":{"icon":"https://..."}}'
```

* **Mounted JSON file** — set `THEME_CUSTOMIZATION_FILE_PATH` to the absolute path of a JSON file inside the container.

```shellscript
THEME_CUSTOMIZATION_FILE_PATH=<path>
```

When both are set, `THEME_CUSTOMIZATION_JSON` is prioritized.

The sections below describe the schema. Each example links to the reference JSON at `deploy/kubernetes/helm/env.d/dev/configuration/theme/demo.json`.

----

## **Your Docs icon** 📝

You can add your own Docs icon in the header from the theme customization file.
Expand All @@ -97,11 +119,13 @@ You can add your own Docs icon in the header from the theme customization file.

```shellscript
THEME_CUSTOMIZATION_FILE_PATH=<path>
# or
THEME_CUSTOMIZATION_JSON=<inline JSON>
```

### Example of JSON

You can activate it with the `header.icon` configuration: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
You can activate it with the `header.icon` configuration: https://github.com/suitenumerique/docs/blob/main/deploy/kubernetes/helm/env.d/dev/configuration/theme/demo.json

This configuration is optional. If not set, the default icon will be used.

Expand All @@ -119,7 +143,7 @@ THEME_CUSTOMIZATION_FILE_PATH=<path>

### Example of JSON

The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/deploy/kubernetes/helm/env.d/dev/configuration/theme/demo.json

`footer.default` is the fallback if the language is not supported.

Expand All @@ -142,7 +166,7 @@ THEME_CUSTOMIZATION_FILE_PATH=<path>

### Example of JSON

The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/deploy/kubernetes/helm/env.d/dev/configuration/theme/demo.json

----

Expand All @@ -168,7 +192,7 @@ See: [LaGaufreV2Props](https://github.com/suitenumerique/ui-kit/blob/main/src/co

### Complete Example

From the theme customization file: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
From the theme customization file: https://github.com/suitenumerique/docs/blob/main/deploy/kubernetes/helm/env.d/dev/configuration/theme/demo.json

### Behavior

Expand Down
1 change: 1 addition & 0 deletions docs/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ These are the environment variables you can set for the `impress-backend` contai
| STORAGES_STATICFILES_BACKEND | | whitenoise.storage.CompressedManifestStaticFilesStorage |
| THEME_CUSTOMIZATION_CACHE_TIMEOUT | Cache duration for the customization settings | 86400 |
| THEME_CUSTOMIZATION_FILE_PATH | Full path to the file customizing the theme. An example is provided in src/backend/impress/configuration/theme/default.json | BASE_DIR/impress/configuration/theme/default.json |
| THEME_CUSTOMIZATION_JSON | Inline JSON string customizing the theme. Takes precedence over `THEME_CUSTOMIZATION_FILE_PATH` when set. Convenient for PaaS / Docker / Kubernetes deployments. | |
| TRASHBIN_CUTOFF_DAYS | Trashbin cutoff | 30 |
| TREEBEARD_PATH_COMPUTE_RETRY_MAX_ATTEMPTS | Number of attempts to create a document before failing. | 10 |
| USER_OIDC_ESSENTIAL_CLAIMS | Essential claims in OIDC token | [] |
Expand Down
18 changes: 9 additions & 9 deletions docs/installation/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ We provide a sample configuration for running Docs using Docker Compose. Please

- A modern version of Docker and its Compose plugin.
- A domain name and DNS configured to your server.
- An Identity Provider that supports OpenID Connect protocol - we provide [an example to deploy Keycloak](../examples/compose/keycloak/README.md).
- An Object Storage that implements S3 API - we provide [an example to deploy Minio](../examples/compose/minio/README.md).
- A Postgresql database - we provide [an example in the compose file](../examples/compose/compose.yaml).
- A Redis database - we provide [an example in the compose file](../examples/compose/compose.yaml).
- An Identity Provider that supports OpenID Connect protocol - we provide [an example to deploy Keycloak](../../deploy/docker/examples/keycloak/README.md).
- An Object Storage that implements S3 API - we provide [an example to deploy Minio](../../deploy/docker/examples/minio/README.md).
- A Postgresql database - we provide [an example in the compose file](../../deploy/docker/compose.yml).
- A Redis database - we provide [an example in the compose file](../../deploy/docker/compose.yml).

## Software Requirements

Expand All @@ -32,7 +32,7 @@ For older versions of Docker Engine that do not include Docker Compose:
```bash
mkdir -p docs/env.d
cd docs
curl -o compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docs/examples/compose/compose.yaml
curl -o compose.yml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/deploy/docker/compose.yml
curl -o env.d/common https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/common
curl -o env.d/backend https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/backend
curl -o env.d/yprovider https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/yprovider
Expand Down Expand Up @@ -61,7 +61,7 @@ In this example, we assume the following services:

Authentication in Docs is managed through Open ID Connect protocol. A functional Identity Provider implementing this protocol is required.

For guidance, refer to our [Keycloak deployment example](../examples/compose/keycloak/README.md).
For guidance, refer to our [Keycloak deployment example](../../deploy/docker/examples/keycloak/README.md).

If using Keycloak as your Identity Provider, set `OIDC_RP_CLIENT_ID` and `OIDC_RP_CLIENT_SECRET` variables with those of the OIDC client created for Docs. By default we have set `docs` as the realm name, if you have named your realm differently, update the value `REALM_NAME` in `env.d/common`

Expand All @@ -71,7 +71,7 @@ For others OIDC providers, update the variables in `env.d/backend`.

Files and media are stored in an Object Store that supports the S3 API.

For guidance, refer to our [Minio deployment example](../examples/compose/minio/README.md).
For guidance, refer to our [Minio deployment example](../../deploy/docker/examples/minio/README.md).

Set `AWS_S3_ACCESS_KEY_ID` and `AWS_S3_SECRET_ACCESS_KEY` with the credentials of a user with `readwrite` access to the bucket created for Docs.

Expand Down Expand Up @@ -147,7 +147,7 @@ AI_MODEL=<model used> e.g. llama

### Frontend theme

You can [customize your Docs instance](../theming.md) with your own theme and custom css.
You can [customize your Docs instance](../customization.md) with your own theme and custom css.

The following environment variables must be set in `env.d/backend`:

Expand All @@ -163,7 +163,7 @@ FRONTEND_CSS_URL=https://storage.yourdomain.tld/themes/custom.css # custom css

If you have your own certificates and proxy setup, you can skip this part.

You can follow our [nginx proxy example](../examples/compose/nginx-proxy/README.md) with automatic generation and renewal of certificate with Let's Encrypt.
You can follow our [nginx proxy example](../../deploy/docker/examples/nginx-proxy/README.md) with automatic generation and renewal of certificate with Let's Encrypt.

You will need to uncomment the environment and network sections in compose file and update it with your values.

Expand Down
10 changes: 5 additions & 5 deletions docs/installation/scalingo.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ scalingo env-set LASUITE_APP_NAME="docs"
scalingo env-set LASUITE_BACKEND_DIR="src/backend/"
scalingo env-set LASUITE_FRONTEND_DIR="src/frontend/"
scalingo env-set LASUITE_NGINX_DIR="."
scalingo env-set LASUITE_SCRIPT_POSTCOMPILE="bin/buildpack_postcompile.sh"
scalingo env-set LASUITE_SCRIPT_POSTFRONTEND="bin/buildpack_postfrontend.sh"
scalingo env-set LASUITE_SCRIPT_POSTCOMPILE="deploy/paas/buildpack_postcompile.sh"
scalingo env-set LASUITE_SCRIPT_POSTFRONTEND="deploy/paas/buildpack_postfrontend.sh"
```

### Database and Cache
Expand Down Expand Up @@ -237,12 +237,12 @@ On Scalingo, the application runs as follows:

1. The buildpack compiles the frontend (Next.js static export)
2. The buildpack compiles the backend (Python dependencies)
3. `bin/buildpack_postcompile.sh` runs to clean up unused files and reduce slug size
4. `bin/buildpack_postfrontend.sh` moves the frontend build to `build/frontend-out`, downloads custom logos, injects the custom theme, and prepares the deployment structure
3. `deploy/paas/buildpack_postcompile.sh` runs to clean up unused files and reduce slug size
4. `deploy/paas/buildpack_postfrontend.sh` moves the frontend build to `build/frontend-out`, downloads custom logos, injects the custom theme, and prepares the deployment structure

### Runtime

The `bin/buildpack_start.sh` script starts three processes:
The `deploy/paas/buildpack_start.sh` script starts three processes:

- **Nginx** serves static files and proxies requests to the backend
- **uvicorn** runs the Django ASGI application on port 8000
Expand Down
2 changes: 1 addition & 1 deletion docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Whenever we are cooking a new release (e.g. `4.18.1`) we should follow a standar

- for backend, update the version number by hand in `pyproject.toml`,
- for each projects (`src/frontend`, `src/frontend/apps/*`, `src/frontend/packages/*`, `src/mail`), run `yarn version --new-version --no-git-tag-version 4.18.1` in their directory. This will update their `package.json` for you,
- for Helm, update Docker image tag in files located at `src/helm/env.d` for both `preprod` and `production` environments:
- for Helm, update Docker image tag in files located at `deploy/kubernetes/helm/env.d` for both `preprod` and `production` environments:

```yaml
image:
Expand Down
19 changes: 19 additions & 0 deletions src/backend/core/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3102,6 +3102,25 @@ def get(self, request):
return drf.response.Response(dict_settings)

def _load_theme_customization(self):
if settings.THEME_CUSTOMIZATION_JSON:
cache_key = "theme_customization_env"
theme_customization = cache.get(cache_key, {})
if theme_customization:
return theme_customization

try:
theme_customization = json.loads(settings.THEME_CUSTOMIZATION_JSON)
except json.JSONDecodeError:
logger.error("THEME_CUSTOMIZATION_JSON is not a valid JSON")
return {}

cache.set(
cache_key,
theme_customization,
settings.THEME_CUSTOMIZATION_CACHE_TIMEOUT,
)
Comment on lines +3106 to +3121

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Cache key does not vary with env value, causing stale theme after config changes.

Line 3106 uses a fixed key (theme_customization_env). With shared Redis, a deployment that changes THEME_CUSTOMIZATION_JSON can still return the previous cached theme until timeout.

💡 Suggested fix
+import hashlib
...
-            cache_key = "theme_customization_env"
+            theme_json = settings.THEME_CUSTOMIZATION_JSON
+            cache_key = f"theme_customization_env_{hashlib.sha256(theme_json.encode()).hexdigest()}"
             theme_customization = cache.get(cache_key, {})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/core/api/viewsets.py` around lines 3106 - 3121, The cache key is
fixed ("theme_customization_env") so different deployments or updates to
settings.THEME_CUSTOMIZATION_JSON can return stale data; update the cache key
used around cache_key and theme_customization to include a unique per-config
identifier (e.g., a hash/digest of settings.THEME_CUSTOMIZATION_JSON or a
deployment/version setting) so the key becomes deterministic per JSON value,
then use that composite key when reading and writing the cache and keep the
existing JSON parsing and error handling (settings.THEME_CUSTOMIZATION_JSON,
settings.THEME_CUSTOMIZATION_CACHE_TIMEOUT, theme_customization).

return theme_customization

Comment on lines +3111 to +3123

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate that THEME_CUSTOMIZATION_JSON decodes to a JSON object.

At Line 3112, json.loads accepts scalar/array JSON too. That can return a non-dict payload in theme_customization, breaking the response contract expected by consumers.

💡 Suggested fix
             try:
                 theme_customization = json.loads(settings.THEME_CUSTOMIZATION_JSON)
             except json.JSONDecodeError:
                 logger.error("THEME_CUSTOMIZATION_JSON is not a valid JSON")
                 return {}
+            if not isinstance(theme_customization, dict):
+                logger.error("THEME_CUSTOMIZATION_JSON must decode to a JSON object")
+                return {}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
theme_customization = json.loads(settings.THEME_CUSTOMIZATION_JSON)
except json.JSONDecodeError:
logger.error("THEME_CUSTOMIZATION_JSON is not a valid JSON")
return {}
cache.set(
cache_key,
theme_customization,
settings.THEME_CUSTOMIZATION_CACHE_TIMEOUT,
)
return theme_customization
try:
theme_customization = json.loads(settings.THEME_CUSTOMIZATION_JSON)
except json.JSONDecodeError:
logger.error("THEME_CUSTOMIZATION_JSON is not a valid JSON")
return {}
if not isinstance(theme_customization, dict):
logger.error("THEME_CUSTOMIZATION_JSON must decode to a JSON object")
return {}
cache.set(
cache_key,
theme_customization,
settings.THEME_CUSTOMIZATION_CACHE_TIMEOUT,
)
return theme_customization
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/core/api/viewsets.py` around lines 3111 - 3123, After
json.loads(settings.THEME_CUSTOMIZATION_JSON) succeeds, validate that the
resulting theme_customization is a dict (JSON object) before using or caching
it; if it's not a dict, log an error (including the unexpected type), return {}
and do not call cache.set with the invalid payload. Update the block around
theme_customization, json.loads, cache.set and cache_key to perform this type
check and early return.

if not settings.THEME_CUSTOMIZATION_FILE_PATH:
return {}

Expand Down
Loading
Loading