Plateforme web pour découvrir et explorer les activités sportives et intellectuelles à Toulouse
Application web Next.js recensant plus de 500 activités sportives et intellectuelles disponibles à Toulouse. Carte interactive, blog SEO-optimisé, et scraping automatique quotidien.
- 🏠 Landing Page : Hero avec 2 CTA (Recherche d'activités + Future app de rencontre)
- 🔍 Recherche d'activités : Carte interactive + filtres avancés par catégorie et quartier
- ⚽ Pages catégories : Sport / Intellectuel avec sous-catégories
- 📝 Blog : 4 articles SEO-optimisés (guides, top clubs, conseils débutants)
- ❓ FAQ : 10 Q&A avec schema FAQPage pour Google rich snippets
- 🗺️ Pages quartiers : Activités par neighbourhood
- 📍 Carte interactive Leaflet.js avec géolocalisation
- 🔄 Scraping automatique quotidien via Vercel Cron Jobs (Google Places + OpenStreetMap)
- 🎨 Design moderne et minimaliste avec SCSS (architecture 7-1 + BEM)
- 📱 Interface 100% responsive (mobile, tablet, desktop)
- 🚀 SEO optimisé : schemas JSON-LD, sitemap dynamique, métadonnées complètes
- 🧭 Navigation Header/Footer sur toutes les pages
- 🎭 Animations Framer Motion
- Framework: Next.js 14 (App Router)
- Language: TypeScript 5
- Base de données: PostgreSQL (Supabase) avec Prisma ORM
- Styling: SCSS (architecture 7-1, convention BEM)
- Carte: Leaflet.js + OpenStreetMap
- Animations: Framer Motion
- Hébergement: Vercel (plan hobby gratuit)
- SEO: JSON-LD schemas (Organization, LocalBusiness, BlogPosting, FAQPage)
- Cloner le repository
git clone <repo-url>
cd ActivityAround- Installer les dépendances
npm install- Configurer les variables d'environnement
cp .env.example .env.localPuis remplir les valeurs dans .env.local :
DIRECT_URL: Connexion directe (port 5432) pour migrationsDATABASE_URL: Connexion poolée (port 6543) pour l'applicationCRON_SECRET: Secret pour sécuriser le cron job (générer avecopenssl rand -base64 32)GOOGLE_PLACES_API_KEY: Clé API Google Places (optionnel)NEXT_PUBLIC_BASE_URL: URL de votre site déployé
- Initialiser la base de données
# Générer le client Prisma
npm run db:generate
# Push le schéma vers la DB (utilise DIRECT_URL)
npm run db:push- Lancer le serveur de développement
npm run devL'application sera accessible sur http://localhost:3000
Si vous n'avez pas PostgreSQL installé localement :
Option 1: Docker
docker run --name postgres-toulouse -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgresOption 2: Vercel Postgres (gratuit)
- Créer un projet sur Vercel
- Ajouter Vercel Postgres
- Copier la
DATABASE_URLdans.env.local
Option 3: Supabase (gratuit)
- Créer un projet sur supabase.com
- Récupérer l'URL de connexion PostgreSQL
- La copier dans
.env.local
# Push le schéma vers la DB
npm run db:push
# Générer le client Prisma
npm run db:generate
# Ouvrir Prisma Studio (GUI)
npm run db:studioActivityAround/
├── src/
│ ├── app/ # Routes Next.js (App Router)
│ │ ├── layout.tsx # Layout racine avec Header/Footer
│ │ ├── page.tsx # Landing page
│ │ ├── activites/ # Recherche d'activités avec carte
│ │ ├── sport/ # Page catégorie sport
│ │ ├── intellectuel/ # Page catégorie intellectuel
│ │ ├── blog/ # Blog index et articles
│ │ │ ├── page.tsx # Liste des articles
│ │ │ └── [slug]/page.tsx # Article individuel
│ │ ├── faq/ # FAQ avec schema FAQPage
│ │ ├── quartier/[name]/ # Pages par quartier
│ │ ├── activity/[id]/[slug]/ # Détail activité SEO-friendly
│ │ ├── not-found.tsx # 404 personnalisée
│ │ └── api/ # API Routes
│ │ ├── activities/ # CRUD activités
│ │ └── cron/ # Cron jobs scraping
│ ├── components/ # Composants React
│ │ ├── Header.tsx # Navigation sticky
│ │ ├── Footer.tsx # Footer 4 colonnes
│ │ ├── FAQ.tsx # Accordion Q&A
│ │ ├── ActivitiesMap.tsx # Carte Leaflet
│ │ └── ... # Autres composants
│ ├── data/ # Données statiques
│ │ └── blog-posts.ts # Articles de blog TypeScript
│ ├── lib/ # Utilitaires
│ │ ├── prisma.ts # Instance Prisma
│ │ └── seo.ts # Helpers SEO et schemas JSON-LD
│ └── styles/ # SCSS (architecture 7-1)
│ ├── abstracts/ # Variables, mixins
│ ├── base/ # Reset, typography
│ ├── components/ # header.scss, footer.scss, etc.
│ ├── layout/ # Layout styles
│ ├── pages/ # home.scss, blog.scss, faq.scss, etc.
│ └── main.scss # Point d'entrée
├── prisma/
│ └── schema.prisma # Schéma DB (activities + reviews)
├── public/ # Assets statiques
│ ├── sitemap.xml # Sitemap dynamique
│ └── robots.txt # Configuration crawlers
└── vercel.json # Configuration Vercel (cron)
Le scraping est effectué automatiquement chaque jour à 3h du matin via Vercel Cron Jobs.
- Google Places API (40 000 requêtes/mois gratuites)
- Overpass API (OpenStreetMap, illimité)
# Créer un fichier .env.local avec CRON_SECRET
curl -X GET http://localhost:3000/api/cron/scrape-activities \
-H "Authorization: Bearer your-cron-secret"git init
git add .
git commit -m "Initial commit: ActivityAround v1.0"
git branch -M main
git remote add origin <your-repo-url>
git push -u origin main- Aller sur vercel.com et se connecter
- Cliquer sur "Add New Project"
- Importer votre repository GitHub
- Configuration du projet :
- Framework Preset: Next.js
- Root Directory:
./(laisser par défaut) - Build Command:
npm run build(détecté automatiquement) - Output Directory:
.next(détecté automatiquement)
Dans Vercel Dashboard > Settings > Environment Variables, ajouter :
DIRECT_URL="postgresql://USER:PASSWORD@HOST.supabase.co:5432/postgres"
DATABASE_URL="postgresql://USER:PASSWORD@HOST.supabase.co:6543/postgres?pgbouncer=true"
CRON_SECRET="your-secure-random-secret"
NEXT_PUBLIC_BASE_URL="https://your-site.vercel.app"Optionnels (pour le scraping) :
GOOGLE_PLACES_API_KEY="your-api-key"
SERPAPI_KEY="your-serpapi-key"
MAPBOX_TOKEN="your-mapbox-token"Pour SEO (optionnels) :
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION="your-verification-code"
NEXT_PUBLIC_GA_MEASUREMENT_ID="G-XXXXXXXXXX"- Créer un compte sur supabase.com
- Créer un nouveau projet
- Aller dans Settings > Database
- Copier les deux chaînes de connexion :
- Connection string (port 5432) →
DIRECT_URL - Connection pooling (port 6543) →
DATABASE_URL
- Connection string (port 5432) →
Une fois déployé, initialiser le schéma :
Option A : Via Vercel CLI
# Installer Vercel CLI
npm i -g vercel
# Se connecter
vercel login
# Link au projet
vercel link
# Exécuter la migration
vercel env pull .env.production
npx prisma db pushOption B : Via Supabase SQL Editor Copier-coller le schéma SQL généré par Prisma dans l'éditeur SQL Supabase.
-
Site web : Vérifier que toutes les pages se chargent
/→ Landing page/activites→ Recherche avec carte/blog→ Liste des articles/faq→ Questions fréquentes
-
API : Tester l'endpoint activities
curl https://your-site.vercel.app/api/activities
-
Cron Job : Vérifier dans Vercel Dashboard > Cron Jobs
- Le job
/api/cron/scrape-activitiesdoit apparaître - Schedule :
0 3 * * *(tous les jours à 3h)
- Le job
-
Google Search Console
- Ajouter votre site
- Vérifier avec
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION - Soumettre le sitemap :
https://your-site.vercel.app/sitemap.xml
-
Google Analytics (optionnel)
- Créer une propriété GA4
- Ajouter
NEXT_PUBLIC_GA_MEASUREMENT_ID
-
Tester les rich snippets
- Google Rich Results Test
- Tester
/faq(FAQPage schema) - Tester
/blog/[slug](BlogPosting schema)
Erreur "Prisma Client not found"
# Ajouter postinstall script dans package.json
"scripts": {
"postinstall": "prisma generate"
}Erreur timeout sur build
- Vérifier que
DATABASE_URLest correctement configuré - Les migrations Prisma utilisent
DIRECT_URLautomatiquement
Cron job ne s'exécute pas
- Vérifier que
vercel.jsonest bien commité - Le cron est protégé par
CRON_SECRET(Vercel l'ajoute automatiquement)
npm run dev # Démarre le serveur de développement
npm run build # Build pour production
npm run start # Démarre le serveur de production
npm run lint # Vérifie le code avec ESLint
npm run db:push # Push le schéma Prisma vers la DB
npm run db:generate # Génère le client Prisma
npm run db:studio # Ouvre Prisma StudioLe projet utilise l'architecture SCSS 7-1 et la convention de nommage BEM.
Variables : src/styles/abstracts/_variables.scss
$color-primary: #2563eb;
$spacing-md: 1rem;
$breakpoint-md: 768px;Mixins : src/styles/abstracts/_mixins.scss
@include respond-to('md') {
// Styles pour écrans ≥ 768px
}- Les routes
/api/cron/*sont protégées parCRON_SECRET - Validation des données avec Zod
- Variables d'environnement pour les clés API
.env.localest dans.gitignore
- 100 GB de bande passante/mois
- 100 heures de compute/mois
- Timeout fonction: 10s (hobby)
- 256 MB de stockage
- 60 heures de compute/mois
- Supabase: 500 MB, 2 projets gratuits
- Railway: 500 MB, $5 de crédit gratuit/mois
MIT