mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-14 02:38:07 +02:00
Image Docker, CI et docs pour le serveur Rust
Image en trois étapes (frontend Vite, binaire Rust, Debian slim avec FFmpeg), healthcheck /healthz, dépendances npm propres à l'ancien serveur retirées, CI Rust (fmt, clippy, tests) et documentation de la mise à jour au prochain démarrage de la stack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013qMexTfVRaegbPAgsagCAJ
This commit is contained in:
14 files changed
+272
-8270
No files matched your search
@@ -38,3 +38,8 @@ logs
|
||||
|
||||
# Uploads (seront montés comme volume)
|
||||
uploads/*
|
||||
|
||||
# Compilation Rust
|
||||
server/target
|
||||
**/target
|
||||
.claude
|
||||
@@ -6,8 +6,8 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
app:
|
||||
name: Application (TypeScript)
|
||||
frontend:
|
||||
name: Frontend (TypeScript)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -15,13 +15,29 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
# Les dépendances natives (canvas, sharp) et le navigateur Remotion ne
|
||||
# servent pas aux vérifications : on saute leurs scripts d'installation.
|
||||
- run: npm ci --ignore-scripts
|
||||
- run: npm run check
|
||||
- run: npm test
|
||||
- run: npm run build
|
||||
|
||||
server:
|
||||
name: Serveur (Rust)
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: server
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: server
|
||||
- run: cargo fmt --check
|
||||
- run: cargo clippy --locked --all-targets -- -D warnings
|
||||
- run: cargo test --locked
|
||||
|
||||
ffmpeg-service:
|
||||
name: Service vidéo (Python)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -35,3 +35,4 @@ npm-debug.log*
|
||||
Thumbs.db
|
||||
# Rust
|
||||
server/target
|
||||
.claude/worktrees
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
L'application utilise Docker Compose pour orchestrer :
|
||||
- **PostgreSQL 16** : Base de données sur réseau interne
|
||||
- **Social Flow App** : Application Node.js exposée sur le port **4523**
|
||||
- **Social Flow App** : serveur Rust (API + frontend compilé), port interne **5555**
|
||||
- **ffmpeg-api** / **remotion-renderer** : services de traitement vidéo des Reels
|
||||
|
||||
## 🚀 Démarrage rapide
|
||||
|
||||
@@ -203,7 +204,8 @@ La stack se construit depuis les sources : `app` et `ffmpeg-api` ont une section
|
||||
## 📊 Healthchecks
|
||||
|
||||
- **PostgreSQL** : Vérifie que la base est prête avant de démarrer l'app
|
||||
- **Migrations** : Exécutées automatiquement au démarrage (`drizzle-kit push --force`)
|
||||
- **Migrations** : exécutées automatiquement par le serveur à chaque démarrage (idempotentes)
|
||||
- **Application** : `GET /healthz` répond `ok` quand le serveur et la base sont joignables (healthcheck de l'image)
|
||||
|
||||
## 🐛 Dépannage
|
||||
|
||||
@@ -232,23 +234,37 @@ Vérifiez que `DATABASE_URL` dans `.env` correspond aux variables `PGUSER`, `PGP
|
||||
|
||||
## 📦 Volumes Docker
|
||||
|
||||
- `postgres_data` : Données persistantes de PostgreSQL
|
||||
- Mappages locaux :
|
||||
- `./attached_assets` → `/app/attached_assets` (médias uploadés)
|
||||
- `./migrations` → `/app/migrations` (migrations DB)
|
||||
- `postgres_data` : données persistantes de PostgreSQL
|
||||
- `encryption_key` : clé de chiffrement des jetons (`/app/.encryption-key-data`)
|
||||
- `audio_uploads`, `media_uploads`, `logos_uploads`, `stories_uploads` : fichiers téléversés (`/app/uploads/...`)
|
||||
|
||||
## 🔄 Mise à jour de l'application
|
||||
|
||||
L'image `socialflow-app` est construite à partir des sources
|
||||
(`pull_policy: build`) : le prochain démarrage de la stack après un `git pull`
|
||||
applique la nouvelle version.
|
||||
|
||||
```bash
|
||||
# 1. Pull les dernières modifications
|
||||
# 1. Récupérer les dernières modifications
|
||||
git pull
|
||||
|
||||
# 2. Reconstruire l'image
|
||||
docker-compose build
|
||||
# 2. Reconstruire et redémarrer (Portainer : « Update the stack »)
|
||||
docker compose up -d --build
|
||||
|
||||
# 3. Redémarrer
|
||||
docker-compose up -d
|
||||
|
||||
# 4. Vérifier les logs
|
||||
docker-compose logs -f app
|
||||
# 3. Vérifier les logs
|
||||
docker compose logs -f app
|
||||
```
|
||||
|
||||
Au démarrage, le serveur complète le schéma de la base (tables, colonnes,
|
||||
index) : aucune commande de migration n'est nécessaire. Les données, les
|
||||
fichiers téléversés, la clé de chiffrement et les sessions ouvertes sont
|
||||
conservés.
|
||||
|
||||
### Passage au serveur Rust
|
||||
|
||||
Depuis la version 2, le serveur est écrit en Rust (dossier `server/`) et
|
||||
remplace l'ancien serveur Node/Express. La bascule ne demande rien de plus
|
||||
qu'une reconstruction : mêmes variables d'environnement, même base, mêmes
|
||||
volumes, et les utilisateurs déjà connectés le restent (cookie `connect.sid`
|
||||
et table `session` repris tels quels). Le rendu Remotion des Reels tourne
|
||||
désormais dans son propre conteneur (`remotion-renderer`).
|
||||
+60
-76
@@ -1,84 +1,68 @@
|
||||
# Debian slim — glibc requis par le Chrome headless shell de Remotion (posix_fallocate64, etc.)
|
||||
FROM node:20-slim
|
||||
# SocialFlow — image de l'application : serveur Rust + frontend React compilé.
|
||||
#
|
||||
# Trois étapes : le frontend est compilé par Vite, le serveur par Cargo, et
|
||||
# l'image finale ne contient que le binaire, les fichiers statiques et FFmpeg
|
||||
# (vignettes vidéo, durée des pistes audio). Pas de Node à l'exécution.
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Frontend (Vite)
|
||||
# ---------------------------------------------------------------------------
|
||||
FROM node:20-slim AS frontend
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
# Aucune dépendance native n'est utile au build du frontend
|
||||
RUN npm ci --ignore-scripts --no-audit --no-fund
|
||||
|
||||
COPY client ./client
|
||||
COPY shared ./shared
|
||||
COPY attached_assets ./attached_assets
|
||||
COPY vite.config.ts tsconfig.json tailwind.config.ts postcss.config.js components.json ./
|
||||
RUN npx vite build
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Serveur (Rust)
|
||||
# ---------------------------------------------------------------------------
|
||||
FROM rust:1-slim-bookworm AS backend
|
||||
WORKDIR /app/server
|
||||
|
||||
# Dépendances compilées dans une couche à part : elles ne sont recompilées que
|
||||
# si Cargo.toml / Cargo.lock changent.
|
||||
COPY server/Cargo.toml server/Cargo.lock ./
|
||||
RUN mkdir src && echo 'fn main() {}' > src/main.rs \
|
||||
&& cargo build --release --locked \
|
||||
&& rm -rf src target/release/socialflow target/release/deps/socialflow-* target/release/.fingerprint/socialflow-*
|
||||
|
||||
COPY server/src ./src
|
||||
RUN cargo build --release --locked
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Image d'exécution
|
||||
# ---------------------------------------------------------------------------
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
ffmpeg \
|
||||
fonts-dejavu-core \
|
||||
fontconfig \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Augmenter la mémoire AVANT npm install + build (évite OOM sur les grosses dépendances)
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
COPY --from=backend /app/server/target/release/socialflow /usr/local/bin/socialflow
|
||||
COPY --from=frontend /app/dist/public ./dist/public
|
||||
COPY public-root ./public-root
|
||||
COPY server/fonts ./server/fonts
|
||||
|
||||
# Dépendances système : build tools, canvas/sharp, fonts, ffmpeg + dépendances Chrome
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 make g++ \
|
||||
libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev libpixman-1-dev \
|
||||
libvips-dev pkg-config \
|
||||
fonts-dejavu-core fontconfig \
|
||||
curl tar bzip2 \
|
||||
ffmpeg \
|
||||
libcap2-bin \
|
||||
ca-certificates \
|
||||
# Dépendances Chrome headless
|
||||
libasound2 \
|
||||
libatk-bridge2.0-0 \
|
||||
libatk1.0-0 \
|
||||
libcups2 \
|
||||
libdbus-1-3 \
|
||||
libdrm2 \
|
||||
libgbm1 \
|
||||
libglib2.0-0 \
|
||||
libgtk-3-0 \
|
||||
libnspr4 \
|
||||
libnss3 \
|
||||
libpango-1.0-0 \
|
||||
libx11-6 \
|
||||
libx11-xcb1 \
|
||||
libxcb1 \
|
||||
libxcomposite1 \
|
||||
libxdamage1 \
|
||||
libxext6 \
|
||||
libxfixes3 \
|
||||
libxkbcommon0 \
|
||||
libxrandr2 \
|
||||
libxshmfence1 \
|
||||
libxtst6 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copier les fichiers de configuration
|
||||
COPY package*.json ./
|
||||
|
||||
# Installer les dépendances
|
||||
RUN npm install --legacy-peer-deps --no-audit --no-fund
|
||||
|
||||
# Copier tout le code source
|
||||
COPY . .
|
||||
|
||||
# Télécharger et installer la police DejaVu Sans
|
||||
RUN mkdir -p server/fonts && \
|
||||
cd server/fonts && \
|
||||
curl -L -f --retry 3 --retry-delay 2 -o dejavu.tar.bz2 "https://sourceforge.net/projects/dejavu/files/dejavu/2.37/dejavu-fonts-ttf-2.37.tar.bz2/download" && \
|
||||
tar -xjf dejavu.tar.bz2 && \
|
||||
cp dejavu-fonts-ttf-2.37/ttf/DejaVuSans.ttf . && \
|
||||
rm -rf dejavu.tar.bz2 dejavu-fonts-ttf-2.37 && \
|
||||
echo "✓ Police DejaVu Sans installée"
|
||||
|
||||
# Build du frontend et backend
|
||||
RUN npm run build
|
||||
|
||||
# Nettoyer les fichiers inutiles
|
||||
RUN rm -rf client/node_modules \
|
||||
client/.vite \
|
||||
node_modules/.cache \
|
||||
/tmp/remotion-*
|
||||
|
||||
# Pré-bundler la composition Remotion
|
||||
RUN node scripts/prebundle-remotion.mjs || true
|
||||
|
||||
# Télécharger le Chrome headless shell de Remotion (binaire glibc natif sur Debian)
|
||||
RUN npx remotion browser ensure && echo "✓ Remotion browser prêt"
|
||||
|
||||
# Exposer le port
|
||||
EXPOSE 5555
|
||||
RUN mkdir -p uploads/media uploads/logos uploads/stories uploads/audio uploads/temp
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=5555
|
||||
EXPOSE 5555
|
||||
|
||||
CMD ["npm", "run", "start"]
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
||||
CMD curl -fsS "http://localhost:${PORT}/healthz" > /dev/null || exit 1
|
||||
|
||||
CMD ["socialflow"]
|
||||
@@ -100,9 +100,9 @@ Architecture Production-Ready avec sécurité renforcée.
|
||||
|
||||
| Fonctionnalité | Détail |
|
||||
| ------------------------------- | ---------------------------------------------------- |
|
||||
| **Authentification** | Passport.js + bcrypt, sessions PostgreSQL |
|
||||
| **Rate Limiting** | 100 req/15min global, 5 tentatives login/15min |
|
||||
| **Headers de sécurité** | Helmet (CSP, HSTS, XSS protection) |
|
||||
| **Authentification** | bcrypt, sessions PostgreSQL (cookie signé) |
|
||||
| **Rate Limiting** | 1000 req/15min global, 30 tentatives login/15min |
|
||||
| **Headers de sécurité** | CSP, HSTS, X-Frame-Options, nosniff… |
|
||||
| **Chiffrement des tokens** | Tokens Facebook/Instagram chiffrés (AES-256) |
|
||||
| **Gestion multi-utilisateurs** | Rôles Admin / User, permissions par page |
|
||||
| **Console SQL** | Requêtes directes en base (admin uniquement) |
|
||||
@@ -117,43 +117,53 @@ Architecture Production-Ready avec sécurité renforcée.
|
||||
socialflow/
|
||||
├── client/ # Frontend React (Vite + TailwindCSS)
|
||||
│ └── src/
|
||||
│ ├── pages/ # 17 pages desktop + 13 pages mobile
|
||||
│ ├── components/ # 47 composants UI (Radix/shadcn)
|
||||
│ └── hooks/ # Hooks React personnalisés
|
||||
├── server/ # Backend Express.js (TypeScript)
|
||||
│ ├── routes.ts # 45+ endpoints REST API
|
||||
│ ├── routes/ # Routes modulaires (analytics, reels)
|
||||
│ ├── services/ # 12 services métier
|
||||
│ │ ├── analytics.ts # Sync Facebook Graph API
|
||||
│ │ ├── facebook.ts # Publication Facebook/Instagram
|
||||
│ │ ├── openrouter.ts # Génération texte IA
|
||||
│ │ ├── cloudinary.ts # Upload cloud médias
|
||||
│ │ ├── ffmpeg.ts # Encodage vidéo (microservice)
|
||||
│ │ ├── freesound.ts # Musique libre de droits
|
||||
│ │ ├── jamendo.ts # Musique libre de droits
|
||||
│ │ ├── imageProcessor.ts # Traitement images (Sharp)
|
||||
│ │ ├── scheduler.ts # Publications programmées
|
||||
│ │ └── token_manager.ts # Gestion tokens OAuth
|
||||
│ └── cron.ts # Tâches planifiées
|
||||
├── shared/ # Schéma DB partagé (Drizzle ORM)
|
||||
│ ├── pages/ # Pages desktop + mobile
|
||||
│ ├── components/ # Composants UI (Radix/shadcn)
|
||||
│ └── remotion/ # Compositions vidéo des Reels (aperçu + rendu)
|
||||
├── server/ # Backend Rust (axum + sqlx)
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── main.rs # Démarrage : migrations, routes, tâches de fond
|
||||
│ ├── migrate.rs # Schéma PostgreSQL, mis à jour au démarrage
|
||||
│ ├── auth.rs # Sessions (cookie connect.sid) et rôles
|
||||
│ ├── db/ # Accès aux données
|
||||
│ ├── routes/ # API REST (/api, /api/v1 externe, pages légales)
|
||||
│ └── services/ # Facebook, TikTok, OpenRouter, Reels, scheduler, crons
|
||||
├── shared/ # Types et logique partagés par le frontend
|
||||
├── remotion-service/ # Rendu des Reels avec Remotion (Node + Chrome)
|
||||
├── ffmpeg-service/ # Microservice FFmpeg (Python/FastAPI)
|
||||
├── docker-compose.yml # Stack Docker (3 services)
|
||||
└── Dockerfile # Image production Node.js
|
||||
├── qwen-tts/ # Voix Qwen3-TTS (optionnel)
|
||||
├── docker-compose.yml # Stack Docker
|
||||
└── Dockerfile # Image de l'application (Rust + frontend compilé)
|
||||
```
|
||||
|
||||
### Stack Technique
|
||||
|
||||
| Couche | Technologies |
|
||||
| ---------- | --------------------------------------------------------------------------- |
|
||||
| **Frontend** | React 18, Vite, TailwindCSS, Radix UI, Recharts, Framer Motion, Wouter |
|
||||
| **Backend** | Express.js, TypeScript, Passport.js, Helmet, node-cron |
|
||||
| **BDD** | PostgreSQL 16, Drizzle ORM, connect-pg-simple (sessions) |
|
||||
| **Frontend** | React 18, Vite, TailwindCSS, Radix UI, Recharts, Wouter |
|
||||
| **Backend** | Rust : axum, tokio, sqlx, reqwest |
|
||||
| **BDD** | PostgreSQL 16 (schéma créé et migré automatiquement au démarrage) |
|
||||
| **IA** | OpenRouter (multi-modèle : GPT-4, Claude, Gemini, etc.) |
|
||||
| **Médias** | Cloudinary (upload), Sharp (images), FFmpeg microservice (vidéo) |
|
||||
| **Musique** | FreeSound API, Jamendo API |
|
||||
| **Réseaux** | Facebook Graph API v19 (Pages, Instagram, Insights) |
|
||||
| **Médias** | Stockage local, FFmpeg (vignettes, microservice vidéo), Remotion (Reels) |
|
||||
| **Réseaux** | Facebook Graph API (Pages, Instagram, Insights), TikTok Content Posting |
|
||||
| **Infra** | Docker Compose, Nginx reverse proxy |
|
||||
|
||||
### Mise à jour
|
||||
|
||||
L'image de l'application est construite à partir des sources (`pull_policy: build`).
|
||||
Après un `git pull`, le prochain démarrage de la stack reconstruit l'image et
|
||||
applique la nouvelle version :
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Au démarrage, le serveur met le schéma de la base à jour tout seul (aucune
|
||||
commande de migration à lancer). Les données, les médias, la clé de chiffrement
|
||||
et les sessions ouvertes sont conservés.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation Rapide
|
||||
@@ -161,7 +171,7 @@ socialflow/
|
||||
### Prérequis
|
||||
|
||||
- [Docker](https://www.docker.com/) & Docker Compose
|
||||
- [Node.js](https://nodejs.org/) v18+ (pour le développement local)
|
||||
- Pour le développement local : [Rust](https://rustup.rs/) (stable), [Node.js](https://nodejs.org/) 20+ et PostgreSQL
|
||||
|
||||
### 1. Récupérer l'application
|
||||
|
||||
@@ -199,11 +209,12 @@ FACEBOOK_APP_SECRET=...
|
||||
|
||||
```bash
|
||||
# Production (Docker)
|
||||
docker-compose up -d
|
||||
docker compose up -d --build
|
||||
|
||||
# Développement local
|
||||
# Développement local (deux terminaux)
|
||||
npm install
|
||||
npm run dev
|
||||
DATABASE_URL=postgresql://... npm run dev:server # API Rust sur le port 5000
|
||||
npm run dev # Frontend Vite, relaie /api vers le port 5000
|
||||
```
|
||||
|
||||
🚀 Rendez-vous sur **`http://localhost:5555`** pour commencer !
|
||||
|
||||
@@ -69,7 +69,6 @@ services:
|
||||
- media_uploads:/app/uploads/media
|
||||
- logos_uploads:/app/uploads/logos
|
||||
- stories_uploads:/app/uploads/stories
|
||||
command: npm run start
|
||||
|
||||
# Service FFmpeg dédié
|
||||
ffmpeg-api:
|
||||
|
||||
Generated
+89
-8090
File diff suppressed because it is too large.
Load diff
+4
-48
@@ -4,22 +4,19 @@
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "NODE_ENV=development tsx server/index.ts",
|
||||
"build": "vite build && esbuild server/index.ts --platform=node --packages=external --bundle --format=esm --outdir=dist",
|
||||
"start": "NODE_ENV=production node dist/index.js",
|
||||
"dev": "vite",
|
||||
"dev:server": "cargo run --manifest-path server/Cargo.toml",
|
||||
"build": "vite build",
|
||||
"start": "cargo run --release --manifest-path server/Cargo.toml",
|
||||
"check": "tsc",
|
||||
"db:push": "drizzle-kit push",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.1016.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fontsource/montserrat": "^5.3.0",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"@neondatabase/serverless": "^0.10.4",
|
||||
"@radix-ui/react-accordion": "^1.2.4",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.7",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.3",
|
||||
@@ -47,46 +44,20 @@
|
||||
"@radix-ui/react-toggle": "^1.1.3",
|
||||
"@radix-ui/react-toggle-group": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.2.0",
|
||||
"@remotion/bundler": "^4.0.438",
|
||||
"@remotion/cli": "^4.0.438",
|
||||
"@remotion/player": "^4.0.438",
|
||||
"@remotion/renderer": "^4.0.438",
|
||||
"@tanstack/react-query": "^5.60.5",
|
||||
"@twemoji/api": "^17.0.2",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/multer": "^2.0.0",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"@types/node-fetch": "^2.6.13",
|
||||
"@types/pg": "^8.15.5",
|
||||
"bcrypt": "^6.0.0",
|
||||
"canvas": "^2.11.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"cloudinary": "^2.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"connect-pg-simple": "^10.0.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"drizzle-orm": "^0.39.1",
|
||||
"drizzle-zod": "^0.7.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"emoji-regex": "^10.6.0",
|
||||
"express": "^4.21.2",
|
||||
"express-rate-limit": "^7.5.1",
|
||||
"express-session": "^1.18.1",
|
||||
"framer-motion": "^11.13.1",
|
||||
"helmet": "^8.1.0",
|
||||
"html-to-image": "^1.11.13",
|
||||
"html2canvas": "^1.4.1",
|
||||
"input-otp": "^1.4.2",
|
||||
"lucide-react": "^0.453.0",
|
||||
"memorystore": "^1.6.7",
|
||||
"multer": "^2.0.2",
|
||||
"music-metadata": "^11.12.3",
|
||||
"next-themes": "^0.4.6",
|
||||
"node-cron": "^4.2.1",
|
||||
"passport": "^0.7.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.16.3",
|
||||
"react": "^18.3.1",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@@ -97,15 +68,12 @@
|
||||
"react-webcam": "^7.2.0",
|
||||
"recharts": "^2.15.2",
|
||||
"remotion": "^4.0.438",
|
||||
"sharp": "^0.34.4",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tw-animate-css": "^1.2.5",
|
||||
"twemoji": "^14.0.2",
|
||||
"twemoji-parser": "^14.0.0",
|
||||
"vaul": "^1.1.2",
|
||||
"wouter": "^3.3.5",
|
||||
"ws": "^8.18.0",
|
||||
"zod": "^3.24.2",
|
||||
"zod-validation-error": "^3.4.0"
|
||||
},
|
||||
@@ -115,27 +83,15 @@
|
||||
"@replit/vite-plugin-runtime-error-modal": "^0.0.3",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/vite": "^4.1.3",
|
||||
"@types/connect-pg-simple": "^7.0.3",
|
||||
"@types/express": "4.17.21",
|
||||
"@types/express-session": "^1.18.0",
|
||||
"@types/node": "20.16.11",
|
||||
"@types/passport": "^1.0.16",
|
||||
"@types/passport-local": "^1.0.38",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/ws": "^8.5.13",
|
||||
"@vitejs/plugin-react": "^4.7.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"esbuild": "^0.25.0",
|
||||
"postcss": "^8.4.47",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tsx": "^4.20.5",
|
||||
"typescript": "5.6.3",
|
||||
"vite": "^5.4.20",
|
||||
"vitest": "^3.2.7"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.8"
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ Preferred communication style: Simple, everyday language.
|
||||
The frontend is built with React and TypeScript, leveraging Vite for bundling and Wouter for routing. State management is primarily handled by TanStack Query. UI components are constructed using Radix UI primitives and shadcn/ui, styled with Tailwind CSS, emphasizing a component-based, responsive, mobile-first design with real-time data synchronization. Dark mode is the default theme.
|
||||
|
||||
### Backend Architecture
|
||||
The backend is developed in Node.js with Express.js, entirely in TypeScript. It adheres to a RESTful API design with dedicated endpoints for authentication, user management, AI content generation, media handling, social page management, and post scheduling. Multer is utilized for file uploads, integrated with Cloudinary. Node-cron manages background processes for scheduled post publication. The architecture incorporates a service layer, storage abstraction, and a middleware-based request processing pipeline. Session management is handled by `express-session` with `connect-pg-simple`.
|
||||
The backend is written in Rust (axum, tokio, sqlx) in the `server/` crate. It exposes the same RESTful API as the former Node/Express server (authentication, user management, AI content generation, media handling, social page management, post scheduling, external API). Uploads are stored locally under `uploads/`. Background tasks (scheduled publications, token checks, analytics, media purge, Reel render queue) run as tokio tasks. Sessions are stored in the PostgreSQL `session` table with a signed `connect.sid` cookie, compatible with the former server. The database schema is created and migrated automatically at startup (`server/src/migrate.rs`). Remotion Reel rendering runs in a separate Node sidecar (`remotion-service/`).
|
||||
|
||||
### Database Architecture
|
||||
PostgreSQL serves as the database, interfaced using Drizzle ORM for type-safe operations and Neon serverless driver for WebSocket support. The schema includes tables for `users`, `cloudinary_config`, `social_pages`, `media`, `posts`, `post_media`, `scheduled_posts`, and `ai_generations`. Drizzle Kit is used for schema migrations.
|
||||
|
||||
@@ -24,6 +24,7 @@ use crate::state::AppState;
|
||||
|
||||
pub fn router(state: AppState) -> Router {
|
||||
let api = Router::new()
|
||||
.route("/healthz", axum::routing::get(healthz))
|
||||
.merge(auth::router())
|
||||
.merge(core::router())
|
||||
.nest("/api/analytics", analytics::router())
|
||||
@@ -56,6 +57,14 @@ pub fn router(state: AppState) -> Router {
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
/// Sonde de santé (Docker) : le serveur répond et la base est joignable.
|
||||
async fn healthz(State(state): State<AppState>) -> Response {
|
||||
match sqlx::query_scalar::<_, i32>("SELECT 1").fetch_one(&state.db.pool).await {
|
||||
Ok(_) => (StatusCode::OK, "ok").into_response(),
|
||||
Err(_) => (StatusCode::SERVICE_UNAVAILABLE, "database unavailable").into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Route inconnue : JSON pour `/api`, sinon fichiers publics puis l'application React.
|
||||
async fn fallback(State(state): State<AppState>, headers: HeaderMap, request: Request) -> Response {
|
||||
let path = request.uri().path().to_string();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"include": ["client/src/**/*", "shared/**/*", "server/**/*"],
|
||||
"include": ["client/src/**/*", "shared/**/*"],
|
||||
"exclude": ["node_modules", "build", "dist", "**/*.test.ts"],
|
||||
"compilerOptions": {
|
||||
"incremental": true,
|
||||
|
||||
@@ -32,6 +32,12 @@ export default defineConfig({
|
||||
emptyOutDir: true,
|
||||
},
|
||||
server: {
|
||||
// En développement, l'API et les fichiers sont servis par le serveur Rust
|
||||
// (`npm run dev:server`, port 5000 par défaut).
|
||||
proxy: {
|
||||
"/api": process.env.API_URL ?? "http://localhost:5000",
|
||||
"/uploads": process.env.API_URL ?? "http://localhost:5000",
|
||||
},
|
||||
fs: {
|
||||
strict: true,
|
||||
deny: ["**/.*"],
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
test: {
|
||||
include: ["shared/**/*.test.ts", "server/**/*.test.ts"],
|
||||
include: ["shared/**/*.test.ts"],
|
||||
environment: "node",
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user