try to implement the global containerization

This commit is contained in:
Giovanni committed 2026-10-03 18:42:21 +02:00
1 parent e2b471312c
commit ed38086d09
24 files changed
+966

No files matched your search

Executable
+34
View File
@@ -0,0 +1,34 @@
BACKEND_GIT_REPO=
FRONTEND_GIT_REPO=
BACKEND_GIT_BRANCH=
FRONTEND_GIT_BRANCH=
GIT_TOKEN=
DB_CONNECTION=
DB_HOST=
DB_PORT=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
DB_ROOT_PASSWORD=
TYPESENSE_API_KEY=
#Mettre à 1 quand vous êtes en développement et à rien en production
DEV=
FORCE_CLONE=false
USER_ID=1000
GROUP_ID=1000
VITE_API_URL=http://localhost:80
VITE_BROADCASTER=reverb
VITE_REVERB_KEY=local
VITE_REVERB_HOST=127.0.0.1
VITE_REVERB_PORT=8080
VITE_FORCE_TLS=false
VITE_DISABLE_STATS=true
VITE_ENCRYPTED=false
VITE_CLUSTER=mt1
VITE_ENABLED_TRANSPORTS=['ws','wss']
Executable
+4
View File
@@ -0,0 +1,4 @@
.idea
.env
backups/
app-code/
Executable
+209
View File
@@ -0,0 +1,209 @@
# Gestion des bénévoles - Comité des fêtes de Beaupont
## Présentation du projet
L'association organise régulièrement des événements et projets mobilisant des bénévoles, mais sa coordination interne est rendue difficile par l'usage d'outils dispersés, et non communicants.
La création d'une plateforme web unique vise donc à centraliser et simplifier la gestion des utilisateurs, des rôles, des événements, des tâches et de la communication. Elle vise à améliorer la collaboration entre tous les bénévoles de l'association.
## Objectifs de l’application
L’application a pour objectifs principaux de :
- Gérer les utilisateurs et leurs rôles au sein de l’association.
- Organiser et planifier les événements et les tâches associées.
- Permettre aux bénévoles de s’inscrire en ligne aux événements et aux tâches.
- Offrir aux responsables un tableau de bord pour suivre la participation et les besoins en ressources humaines.
- Centraliser les informations et la communication autour des projets associatifs.
## Prérequis
Comme notre architecture se base sur l'utilisation de Docker, les seules prérequis pour la machine sur laquelle vous souhaitez installer cette application sont :
- [Docker](https://www.docker.com/)
- [Git](https://git-scm.com/)
## Installation
Pour installer ce projet il vous suffit de cloner le dépôt avec la commande suivante :
```bash
git clone <adresse du dépôt>
```
## Initialisation du projet
### 1. Configuration du fichier `.env` principal
1. Créez un fichier `.env` à la racine du projet.
2. Copiez le contenu du fichier `.env.example` dans le fichier `.env`.
3. Renseignez les variables suivantes :
| Variable | Description |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BACKEND_GIT_REPO` | URL HTTPS du dépôt backend sans le préfixe `https://` (ex : `gitlab.com/user/repo-backend.git`) |
| `FRONTEND_GIT_REPO` | URL HTTPS du dépôt frontend sans le préfixe `https://` |
| `BACKEND_GIT_BRANCH` | Branche de votre dépôt backend à utiliser (ex : `main`, `dev`) |
| `FRONTEND_GIT_BRANCH` | Branche de votre dépôt frontend à utiliser |
| `GIT_TOKEN` | Token GitLab à générer depuis *Préférences → User settings → Personal access tokens* <br>Permissions requises :<br>- `read_repository` (obligatoire)<br>- `write_repository` (optionnel, uniquement en développement) |
| `DB_CONNECTION` | Type de base de données utilisée (ex : `mysql`, `mariadb`) |
| `DB_HOST` | Adresse du serveur de base de données (ex : `localhost`, `db`) |
| `DB_PORT` | Port de la base de données (ex : `3306` pour MySQL/MariaDB) |
| `DB_DATABASE` | Nom de la base de données |
| `DB_USERNAME` | Nom d’utilisateur de la base de données |
| `DB_PASSWORD` | Mot de passe de l’utilisateur de la base de données |
| `DB_ROOT_PASSWORD` | Mot de passe du compte root de la base de données |
| `FORCE_CLONE` | Mettre à `true` pour forcer le clonage du dépôt backend même si la branche configurée diffère de la branche actuelle. |
| `DEV` | Mettre `1` en environnement de développement, laisser vide sinon. |
| `VITE_API_URL` | URL du frontend hébergé et exposé par le conteneur Nginx (par défaut sur le port 80) |
### 2. Configuration du fichier `.env` php
Répétez la même opération pour le fichier `docker/php/.env` en copiant depuis `docker/php/.env.example`.
De plus, un utilisateur administrateur est automatiquement créé avec les informations suivantes :
- **Prénom :** `admin`
- **Nom :** `admin`
- **Adresse e-mail :** `admin@mail.com`
- **Mot de passe :** `admin`
- **Numéro de téléphone :** `0909090909`
> Il est bien sûr possible de modifier ces valeurs dans le fichier `docker/php/.env` avant le premier lancement du seeder, en utilisant les variables : `ADMIN_NAME`, `ADMIN_LASTNAME`, `ADMIN_MAIL`, `ADMIN_PASSWORD` et `ADMIN_PHONE_NUMBER`
### 3. Note importante
> ⚠️ Si vous êtes sous **Windows**, assurez-vous que tous les fichiers `.sh` utilisent des fins de ligne **LF** et non **CRLF**, sous peine d’erreurs lors de l’exécution des scripts.
## Lancement
Une fois la configuration terminée :
1. Ouvrez un terminal.
2. Placez-vous à la racine du projet.
3. Exécutez les commandes suivantes dans l'ordre :
```bash
docker compose down -v
```
> Arrête et supprime les conteneurs existants ainsi que les volumes associés.
> Cette étape permet de repartir sur une base propre.
```bash
docker compose up --build -d
```
> Reconstruit les images Docker et démarre l’ensemble des services en arrière-plan.
## Point technique
### 1. Le nommage
Nous avons adopté une convention de nommage en **camelCase** pour les variables, fonctions et fichiers JavaScript côté frontend.
Pour les composants React, nous utilisons la convention **PascalCase** afin de les différencier des éléments HTML.
Côté backend (Laravel), nous respectons les conventions PHP :
- **camelCase** pour les variables et méthodes
- **PascalCase** pour les classes (Controllers, Models, Policies, etc.)
Les noms sont choisis de manière explicite et descriptive afin de faciliter la compréhension du code et sa maintenance.
### 2. Les commentaires
Nous avons fait le choix de limiter l’utilisation des commentaires dans le code. En effet, nous privilégions un code clair, lisible et auto-documenté, notamment grâce à :
- un nommage explicite des variables, fonctions et classes
- l’utilisation du typage lorsque cela est possible
- une structure de projet organisée
- une documentation externe (README, Storybook, Bruno)
Les commentaires sont donc utilisés uniquement lorsque cela apporte une réelle valeur ajoutée, par exemple pour expliquer une logique complexe, un choix technique spécifique ou un comportement non évident.
### 3. La documentation
La documentation du projet est assurée à plusieurs niveaux :
- Un **README** structuré expliquant l’installation, la configuration et le fonctionnement global
- Une documentation des routes API via **Bruno**
- L’utilisation de **Storybook** pour documenter et tester visuellement les composants UI
### 4. La programmation défensive
Nous avons appliqué la programmation défensive afin de rendre notre application plus robuste, sécurisée et fiable face aux erreurs potentielles.
Dans notre projet, cela se traduit notamment par :
- Validation des données côté backend (Laravel) avant utilisation
- Vérification des entrées utilisateur afin d’éviter les données incohérentes ou malveillantes
- Gestion des rôles et permissions pour empêcher l’accès à des ressources non autorisées (utilisation de policies Laravel)
- Gestion des cas d’erreur (ex : utilisateur inexistant, tâche non trouvée, accès interdit) avec des réponses HTTP adaptées
- Utiliser des valeurs par défaut ou des vérifications avant utilisation pour éviter les erreurs inattendues
Enfin, grâce à Docker, nous limitons les problèmes liés à l’environnement (configuration, versions, dépendances), ce qui contribue également à une approche défensive globale du projet.
### 5. La gestion des erreurs
La gestion des erreurs est assurée à plusieurs niveaux :
- Backend Laravel : gestion des exceptions et retour de codes HTTP appropriés (200, 401, 404, 422, etc.)
- Frontend React : gestion des erreurs utilisateur (formulaires, affichage de messages d’erreur)
### 6. Le débogage
Le débogage a été réalisé grâce à plusieurs outils et méthodes :
- Utilisation des outils de développement du navigateur (console, réseau)
- Tests des routes API avec Bruno
- Logs côté docker et backend pour analyser le comportement du serveur
- Par exemple un membre de notre groupe rencontré quelques problèmes lors du lancement des conteneurs docker. Il a donc accédé aux logs du conteneur en question, qui indiquait un problème de clonage du repo git : `unable to access to {url du depot git}` (cela peut être du a un `Personal Access Token` expiré, ou une mauvaise connexion internet)
- Tests manuels réguliers lors du développement
### 7. L'architecture
Nous avons choisi d’adopter une architecture basée sur trois dépôts Git distincts, afin de séparer clairement les responsabilités et de faciliter la maintenance du projet :
- **Dépôt frontend** : contient le code de l’application développée en React
- **Dépôt backend** : contient le code de l’API développée avec Laravel
- **Dépôt Docker** : contient toute la configuration nécessaire à l’installation et au déploiement du projet sur n’importe quelle machine
Ce troisième dépôt permet de déployer l’ensemble de l’application de manière reproductible grâce à Docker, en centralisant la configuration des services.
Notre environnement de déploiement repose sur plusieurs conteneurs Docker :
- **Backend (Laravel)** : gestion de la logique métier et de l’API
- **Frontend (React)** : interface utilisateur (version temporaire pour le déploiement)
- **Base de données (MariaDB)** : stockage des données
- **Nginx** : serveur web utilisé pour exposer les services et gérer les requêtes HTTP
- **Typesense** : moteur de recherche utilisé pour améliorer les performances des recherches
- **Backup** : conteneur dédié à la sauvegarde de la base de données
- **Serveur WebSocket (Laravel Reverb)** : gestion des communications en temps réel
> Un schéma du fonctionnement global de l'application est disponible dans le dossier final de rendus.
### 8. Concepts de programmation
Nous avons appliqué plusieurs concepts de programmation :
- Programmation orientée objet (POO) côté backend (Laravel)
- Composants réutilisables côté frontend (React)
- Gestion d’état via les Contexts React
- API REST pour la communication entre frontend et backend
- Programmation modulaire pour une meilleure organisation du code
Pour améliorer la qualité et la robustesse du code, nous avons migré une partie du projet de JavaScript vers TypeScript.
Cette conversion permet :
- Moins d’erreurs grâce au typage statique.
- Un code plus lisible et documenté avec des interfaces claires.
- Une meilleure collaboration grâce à des types explicites.
Les interfaces TypeScript sont regroupées dans des fichiers dédiés, ce qui centralise les définitions et simplifie les mises à jour.
### 9. Tests unitaires
Nous avons mis en place quelques tests unitaires sur certaines fonctions utilitaires, par exemple :
- `utils/auth/login.test.js`
- `utils/auth/logout.test.js`
Suite à un échange avec notre professeur, il nous a été indiqué qu’un nombre limité de tests suffisait pour démontrer notre compréhension et notre mise en pratique de ce concept. En effet, tester l’ensemble du projet aurait demandé un temps de développement trop important au regard des contraintes du projet.
Nous avons donc choisi de nous concentrer sur quelques cas représentatifs, afin de valider notre approche des tests unitaires tout en respectant les délais impartis.
### 10. Intégration continu
Dans notre projet, l’intégration continue repose sur les outils et pratiques utilisés tout au long du développement.
Nous avons mis en place tous les outils qui permettent à termes l'intégration continu de l'application :
- Utilisation de Git pour gérer les versions du projet et intégrer régulièrement les modifications de chaque membre de l’équipe
- Utilisation de Docker pour garantir un environnement de développement et de déploiement identique et reproductible
- Tests réguliers des fonctionnalités à chaque ajout de code (tests manuels et tests API avec Bruno)
- Validation continue du projet, afin de s’assurer qu’une version fonctionnelle reste disponible à tout moment
+137
View File
@@ -0,0 +1,137 @@
services:
mariadb:
image: mariadb:latest
container_name: app-mariadb
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DB_DATABASE}
ports:
- "3306:3306"
volumes:
- dbdata:/var/lib/mysql
restart: unless-stopped
php:
build:
context: ./docker/php
dockerfile: Dockerfile
args:
USER_ID: ${USER_ID:-1000}
GROUP_ID: ${GROUP_ID:-1000}
container_name: app-php
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ./app-code:/var/www/app${DEV:+:delegated}
- ./docker/php/.env:/tmp/app.env:ro
- typesense-data:/typesense-data:ro
environment:
- GIT_TOKEN=${GIT_TOKEN}
- BACKEND_GIT_REPO=${BACKEND_GIT_REPO}
- BACKEND_GIT_BRANCH=${BACKEND_GIT_BRANCH}
- DEV=${DEV}
- DB_CONNECTION=${DB_CONNECTION}
- DB_HOST=${DB_HOST}
- DB_PORT=${DB_PORT}
- DB_DATABASE=${DB_DATABASE}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- VITE_API_URL=${VITE_API_URL}
depends_on:
- mariadb
- typesense
restart: unless-stopped
healthcheck:
test: [ "CMD-SHELL", "test -d /var/www/app/vendor && pidof php-fpm || exit 1" ]
interval: 5s
timeout: 3s
retries: 20
start_period: 120s
frontend:
build:
context: ./docker/frontend
dockerfile: Dockerfile
container_name: app-frontend
environment:
- GIT_TOKEN=${GIT_TOKEN}
- FRONTEND_GIT_REPO=${FRONTEND_GIT_REPO}
- FRONTEND_GIT_BRANCH=${FRONTEND_GIT_BRANCH}
- VITE_API_URL=${VITE_API_URL}
- VITE_BROADCASTER=${VITE_BROADCASTER}
- VITE_REVERB_KEY=${VITE_REVERB_KEY}
- VITE_REVERB_HOST=${VITE_REVERB_HOST}
- VITE_REVERB_PORT=${VITE_REVERB_PORT}
- VITE_FORCE_TLS=${VITE_FORCE_TLS}
- VITE_DISABLE_STATS=${VITE_DISABLE_STATS}
- VITE_ENCRYPTED=${VITE_ENCRYPTED}
- VITE_CLUSTER=${VITE_CLUSTER}
- VITE_ENABLED_TRANSPORTS=${VITE_ENABLED_TRANSPORTS}
volumes:
- ./app-code:/var/www/app${DEV:+:delegated}
depends_on:
php:
condition: service_healthy
restart: "no"
nginx:
image: nginx:alpine
container_name: app-nginx
volumes:
- ./app-code:/var/www/app${DEV:+:delegated}
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "80:80"
depends_on:
php:
condition: service_healthy
frontend:
condition: service_completed_successfully
restart: unless-stopped
typesense:
build:
context: ./docker/typesense
dockerfile: Dockerfile
restart: unless-stopped
volumes:
- typesense-data:/data
backup:
build:
context: ./docker/backup
dockerfile: Dockerfile
container_name: app-backup
environment:
- DB_PASSWORD=${DB_PASSWORD}
- DB_DATABASE=${DB_DATABASE}
- DB_USERNAME=${DB_USERNAME}
volumes:
- ./backups:/backups
restart: unless-stopped
reverb:
build:
context: ./docker/reverb
dockerfile: Dockerfile
container_name: app-reverb
entrypoint: []
command: php artisan reverb:start --host=0.0.0.0 --port=8080
volumes:
- ./app-code:/var/www/app:delegated
ports:
- "8080:8080"
depends_on:
- php
- mariadb
restart: unless-stopped
volumes:
dbdata:
typesense-data:
networks:
default:
ipam:
config:
- subnet: 192.168.200.0/24
+14
View File
@@ -0,0 +1,14 @@
FROM alpine:latest
RUN apk add --no-cache mariadb-client bash dcron
RUN mkdir -p /backups
RUN mkdir -p /etc/periodic/daily
COPY backup_db.sh /etc/periodic/daily/backup_db
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /etc/periodic/daily/backup_db
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
BACKUP_DIR="/backups"
mkdir -p "$BACKUP_DIR"
DAY=$(date +%d)
FILE="$BACKUP_DIR/$DAY.sql"
mysqldump -h mariadb -u "$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" > "$FILE" 2>/dev/null
if [ $? -eq 0 ]; then
echo "[$(date)] Backup $DB_DATABASE sauvegardé dans $FILE" >> "$BACKUP_DIR/backup.log"
else
echo "[$(date)] ERREUR lors du backup de $DB_DATABASE" >> "$BACKUP_DIR/backup.log"
fi
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
crond -f -l 2
+14
View File
@@ -0,0 +1,14 @@
FROM node:20-alpine
WORKDIR /app
RUN apk add --no-cache git bash
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
COPY scripts/wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/entrypoint.sh \
/usr/local/bin/wait-for-it.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["build"]
+38
View File
@@ -0,0 +1,38 @@
#!/bin/sh
set -e
FRONTEND_DIR=/app
APP_DIR=/var/www/app
PUBLIC_DIR="$APP_DIR/public"
GIT_URL="https://oauth2:${GIT_TOKEN}@${FRONTEND_GIT_REPO}"
PHP_HOST="app-php"
PHP_PORT=9000
/usr/local/bin/wait-for-it.sh "$PHP_HOST:$PHP_PORT" -t 300
if [ ! -d "$FRONTEND_DIR/.git" ]; then
git clone -b "${FRONTEND_GIT_BRANCH:-main}" "$GIT_URL" "$FRONTEND_DIR"
else
cd "$FRONTEND_DIR"
git fetch origin
git reset --hard origin/"${FRONTEND_GIT_BRANCH:-main}"
fi
cp "$APP_DIR/public/index.php" "$FRONTEND_DIR/index.php"
cd "$FRONTEND_DIR"
npm ci --prefer-offline --no-audit
npm run build
find "$PUBLIC_DIR" -mindepth 1 \
! -name 'index.php' \
! -name '.htaccess' \
! -name 'storage' \
-delete
cp -r dist/* "$PUBLIC_DIR/"
if [ ! -L "$PUBLIC_DIR/storage" ] || [ ! -e "$PUBLIC_DIR/storage" ]; then
ln -sfn "$APP_DIR/storage/app/public" "$PUBLIC_DIR/storage"
fi
exit 0
+182
View File
@@ -0,0 +1,182 @@
#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available
WAITFORIT_cmdname=${0##*/}
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
else
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
fi
WAITFORIT_start_ts=$(date +%s)
while :
do
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
WAITFORIT_result=$?
else
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
WAITFORIT_result=$?
fi
if [[ $WAITFORIT_result -eq 0 ]]; then
WAITFORIT_end_ts=$(date +%s)
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
break
fi
sleep 1
done
return $WAITFORIT_result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
WAITFORIT_hostport=(${1//:/ })
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
shift 1
;;
--child)
WAITFORIT_CHILD=1
shift 1
;;
-q | --quiet)
WAITFORIT_QUIET=1
shift 1
;;
-s | --strict)
WAITFORIT_STRICT=1
shift 1
;;
-h)
WAITFORIT_HOST="$2"
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
shift 2
;;
--host=*)
WAITFORIT_HOST="${1#*=}"
shift 1
;;
-p)
WAITFORIT_PORT="$2"
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
WAITFORIT_PORT="${1#*=}"
shift 1
;;
-t)
WAITFORIT_TIMEOUT="$2"
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
WAITFORIT_TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
WAITFORIT_CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
echoerr "Error: you need to provide a host and port to test."
usage
fi
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
wait_for
WAITFORIT_RESULT=$?
exit $WAITFORIT_RESULT
else
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
wait_for_wrapper
WAITFORIT_RESULT=$?
else
wait_for
WAITFORIT_RESULT=$?
fi
fi
if [[ $WAITFORIT_CLI != "" ]]; then
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
exit $WAITFORIT_RESULT
fi
exec "${WAITFORIT_CLI[@]}"
else
exit $WAITFORIT_RESULT
fi
+28
View File
@@ -0,0 +1,28 @@
server {
listen 80;
server_name 127.0.0.1;
root /var/www/app/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SERVER_NAME 127.0.0.1;
fastcgi_param HTTPS off;
}
location /app/ {
proxy_pass http://reverb:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}
+81
View File
@@ -0,0 +1,81 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
CORS_PATHS=api/*,sanctum/csrf-cookie,broadcasting/auth
DEV_CORS_ALLOWED_ORIGINS=http://localhost:5173
PROD_CORS_ALLOWED_ORIGINS=http://localhost
SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1,localhost:8000,localhost:5173
ADMIN_NAME=
ADMIN_LASTNAME=
ADMIN_MAIL=
ADMIN_PASSWORD=
ADMIN_PHONE_NUMBER=
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=localhost
SESSION_SECURE_COOKIE=false
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=local
REVERB_APP_KEY=local
REVERB_APP_SECRET=local
REVERB_HOST=reverb
REVERB_PORT=8080
REVERB_SCHEME=http
PUSHER_APP_CLUSTER="mt1"
CACHE_STORE=file
QUEUE_CONNECTION=sync
FILESYSTEM_DISK=local
# CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_SCHEME=null
MAIL_HOST=host.docker.internal
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
TYPESENSE_CONNECTION=typesense
TYPESENSE_API_KEY=
+27
View File
@@ -0,0 +1,27 @@
FROM php:8.4-fpm
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN apt-get update && apt-get install -y \
git unzip libzip-dev libpng-dev libonig-dev gosu \
&& apt-get install -y netcat-openbsd \
&& docker-php-ext-install pdo_mysql zip pcntl
RUN if [ ${USER_ID:-0} -ne 0 ] && [ ${GROUP_ID:-0} -ne 0 ]; then \
groupmod -g ${GROUP_ID} www-data && \
usermod -u ${USER_ID} -g ${GROUP_ID} www-data \
;fi
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
COPY scripts/*.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/*.sh
WORKDIR /var/www/app
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["php-fpm"]
+23
View File
@@ -0,0 +1,23 @@
#!/bin/sh
set -e
. /usr/local/bin/context.sh
. /usr/local/bin/setup_git.sh
. /usr/local/bin/setup_composer.sh
. /usr/local/bin/setup_env.sh
. /usr/local/bin/setup_laravel.sh
echo "[INIT] Starting initialization..."
setup_git
setup_composer
setup_env
/usr/local/bin/wait-mariadb.sh
/usr/local/bin/wait-typesense.sh
setup_laravel
echo "[INIT] Done ✅"
exec "$@"
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
APP_DIR=/var/www/app
IS_DEV=${DEV:-0}
run() {
if [ "$IS_DEV" = 1 ]; then
gosu www-data "$@"
else
"$@"
fi
}
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
setup_composer() {
echo "Installing dependencies..."
mkdir -p /var/www/.composer/cache
chown -R www-data:www-data /var/www/.composer
if [ -f composer.json ]; then
run composer install --no-interaction --prefer-dist
fi
}
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
setup_env() {
echo "Configuring environment..."
cp /tmp/app.env .env
/usr/local/bin/wait-typesense.sh
TYPESENSE_API_KEY=$(cat /typesense-data/api-key)
sed -i "s/^TYPESENSE_API_KEY=.*/TYPESENSE_API_KEY=$TYPESENSE_API_KEY/" .env
echo "DEV=$DEV" >> .env
if [ "$IS_DEV" = 1 ]; then
chown www-data:www-data .env
chmod 664 .env
else
chown www-data:www-data .env
chmod 640 .env
fi
}
+36
View File
@@ -0,0 +1,36 @@
#!/bin/sh
setup_git() {
echo "Setting up Git..."
GIT_URL="https://oauth2:${GIT_TOKEN}@${BACKEND_GIT_REPO}"
BRANCH="${BACKEND_GIT_BRANCH:-main}"
FORCE_CLONE="${FORCE_CLONE:-false}"
git config --global --add safe.directory "$APP_DIR"
if [ ! -d "$APP_DIR/.git" ]; then
echo "Cloning repo..."
git clone -b "$BRANCH" "$GIT_URL" "$APP_DIR"
else
echo "Updating repo..."
cd "$APP_DIR"
CURRENT_BRANCH=$(run git rev-parse --abbrev-ref HEAD)
if [ "$CURRENT_BRANCH" = "$BRANCH" ]; then
run git fetch origin
run git reset --hard origin/"$CURRENT_BRANCH"
else
if [ "$FORCE_CLONE" = "true" ]; then
rm -rf "$APP_DIR"
mkdir -p "$APP_DIR"
git clone -b "$BRANCH" "$GIT_URL" "$APP_DIR"
else
run git fetch origin
run git reset --hard origin/"$BRANCH"
fi
fi
fi
cd "$APP_DIR"
}
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
setup_laravel() {
echo "Setting up Laravel..."
run php artisan key:generate --force
run php artisan config:clear
run php artisan cache:clear
run php artisan migrate --force --seed
if [ "$IS_DEV" = 1 ]; then
chmod -R 775 storage bootstrap/cache
chmod -R 755 public
else
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
fi
run php artisan storage:link
}
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
until nc -z mariadb 3306; do
sleep 2
done
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
while [ ! -f /typesense-data/api-key ]; do
sleep 1
done
+24
View File
@@ -0,0 +1,24 @@
FROM php:8.4-fpm
RUN apt-get update && apt-get install -y \
git \
unzip \
libzip-dev \
libpng-dev \
libonig-dev \
libxml2-dev \
&& docker-php-ext-install \
pdo \
pdo_mysql \
mbstring \
xml \
pcntl \
sockets \
zip \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/app
EXPOSE 8080
+6
View File
@@ -0,0 +1,6 @@
FROM typesense/typesense:29.0
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
set -e
DATA_DIR="/data"
KEY_FILE="$DATA_DIR/api-key"
if [ ! -f "$KEY_FILE" ]; then
tr -dc A-Za-z0-9 </dev/urandom | head -c 32 > "$KEY_FILE"
fi
API_KEY=$(cat "$KEY_FILE")
exec /opt/typesense-server \
--data-dir "$DATA_DIR" \
--api-key "$API_KEY" \
--enable-cors