diff --git a/.gitignore b/.gitignore
index 26ae07d..f491b79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,3 +71,6 @@ venv.bak/
# Poetry
poetry.lock
+
+# Logs
+logs/
\ No newline at end of file
diff --git a/README.md b/README.md
index c514d67..54b6444 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[English](#english) | [Français](#français)
-
+
## 🏆 FossBadge - Open Badge Platform
FossBadge is a free and open source platform for creating, managing, and sharing digital badges. It allows organizations to recognize skills and achievements through a simple, accessible interface.
@@ -66,6 +66,15 @@ Run the tests :
uv run python manage.py test
```
+### Launch in production
+1. Set `Debug` to `False` in `fossbadge/settings.py`.
+2. Install [docker](https://docs.docker.com/engine/install/)
+3. Create à `.env` file : `$ cp env_exemple .env` and edit its values
+4. Create a network in docker : `$ docker network create frontend`
+5. Run the docker compose : `$ docker compose -f docker-compose-prod.yml up`
+
+After that, nginx will run on port 80.
+
### 📁 Project Structure
- `core/`: Main application with views, models, and templates
@@ -84,7 +93,7 @@ This project is licensed under the AGPLv3 License - see the LICENSE file for det
---
-
+
## 🏆 FossBadge - Plateforme de Badges Ouverts
FossBadge est une plateforme libre et open source pour créer, gérer et partager des badges numériques. Elle permet aux organisations de reconnaître les compétences et les réalisations à travers une interface simple et accessible.
@@ -148,6 +157,16 @@ Lancer les tests :
uv run python manage.py test
```
+
+### Lancer en production
+1. Mettre `Debug` à `False` dans `fossbadge/settings.py`.
+2. Installer [docker](https://docs.docker.com/engine/install/)
+3. Créer un fichier `.env` : `$ cp env_exemple .env` et éditer ses valeurs
+4. Créer un réseau dans docker : `$ docker network create frontend`
+5. Lancer le docker compose : `$ docker compose -f docker-compose-prod.yml up`
+
+Après ça, nginx tournera sur le port 80.
+
### 📁 Structure du Projet
- `core/` : Application principale avec les vues, modèles et templates
diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml
new file mode 100644
index 0000000..66b6c4f
--- /dev/null
+++ b/docker-compose-prod.yml
@@ -0,0 +1,66 @@
+services:
+ fossbadge_django:
+ build: .
+ container_name: fossbadge_django
+ hostname: fossbadge_django
+ restart: always
+ env_file: .env
+ user: fossbadge
+ volumes:
+ - ./ssh:/home/fossbadge/.ssh
+ - ./:/home/fossbadge/FossBadge
+ - static_volume:/home/fossbadge/FossBadge/staticfiles
+ depends_on:
+ - postgres
+ command: "bash start.sh"
+ networks:
+ - fossbadge_backend
+
+ postgres:
+ image: postgres
+ restart: always
+ container_name: postgres
+ hostname: postgres
+ ports:
+ - "5432:5432"
+ env_file:
+ - .env
+ environment:
+ - "POSTGRES_HOST_AUTH_METHOD=trust"
+ networks:
+ - fossbadge_backend
+
+ fossbadge_nginx:
+ image: nginx
+ restart: always
+ ports:
+ - 80:80
+ container_name: fossbadge_nginx
+ hostname: fossbadge_nginx
+ volumes:
+ - ./media:/www/media
+ - static_volume:/www/static
+ - ./logs:/logs
+ - ./nginx:/etc/nginx/conf.d
+ depends_on:
+ - fossbadge_django
+ links:
+ - fossbadge_django:fossbadge_django
+ labels:
+ - traefik.enable=true
+ - traefik.docker.network=frontend
+ - traefik.http.routers.fossbadge_nginx.tls.certresolver=myresolver
+ - traefik.http.routers.fossbadge_nginx.rule=Host(`$DOMAIN`)
+ - traefik.http.services.fossbadge_nginx.loadbalancer.server.port=80
+ - traefik.http.routers.fossbadge_nginx.middlewares=crowdsec@file
+ networks:
+ - frontend
+ - fossbadge_backend
+
+volumes:
+ static_volume:
+
+networks:
+ frontend:
+ external: true
+ fossbadge_backend:
\ No newline at end of file
diff --git a/env_exemple b/env_exemple
new file mode 100644
index 0000000..0b11d2f
--- /dev/null
+++ b/env_exemple
@@ -0,0 +1,6 @@
+DOMAIN="" # your domain
+
+# POSTGRES settings
+POSTGRES_USER=
+POSTGRES_DBNAME=
+POSTGRES_PASSWORD=
\ No newline at end of file
diff --git a/fossbadge/settings.py b/fossbadge/settings.py
index e85cb95..81ed17e 100644
--- a/fossbadge/settings.py
+++ b/fossbadge/settings.py
@@ -11,7 +11,7 @@
"""
from pathlib import Path
-
+import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -105,13 +105,25 @@
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': BASE_DIR / 'db.sqlite3',
- }
-}
+if DEBUG:
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': BASE_DIR / 'db.sqlite3',
+ },
+ }
+else:
+ DATABASES = {
+ 'default': {
+ "ENGINE": "django.db.backends.postgresql",
+ "NAME": os.getenv("POSTGRES_DBNAME"),
+ "USER": os.getenv("POSTGRES_USER"),
+ "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
+ "HOST": "postgres",
+ "PORT": 5432
+ }
+ }
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
diff --git a/pyproject.toml b/pyproject.toml
index 9f58338..7f6c137 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,6 +15,7 @@ dependencies = [
"django-cleanup (>=9.0.0,<10.0.0)",
"gunicorn (>=23.0.0,<24.0.0)",
"beautifulsoup4>=4.14.3",
+ "psycopg[binary]>=3.3.2",
"sweetify>=2.3.1",
]
diff --git a/start.sh b/start.sh
index cd01d00..1ecdcf6 100644
--- a/start.sh
+++ b/start.sh
@@ -6,17 +6,14 @@ export PATH="/home/fossbadge/.local/bin:$PATH"
uv sync
echo "UV install ok"
+# Migrate
uv run python3 manage.py migrate
-# Install if no asset created :
-uv run python3 manage.py install
-# New static for nginx ?
+# Add static to nginx
uv run python3 manage.py collectstatic --noinput
echo "Run GUNICORN"
-echo "You should be able to see the Fedow dashbord at :"
-echo "https://$DOMAIN/dashboard/"
-sqlite3 ./database/db.sqlite3 'PRAGMA journal_mode=WAL;'
-sqlite3 ./database/db.sqlite3 'PRAGMA synchronous=normal;'
-uv run gunicorn fossbadge.wsgi --log-level=info --log-file /home/fossbadge/FossBadge/logs/gunicorn.logs -w 3 -b 0.0.0.0:8000
+echo "You should be able to see the fossbadge home at :"
+echo "https://$DOMAIN/"
+uv run gunicorn fossbadge.wsgi --log-level=info --log-file /home/fossbadge/FossBadge/logs/gunicorn.logs -w 3 -b 0.0.0.0:8000
\ No newline at end of file
diff --git a/start_dev.sh b/start_dev.sh
index 8be481a..60aee66 100644
--- a/start_dev.sh
+++ b/start_dev.sh
@@ -15,6 +15,8 @@ echo "UV install ok"
sqlite3 ./db.sqlite3 'PRAGMA journal_mode=WAL;'
sqlite3 ./db.sqlite3 'PRAGMA synchronous=normal;'
+uv run python manage.py migrate
+
if [[ "$GUNICORN" == "1" ]]; then
echo "→ Gunicorn activé, démarrage…"
uv run python3 manage.py collectstatic --noinput
diff --git a/uv.lock b/uv.lock
index b558210..c3edb46 100644
--- a/uv.lock
+++ b/uv.lock
@@ -146,6 +146,7 @@ dependencies = [
{ name = "djangorestframework" },
{ name = "gunicorn" },
{ name = "pillow" },
+ { name = "psycopg", extra = ["binary"] },
{ name = "sweetify" },
]
@@ -166,6 +167,7 @@ requires-dist = [
{ name = "djangorestframework", specifier = ">=3.16,<4.0.0" },
{ name = "gunicorn", specifier = ">=23.0.0,<24.0.0" },
{ name = "pillow", specifier = ">=10" },
+ { name = "psycopg", extras = ["binary"], specifier = ">=3.3.2" },
{ name = "sweetify", specifier = ">=2.3.1" },
]
@@ -363,6 +365,41 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
]
+[[package]]
+name = "psycopg"
+version = "3.3.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e0/1a/7d9ef4fdc13ef7f15b934c393edc97a35c281bb7d3c3329fbfcbe915a7c2/psycopg-3.3.2.tar.gz", hash = "sha256:707a67975ee214d200511177a6a80e56e654754c9afca06a7194ea6bbfde9ca7", size = 165630, upload-time = "2025-12-06T17:34:53.899Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8c/51/2779ccdf9305981a06b21a6b27e8547c948d85c41c76ff434192784a4c93/psycopg-3.3.2-py3-none-any.whl", hash = "sha256:3e94bc5f4690247d734599af56e51bae8e0db8e4311ea413f801fef82b14a99b", size = 212774, upload-time = "2025-12-06T17:31:41.414Z" },
+]
+
+[package.optional-dependencies]
+binary = [
+ { name = "psycopg-binary", marker = "implementation_name != 'pypy'" },
+]
+
+[[package]]
+name = "psycopg-binary"
+version = "3.3.2"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/75/ad18c0b97b852aba286d06befb398cc6d383e9dfd0a518369af275a5a526/psycopg_binary-3.3.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9ca24062cd9b2270e4d77576042e9cc2b1d543f09da5aba1f1a3d016cea28390", size = 4596371, upload-time = "2025-12-06T17:34:18.007Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/79/91649d94c8d89f84af5da7c9d474bfba35b08eb8f492ca3422b08f0a6427/psycopg_binary-3.3.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c749770da0947bc972e512f35366dd4950c0e34afad89e60b9787a37e97cb443", size = 4675139, upload-time = "2025-12-06T17:34:21.374Z" },
+ { url = "https://files.pythonhosted.org/packages/56/ac/b26e004880f054549ec9396594e1ffe435810b0673e428e619ed722e4244/psycopg_binary-3.3.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:03b7cd73fb8c45d272a34ae7249713e32492891492681e3cf11dff9531cf37e9", size = 5456120, upload-time = "2025-12-06T17:34:25.102Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8d/410681dccd6f2999fb115cc248521ec50dd2b0aba66ae8de7e81efdebbee/psycopg_binary-3.3.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:43b130e3b6edcb5ee856c7167ccb8561b473308c870ed83978ae478613764f1c", size = 5133484, upload-time = "2025-12-06T17:34:28.933Z" },
+ { url = "https://files.pythonhosted.org/packages/66/30/ebbab99ea2cfa099d7b11b742ce13415d44f800555bfa4ad2911dc645b71/psycopg_binary-3.3.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c1feba5a8c617922321aef945865334e468337b8fc5c73074f5e63143013b5a", size = 6731818, upload-time = "2025-12-06T17:34:33.094Z" },
+ { url = "https://files.pythonhosted.org/packages/70/02/d260646253b7ad805d60e0de47f9b811d6544078452579466a098598b6f4/psycopg_binary-3.3.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cabb2a554d9a0a6bf84037d86ca91782f087dfff2a61298d0b00c19c0bc43f6d", size = 4983859, upload-time = "2025-12-06T17:34:36.457Z" },
+ { url = "https://files.pythonhosted.org/packages/72/8d/e778d7bad1a7910aa36281f092bd85c5702f508fd9bb0ea2020ffbb6585c/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74bc306c4b4df35b09bc8cecf806b271e1c5d708f7900145e4e54a2e5dedfed0", size = 4516388, upload-time = "2025-12-06T17:34:40.129Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/f1/64e82098722e2ab3521797584caf515284be09c1e08a872551b6edbb0074/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d79b0093f0fbf7a962d6a46ae292dc056c65d16a8ee9361f3cfbafd4c197ab14", size = 4192382, upload-time = "2025-12-06T17:34:43.279Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/d0/c20f4e668e89494972e551c31be2a0016e3f50d552d7ae9ac07086407599/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1586e220be05547c77afc326741dd41cc7fba38a81f9931f616ae98865439678", size = 3928660, upload-time = "2025-12-06T17:34:46.757Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/e1/99746c171de22539fd5eb1c9ca21dc805b54cfae502d7451d237d1dbc349/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:458696a5fa5dad5b6fb5d5862c22454434ce4fe1cf66ca6c0de5f904cbc1ae3e", size = 4239169, upload-time = "2025-12-06T17:34:49.751Z" },
+ { url = "https://files.pythonhosted.org/packages/72/f7/212343c1c9cfac35fd943c527af85e9091d633176e2a407a0797856ff7b9/psycopg_binary-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:04bb2de4ba69d6f8395b446ede795e8884c040ec71d01dd07ac2b2d18d4153d1", size = 3642122, upload-time = "2025-12-06T17:34:52.506Z" },
+]
+
[[package]]
name = "ptyprocess"
version = "0.7.0"