Spécification de Design: Portfolio Geekbrain.io
Date: 2025-03-21 Statut: Brouillon Auteur: Claude (avec Eric Chicoine)
1. Vision et Objectifs
1.1 But du projet
Créer un site portfolio professionnel pour présenter les activités de développeur Python/Agentique freelance sous la marque Geekbrain.io.
1.2 Objectifs spécifiques
- Présenter les compétences et expériences
- Afficher les projets via une liste dynamique tirée du GitBucket local
- Permettre aux clients potentiels de contacter via un formulaire
- Design steampunk professionnel moderne
- Hébergement sur NAS Docker avec Nginx Proxy Manager
- Maintenance simple et contrôle total du code
2. Exigences
2.1 Exigences fonctionnelles
Pages
- Accueil: Hero section, résumé, services, compétences principales, CTA
- À propos: Parcours, photo, compétences détaillées
- Projets: Liste automatique des repos GitBucket (nom + description README)
- Contact: Formulaire avec validation, reCAPTCHA, envoi email + stockage BD
Champs:
- Nom (obligatoire)
- Email (obligatoire, validation email)
- Sujet (obligatoire)
- Message (obligatoire)
- Soumis avec reCAPTCHA v2
Traitement:
- Validation frontend + backend
- Stockage en base de données (table
contacts)
- Envoi email via SMTP Gmail ([email protected])
- Réponse HTTP appropriée (succès/erreur)
Affichage des projets
- Appel API GitBucket:
http://10.0.0.16:8080/api/v3/users/rcairbum/repos
- Extraction:
name + description
- Affichage en cartes sans lien vers le repo GitBucket (projets affichés en lecture seule)
- Si API down ou erreur: afficher "Projets temporairement indisponibles"
- Cache: 5 minutes
- Note: Les repos seront configurés en public sur GitBucket, donc pas besoin d'authentification
2.2 Exigences non-fonctionnelles
- Site rapide (FastAPI asynchrone)
- Cache des appels GitBucket (éviter requêtes fréquentes)
Sécurité
- reCAPTCHA pour anti-spam
- Validation backend complète
- Pas d'injection SQL (SQLAlchemy ORM)
- Variables d'environnement pour secrets (SMTP, DB)
- Headers de sécurité (CORS, etc.)
Hébergement
- Docker container isolé
- Utilisation MariaDB existante
- Proxy via Nginx Proxy Manager
- HTTPS automatique via Let's Encrypt
Maintenance
- Configuration via variables d'environnement
- Logs structurés
- Code modulaire et documenté
3. Architecture Technique
3.1 Stack
- Backend: FastAPI 0.104+ (Python 3.11+)
- Frontend: Jinja2 templates + CSS personnalisé
- Base de données: MariaDB (10.0.0.16:3306)
- ORM: SQLAlchemy 2.0+ avec asyncpg (async)
- Validation: Pydantic v2
- Email: aiosmtplib (async SMTP)
- Container: Docker + docker-compose
- Proxy: Nginx Proxy Manager
- API externe: GitBucket REST API (compatible GitHub v3)
3.2 Structure du projet
geekbrain-portfolio/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app, routes
│ ├── config.py # Configuration (env vars)
│ ├── database.py # DB connection, session
│ ├── models.py # SQLAlchemy models
│ ├── schemas.py # Pydantic schemas
│ ├── crud.py # Database operations
│ ├── routes/
│ │ ├── home.py
│ │ ├── about.py
│ │ ├── projects.py
│ │ └── contact.py
│ ├── services/
│ │ ├── gitbucket.py # Fetch repos from GitBucket
│ │ └── email.py # Send contact email
│ ├── templates/
│ │ ├── base.html # Steampunk theme
│ │ ├── index.html
│ │ ├── about.html
│ │ ├── projects.html
│ │ └── contact.html
│ ├── static/
│ │ ├── css/
│ │ │ └── style.css # Steampunk styling
│ │ ├── js/
│ │ │ └── main.js # Frontend validation, reCAPTCHA
│ │ └── assets/ # Logo et images (copié depuis public/assets/)
│ │ └── images/ # Contient Geekbrain-io.png
└── docker/
├── Dockerfile
├── docker-compose.yml
└── .env.example
3.3 Docker
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
docker-compose.yml:
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=mysql+aiomysql://geekbrain_app:${DB_PASSWORD}@10.0.0.16:3306/geekbrain_portfolio
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_USER=${SMTP_USER}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- RECAPTCHA_SECRET=${RECAPTCHA_SECRET}
- GITBUCKET_URL=http://10.0.0.16:8080/api/v3/users/rcairbum/repos
volumes:
- ./app/static:/app/static
restart: unless-stopped
3.4 Base de données
Création MariaDB (à exécuter sur le serveur DB)
CREATE DATABASE geekbrain_portfolio CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'geekbrain_app'@'%' IDENTIFIED BY '${APP_DB_PASSWORD}';
GRANT SELECT, INSERT, UPDATE, DELETE ON geekbrain_portfolio.* TO 'geekbrain_app'@'%';
FLUSH PRIVILEGES;
(Privilèges restreints aux opérations nécessaires, pas ALL PRIVILEGES pour plus de sécurité)
Schéma
Table contacts:
CREATE TABLE contacts (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
subject VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(45),
recaptcha_score FLOAT
);
(Optionnel) Table site_settings pour config future?
4. Modèles de données (SQLAlchemy)
class Contact(Base):
__tablename__ = "contacts"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(255))
email: Mapped[str] = mapped_column(String(255))
subject: Mapped[str] = mapped_column(String(255))
message: Mapped[str] = mapped_column(Text)
submitted_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
ip_address: Mapped[Optional[str]] = mapped_column(String(45))
5. API Endpoints (FastAPI)
| Méthode |
Path |
Description |
| GET |
/ |
Page d'accueil |
| GET |
/about |
Page à propos |
| GET |
/projects |
Page projets (appelle GitBucket API) |
| GET |
/contact |
Page contact (formulaire) |
| POST |
/contact |
Soumission formulaire (validate + save + email) |
| GET |
/health |
Health check (pour monitoring) |
POST /contact body
{
"name": "Jean Dupont",
"email": "[email protected]",
"subject": "Demande de devis",
"message": "Bonjour, je souhaite...",
"recaptcha_token": "token_from_frontend"
}
Response
{
"success": true,
"message": "Message envoyé avec succès"
}
6. Design UI/UX
6.1 Palette Steampunk Pro Moderne
- Primaire: Laiton doré
#D4AF37 (boutons, accents)
- Secondaire: Gris acier
#4a4a4a (textes secondaires, fonds sombres)
- Fond clair: Blanc cassé
#F5F5DC (cartes, contenu)
- Fond sombre: Noir charbon
#1a1a1a (header, footer, hero)
- Accent: Cuivre
#B87333 (gradients, hover)
6.2 Typographie
- Headers: Times New Roman, Georgia (serif)
- Body: System fonts (sans-serif pour lisibilité)
- Tailles généreuses, espacement aéré
6.3 Layout
- Header sombre avec logo (
public/assets/images/Geekbrain-io.png) à gauche, nav alignée droite
- Navigation horizontale desktop, hamburger menu mobile
- Hero section avec gradient doré et call-to-action
- Grille responsive pour projets et cartes
- Footer sombre avec copyright + LinkedIn
- Bordure
2px solid #D4AF37 sur cartes/hero
6.4 Responsive
- Mobile-first CSS
- Breakpoints: 768px, 1024px
- Navigation adaptative
7. Configuration
Variables d'environnement requises:
| Variable |
Description |
obligatoire |
DATABASE_URL |
Connection MariaDB (SQLAlchemy format) |
Oui |
SMTP_HOST |
Serveur SMTP (smtp.gmail.com) |
Oui |
SMTP_PORT |
Port SMTP (587) |
Oui |
SMTP_USER |
Email expéditeur ([email protected]) |
Oui |
SMTP_PASSWORD |
Mot de passe/mot de passe d'appli Gmail |
Oui |
RECAPTCHA_SECRET |
Clé secrète reCAPTCHA v2 |
Oui |
GITBUCKET_URL |
URL API GitBucket |
Oui |
CACHE_TTL |
Cache API GitBucket en secondes (défaut: 300) |
Non |
8. Sécurité
8.1 reCAPTCHA
- reCAPTCHA v2 ("I'm not a robot") sur formulaire
- Vérification backend via secret key
- Score/threshold pour détecter bots
8.2 Validation
- Pydantic pour schémas de données
- Validation email, longueur, caractères
- Protection CSRF? (pas nécessaire pour API simple)
- CORS configuré (allow origins si besoin)
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
8.4 Secrets
- Variables d'environnement uniquement
- Jamais commit de .env
- Supporter configurer via Docker secrets/swarm si nécessaire
9. Intégrations externes
9.1 GitBucket API
- Endpoint:
http://10.0.0.16:8080/api/v3/users/rcairbum/repos
- Méthode: GET
- Format: JSON (compatible GitHub API v3)
- Authentication: Non requis (les repos seront configurés en public)
- Cache: 5 minutes par défaut (pour éviter surcharge)
- Fallback: Si erreur/timeout, afficher message "Projets temporairement indisponibles"
9.2 Email (SMTP)
- SMTP Gmail (TLS)
- Destinataire: [email protected] (ou configurable)
- Expéditeur: même que SMTP_USER
- Template d'email simple avec infos du contact
9.3 reCAPTCHA
- Version v2 (checkbox)
- Site key en frontend (dans template)
- Secret key en backend (variable env)
- Vérification via API Google
10. Hébergement et Déploiement
10.1 Prérequis sur NAS
- Docker installé
- Docker Compose
- MariaDB accessible (10.0.0.16:3306)
- Nginx Proxy Manager (NPM) installé
10.2 Étapes de déploiement
-
Configurer la base de données MariaDB (sur le serveur DB):
CREATE DATABASE geekbrain_portfolio CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'geekbrain_app'@'%' IDENTIFIED BY 'UN_MOT_DE_PASSE_SECURISE';
GRANT ALL PRIVILEGES ON geekbrain_portfolio.* TO 'geekbrain_app'@'%';
FLUSH PRIVILEGES;
-
Préparer le container Docker:
- Cloner/construire l'application
- Créer
.env à partir de .env.example
- Renseigner variables (DB password, SMTP, reCAPTCHA, etc.)
-
Démarrer le service:
docker-compose up -d
-
Configurer Nginx Proxy Manager:
- Ajouter un "Proxy Host"
- Domain names:
portfolio.geekbrain.io
- Scheme: http, Host: IP_DU_NAS, Port: 8000
- Activer SSL (Let's Encrypt)
- Activer WebSockets si besoin (pas nécessaire ici)
-
Vérifier:
10.3 Mise à jour
git pull <repo>
docker-compose down
docker-compose up -d --build
11. Maintenance et Monitoring
11.1 Logs
- FastAPI logs structurés (JSON si possible)
- Docker logs (
docker-compose logs -f web)
- Configuration niveau log via variable env (
LOG_LEVEL)
11.2 Health check
Endpoint /health retourne 200 si DB connectée.
11.3 Sauvegardes
- Backup MariaDB automatique (géré au niveau NAS)
- Backup code Git (hors périmètre)
11.4 Monitoring
- Métriques FastAPI (optionnel)
- Monitoring Docker via Portainer ou Watchtower
12. Évolution future (backlog)
- Interface admin pour gérer projets (au lieu de GitBucket API)
- Blog technique avec articles markdown
- Multilanguage (i18n)
- Stats de visites (Plausible/Umami)
- Notification Slack/Discord pour nouveaux contacts
- Export contacts CSV
- Thème sombre/clair
13. Risques et Contraintes
13.1 Risques
- GitBucket API non accessible depuis container (réseau) → utiliser SSHFS ou API publique?
- Spam malgré reCAPTCHA → prévoir rate limiting
- SMTP Gmail limitations (quotas) → prévoir alternative
- dépendandance à GitBucket privé → considérer copie locale
13.2 Contraintes
- Doit fonctionner sur NAS avec ressources limitées (RAM/CPU)
- Version MariaDB existante (compatibilité SQLAlchemy)
- Accès réseau local à GitBucket (10.0.0.16)
14. Tests
14.1 Tests unitaires
- Modèles Pydantic
- Fonctions de validation
- Crud opérations
14.2 Tests d'intégration
- Endpoints API (TestClient)
- Connexion DB
- Envoi email (mock SMTP)
14.3 Tests manuels
- Formulaire soumission avec/erreurs
- Affichage projets (mocked API)
- Responsive design
15. Suivi et Acceptation
Critères d'acceptation
Prochaines étapes:
- Valider cette spécification
- Créer le plan d'implémentation détaillé (writing-plans)
- Implémenter par phases (setup, DB, routes, templates, intégrations, Docker)
- Tester et déployer
Document generated by Claude Code - superpowers:brainstorming