Guide pas à pas pour développeur débutant : prérequis, base de données, serveur, emails, paiement, API, chatbot IA, tâches planifiées, sécurité et dépannage.
http:// vers https://. Avant la mise en ligne, le certificat SSL doit être actif, sinon les visiteurs verront une alerte de sécurité. Suivez la section 11. HTTPS et nom de domaine puis la section 21 bis. Sécurité renforcée V65.Le projet est fait de deux parties qui doivent tourner sur le même nom de domaine :
| Partie | Contenu | Technologie |
|---|---|---|
| frontend/ la boutique + le back office | Pages HTML (accueil, boutique, fiche produit, panier, commande, compte, blog, FAQ, pages légales…), admin.html (back office), scripts js/, styles css/, icônes, service worker (application installable). | HTML, CSS, JavaScript (aucune compilation nécessaire) |
| backend/ le serveur | Contrôleurs, modèles, migrations (tables), emails, paiements, SEO, connecteurs API. Ce n'est pas un projet Laravel complet : ce sont les fichiers à ajouter dans un projet Laravel neuf. | PHP 8.2+, Laravel 11 ou 12, PostgreSQL, Laravel Sanctum |
/api/v1/catalog.js (le catalogue venant de la base) puis js/data.js./api/... sont toujours relatives au domaine : c'est pour cela que la boutique et Laravel doivent être sur le même domaine./home/votrecompte/ ├── amyevolution/ ← projet Laravel (PAS accessible depuis le web) │ ├── app/ bootstrap/ config/ database/ routes/ resources/ storage/ vendor/ │ ├── .env ← vos réglages secrets │ └── artisan └── public_html/ ← racine web du domaine (= dossier public/ de Laravel) ├── index.php ← porte d'entrée de Laravel (OBLIGATOIRE) ├── .htaccess ← fusionné (voir section 10) ├── index.html, shop.html, product.html, admin.html … ← contenu de frontend/ ├── css/ js/ icon/ ├── storage → ../amyevolution/storage/app/public ← lien des images importées ├── frontend/ ← copie de frontend/ (voir piège n°2) └── backend/login.html ← page de connexion du back office
Avant d'acheter ou de choisir une offre, vérifiez chaque ligne avec le support de l'hébergeur.
| Élément | Obligatoire ? | Détail |
|---|---|---|
| PHP 8.2 ou plus (8.3 conseillé) | Oui | Laravel 11 et 12 refusent PHP 8.1. Le choix de version se fait souvent dans cPanel > « Sélectionner une version de PHP ». |
| PostgreSQL (version 13 ou plus) | Oui | Le projet utilise des fonctions propres à PostgreSQL (colonnes jsonb, séquence des numéros de commande, recherche ILIKE). MySQL/MariaDB ne fonctionne pas. Beaucoup d'offres mutualisées ne proposent que MySQL : voir l'encadré ci-dessous. |
| Extensions PHP | Oui | pdo_pgsql, pgsql, mbstring, openssl, curl, fileinfo, tokenizer, xml, ctype, json, bcmath. Conseillées : intl, gd, zip, opcache. |
| Accès SSH (terminal) | Fortement conseillé | Indispensable pour lancer php artisan (migrations, création de l'administrateur, vidage du cache). Sans SSH, voir la variante en section 9. |
| Composer 2 | Conseillé sur le serveur | Souvent disponible en SSH (composer -V). Sinon, on installe les dépendances sur votre ordinateur et on envoie le dossier vendor/. |
| Choix de la racine web du domaine | Oui | Le domaine doit pointer vers le dossier public/ de Laravel, ou bien on place le contenu de public/ dans public_html (section 9). |
Apache avec mod_rewrite | Oui | Presque toujours présent en mutualisé. Nginx fonctionne aussi (voir section 10). |
| Certificat SSL (HTTPS) | Oui | Let's Encrypt gratuit dans cPanel (« SSL/TLS Status » ou « AutoSSL »). Le paiement, la connexion et les connecteurs API exigent HTTPS. |
| Tâches planifiées (cron) | Oui si connecteurs API | Une tâche chaque minute (section 13). Certaines offres limitent à une tâche toutes les 5 ou 15 minutes : cela reste acceptable. |
| Boîte email du domaine (SMTP) | Oui | Pour les confirmations de commande, les changements de statut, le mot de passe oublié et les alertes. Voir section 12. |
| Espace disque | 1 Go minimum | Le projet + vendor/ pèse environ 80 Mo. Prévoyez de la place pour les images importées et les sauvegardes. |
Mémoire PHP (memory_limit) | 256 Mo conseillés | Les imports Excel et le catalogue complet consomment de la mémoire. |
Taille d'envoi (upload_max_filesize, post_max_size) | 8 Mo minimum | Les images importées sont envoyées au serveur (jusqu'à environ 4 Mo chacune). |
| Appels sortants HTTPS | Oui si paiement, IA ou connecteurs | Le serveur doit pouvoir appeler Flouci, Konnect, ClicToPay, OpenAI et vos logiciels partenaires. Certains hébergeurs bloquent les appels sortants : à vérifier. |
.env : l'adresse fournie dans DB_HOST et DB_SSLMODE=require. Vérifiez que l'hébergeur autorise la connexion sortante sur le port 5432.| Outil | À quoi il sert | Où le trouver |
|---|---|---|
| PHP 8.3 | Préparer le projet et lancer artisan en local | Windows : Laragon ou XAMPP · Mac : Herd ou Homebrew |
| Composer 2 | Installer Laravel et ses dépendances | getcomposer.org |
| PostgreSQL (facultatif) | Tester en local avant la mise en ligne | postgresql.org (avec pgAdmin) |
| Client FTP/SFTP | Envoyer les fichiers chez l'hébergeur | FileZilla, WinSCP |
| Client SSH | Se connecter au terminal du serveur | Terminal (Mac/Linux), PowerShell ou PuTTY (Windows) |
| Éditeur de code | Modifier le .env et les fichiers | Visual Studio Code |
| 7-Zip | Ouvrir l'archive du projet | 7-zip.org |
.htaccess de la boutique contient déjà les règles de Laravel, la connexion se fait par /admin-login.html (aucune copie supplémentaire de dossier), et la migration 1 complète la table users d'un Laravel neuf. Les explications ci-dessous restent valables pour les versions précédentes.En lisant le code, trois points bloquent une installation « à la lettre » du fichier INSTALLATION.txt. Voici les solutions. Elles sont reprises dans les étapes suivantes.
frontend/.htaccess ne contient que des règles de cache et de compression. Si vous copiez le contenu de frontend/ dans public/ en écrasant les fichiers, le .htaccess de Laravel disparaît : toutes les adresses /api/... renvoient alors « 404 Not Found » et la boutique reste en mode démo..htaccess fusionné donné en section 10.../backend/login.html et ../frontend/admin.html. Une fois frontend/ copié à la racine du site, ces adresses pointent vers /backend/login.html et /frontend/admin.html, qui n'existent pas.frontend/ complet dans public_html/frontend/ ;public_html/backend/ et y mettre backend/login.html.https://www.votre-domaine.tn/admin-login.html./admin.html, /login-admin.html…). C'est une petite modification du code, prévue dans la liste des correctifs.0001_01_01_000000_create_users_table.php. Elle crée une table users avec une seule colonne name. La migration du projet voit que la table existe, n'y touche pas, et il manque alors first_name, last_name, role… La connexion admin et l'inscription des clients échouent.php artisan migrate (section 5, étape 3).On prépare tout en local, puis on envoie le résultat. C'est plus sûr et plus rapide que de tout faire sur le serveur.
composer create-project laravel/laravel amyevolution
cd amyevolution
php artisan install:api # installe Laravel Sanctum (jetons de connexion) et active routes/api.php
Si la commande pose une question sur les migrations, répondez non : on lancera les migrations plus tard.
Copiez dans le projet Laravel (en remplaçant les fichiers existants) :
Depuis ecommerceV40/backend/ | Vers amyevolution/ |
|---|---|
app/ (tout le dossier) | app/ |
bootstrap/app.php | bootstrap/app.php |
config/mail.php, config/services.php, config/shop.php | config/ |
database/migrations/*, database/seeders/* (avec data/catalog.json) | database/ |
resources/views/emails/* | resources/views/emails/ |
routes/api.php, routes/web.php | routes/ |
env.example.txt | renommé en .env (section 7) |
Dans database/migrations/, supprimez :
0001_01_01_000000_create_users_table.php 0001_01_01_000001_create_cache_table.php 0001_01_01_000002_create_jobs_table.php
Gardez la migration ..._create_personal_access_tokens_table.php ajoutée par Sanctum : celle du projet la détecte et ne la recrée pas. Il doit rester les 16 migrations 2025_01_01_0000xx_... du projet.
composer install --no-dev --optimize-autoloader
public/ de Laravel, supprimez robots.txt et index.html s'ils existent (le robots.txt est généré par le serveur). Ne supprimez jamais index.php.frontend/ dans public/, sauf .htaccess.public/.htaccess par la version fusionnée de la section 10.frontend/ complet dans public/frontend/, et créez public/backend/login.html (copie de backend/login.html).Les pages Contact, FAQ, Blog, Livraison, Retours, Garantie, CGV, Mentions légales, Confidentialité et Cookies contiennent l'adresse https://www.amyevolution.tn/ (adresse officielle pour Google et aperçu sur les réseaux sociaux). Si votre domaine est différent, faites un « Rechercher / Remplacer dans les fichiers » avec VS Code dans public/.
compte_amyevolution. Le préfixe du compte est ajouté automatiquement.localhost) et port (5432).sudo -u postgres psql CREATE USER amyevolution WITH PASSWORD 'un-mot-de-passe-tres-solide'; CREATE DATABASE amyevolution OWNER amyevolution ENCODING 'UTF8'; \q
Le fichier .env se trouve à la racine du projet Laravel. Il ne doit jamais être accessible depuis le web ni envoyé à qui que ce soit. Après chaque modification : php artisan config:clear (ou config:cache en production).
# ---------- Application ---------- APP_NAME="AMY EVOLUTION" APP_ENV=production # production = robots.txt ouvert à Google, erreurs masquées APP_KEY= # rempli par : php artisan key:generate (NE JAMAIS LE CHANGER ENSUITE) APP_DEBUG=false # true seulement pour chercher une erreur, puis remettre false APP_URL=https://www.votre-domaine.tn # adresse exacte, sans / final (sert aux emails et au SEO) APP_LOCALE=fr APP_TIMEZONE=Africa/Tunis # ---------- Base PostgreSQL ---------- DB_CONNECTION=pgsql DB_HOST=127.0.0.1 # ou localhost, ou l'adresse de la base externe DB_PORT=5432 DB_DATABASE=compte_amyevolution DB_USERNAME=compte_amyuser DB_PASSWORD=MOT_DE_PASSE_DE_LA_BASE DB_SCHEMA=public DB_SSLMODE=prefer # require pour une base externe chiffrée # ---------- Sécurité (NOUVEAU V65) ---------- FORCE_HTTPS=true # http:// renvoie vers https:// (false = couper temporairement, ex. certificat en panne) SESSION_SECURE_COOKIE=true # cookie de connexion envoyé seulement en HTTPS SESSION_HTTP_ONLY=true # cookie illisible par JavaScript (protège contre le vol de session) SESSION_SAME_SITE=lax # bloque l'envoi du cookie depuis un autre site SESSION_ENCRYPT=true # contenu de la session chiffré en base SESSION_LIFETIME=120 # déconnexion après 120 minutes d'inactivité LOG_LEVEL=warning # journal sans détails inutiles BCRYPT_ROUNDS=12 # solidité du chiffrement des mots de passe # ---------- Sessions, cache, file d'attente ---------- SESSION_DRIVER=database CACHE_STORE=database # OBLIGATOIRE (database ou redis) : sert à l'anti-rejeu des connecteurs API QUEUE_CONNECTION=sync # emails envoyés tout de suite ; une panne SMTP ne bloque jamais une commande # ---------- Emails (peut être remplacé depuis le back office) ---------- MAIL_MAILER=smtp MAIL_HOST=mail.votre-domaine.tn MAIL_PORT=465 MAIL_ENCRYPTION=ssl MAIL_USERNAME=contact@votre-domaine.tn MAIL_PASSWORD=MOT_DE_PASSE_DE_LA_BOITE MAIL_FROM_ADDRESS=contact@votre-domaine.tn MAIL_FROM_NAME="${APP_NAME}" MAIL_ADMIN_ADDRESS= # reçoit les alertes « nouvelle commande / nouveau message » (vide = email boutique) # ---------- Chatbot IA (facultatif) ---------- AI_API_KEY= # vide = chatbot local sans IA (aucune erreur) AI_BASE_URL=https://api.openai.com/v1 AI_MODEL=gpt-4o-mini # ---------- Boutique (config/shop.php) ---------- SHOP_NAME=AMYEVOLUTION SHOP_TAGLINE="Électronique Premium en Tunisie" SHOP_PHONE="+216 71 234 567" SHOP_EMAIL=contact@votre-domaine.tn SHOP_STREET="Centre Commercial Lac 2" SHOP_CITY=Tunis SHOP_POSTAL_CODE=1053 SHOP_SOCIAL_URLS=https://facebook.com/...,https://instagram.com/... SHOP_LOGO=/icon/icon-512.png SHOP_DEFAULT_IMAGE=/icon/icon-512.png SHOP_CLEAN_URLS=true # adresses propres /produit/..., /categorie/..., /marque/... SHOP_FRONTEND_PATH= # vide = dossier public/ de Laravel (voir section 9, cas public_html) SHOP_FRONTEND_URL=/ # Livraison (le serveur recalcule toujours le total de la commande) SHOP_SHIPPING_PRICE=7 SHOP_EXPRESS_PRICE=15 SHOP_FREE_SHIPPING_FROM=150 SHOP_RETURNS_DAYS=30 # Modes de paiement acceptés (false = retiré) SHOP_PAY_COD=true # paiement à la livraison (choix par défaut) SHOP_PAY_CARD=true SHOP_PAY_D17=true SHOP_PAY_FLOUCI=true SHOP_PAY_VIREMENT=true
.env dans un endroit sûr..env existant n'est pas remplacé. Ouvrez backend/env.example.txt, copiez toute la rubrique # --- Sécurité (VERSION 65) --- (de FORCE_HTTPS à BCRYPT_ROUNDS) et collez-la dans le .env du serveur, puis lancez php artisan config:clear. Vérifiez au passage APP_ENV=production, APP_DEBUG=false et APP_URL=https://.....env donne les valeurs par défaut. Les réglages enregistrés dans le back office (livraison, zones, moyens de paiement, SMTP, textes…) les remplacent ensuite. Exemple : un SMTP saisi dans Paramètres > Email SMTP passe avant les lignes MAIL_... du .env.À lancer dans le dossier du projet Laravel, en local (si votre base locale est la même que celle du serveur) ou directement sur le serveur en SSH.
php artisan key:generate # une seule fois, au tout début php artisan migrate --force # crée toutes les tables php artisan db:seed --class=CatalogSeeder --force # facultatif : produits de démonstration php artisan db:seed --class=CouponSeeder --force # facultatif : codes BIENVENUE10 et LIVRAISON php artisan storage:link # rend visibles les images importées php artisan amy:create-admin vous@votre-domaine.tn "Votre Nom" # → le mot de passe est demandé (8 caractères minimum, lettre + chiffre), il ne s'affiche pas # → la même commande remet un nouveau mot de passe si vous l'oubliez php artisan config:cache php artisan route:cache php artisan view:cache
| Domaine | Tables |
|---|---|
| Comptes et technique | users, password_reset_tokens, sessions, personal_access_tokens, cache, cache_locks, jobs, failed_jobs |
| Catalogue | categories (3 niveaux), brands, products (avec vente flash, nouveauté, déstockage, produits liés, index de performance) |
| Ventes | coupons, addresses, orders, order_items, order_histories, carts, séquence order_number_seq |
| Relation client | reviews, wishlist_items, newsletter_subscribers, contact_messages, product_views, customers |
| Contenu et réglages | settings, media, blog_posts |
| Chatbot | chatbot_questions, chatbot_documents |
| Connecteurs API | api_keys, api_request_logs, webhook_endpoints, webhook_deliveries |
INSTALLATION.txt (étape 1) crée un administrateur avec le rôle admin via php artisan tinker. Utilisez plutôt amy:create-admin : elle crée un Super Admin (seul rôle qui peut gérer les utilisateurs, les connecteurs API et les réglages sensibles) et vérifie la solidité du mot de passe.vendor/) dans /home/votrecompte/amyevolution/, par SFTP ou en archive .zip à décompresser avec le gestionnaire de fichiers de cPanel.amyevolution/public./home/votrecompte/amyevolution/ (hors de public_html).amyevolution/public/ dans public_html/.public_html/index.php : remplacez les chemins __DIR__.'/../ par __DIR__.'/../amyevolution/. Il y a 3 lignes à changer :
if (file_exists($maintenance = __DIR__.'/../amyevolution/storage/framework/maintenance.php')) { ... }
require __DIR__.'/../amyevolution/vendor/autoload.php';
$app = require_once __DIR__.'/../amyevolution/bootstrap/app.php';.env :
SHOP_FRONTEND_PATH=/home/votrecompte/public_html
amyevolution/bootstrap/app.php, indiquez le nouveau dossier public (sinon storage:link et certaines adresses visent le mauvais dossier). Remplacez return Application::configure(...) par $app = Application::configure(...), laissez tout le reste identique jusqu'à ->create();, puis ajoutez à la fin :
$app->usePublicPath('/home/votrecompte/public_html');
return $app;ln -s /home/votrecompte/amyevolution/storage/app/public /home/votrecompte/public_html/storageSans SSH : créez une tâche cron unique avec cette même commande, puis supprimez-la.
chmod -R 775 storage bootstrap/cache chmod 640 .env
composer install et toutes les commandes artisan sur votre ordinateur, avec un .env qui pointe vers la base du serveur, si l'hébergeur autorise la connexion à distance à PostgreSQL (cPanel > « PostgreSQL distant » ou « Remote Database Access »).bootstrap/cache/config.php si vous avez fait config:cache en local : il contient les chemins de votre ordinateur.Ce fichier remplace public/.htaccess (ou public_html/.htaccess). Il réunit les règles indispensables de Laravel et les règles de performance de la boutique (piège n°1).
Version V65 : copie exacte du fichier frontend/.htaccess livré dans l’archive (HTTPS forcé, fichiers sensibles bloqués, en-têtes de sécurité). Copiez le fichier tel quel plutôt que de le retaper.
# ============================================================ # AMYEVOLUTION — .htaccess (VERSION 47 : fusion Laravel + boutique) # Peut maintenant écraser public/.htaccess de Laravel sans risque (piège n°1 réglé). # Sans Laravel (dossier frontend seul, mode démo) : les règles Laravel sont ignorées # automatiquement car index.php n'existe pas. # ============================================================ DirectoryIndex index.php index.html <IfModule mod_rewrite.c> <IfModule mod_negotiation.c> Options -MultiViews -Indexes </IfModule> RewriteEngine On # En-têtes d'autorisation (connexion admin, comptes clients, clés API) RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteCond %{HTTP:x-xsrf-token} . RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] # VERSION 65 : HTTPS FORCÉ — un visiteur qui tape http:// est renvoyé vers https:// (redirection 301 définitive) # Fonctionne aussi derrière Cloudflare / un proxy (en-tête X-Forwarded-Proto). # Les adresses locales (localhost) ne sont pas redirigées, pour pouvoir tester sans certificat. RewriteCond %{HTTPS} !=on RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC] RewriteCond %{HTTP_HOST} !^(localhost|127\.0\.0\.1)(:\d+)?$ [NC] RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # Facultatif : forcer aussi « www. » (une seule adresse pour Google). Retirez les # des 2 lignes : # RewriteCond %{HTTP_HOST} ^amyevolution\.tn$ [NC] # RewriteRule ^ https://www.amyevolution.tn%{REQUEST_URI} [L,R=301] # Fichiers cachés (.env, .git, .htpasswd…) : interdits, sauf .well-known (certificat SSL Let's Encrypt) RewriteRule (^|/)\.(?!well-known/) - [F,L] # Aucun script PHP ne peut s'exécuter depuis le dossier des images envoyées RewriteRule ^storage/.*\.(php\d?|phtml|phar)$ - [F,L,NC] # Les règles ci-dessous ne s'appliquent que si Laravel est présent (public/index.php) RewriteCond %{DOCUMENT_ROOT}/index.php !-f RewriteRule ^ - [L] # Pages SEO servies par Laravel (titre, description, données Google), même si le .html existe # VERSION 62 : les anciennes adresses .html des pages passent aussi par Laravel (redirection 301 vers /livraison, /contact…) RewriteRule ^(index|product|shop|page|blog|destockage|contact|faq|shipping|returns|warranty|cgv|legal|privacy|cookies)\.html$ index.php [L] # Retirer le / final RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1 [L,R=301] # Tout le reste : fichier existant, sinon Laravel (/api/..., /produit/..., /sitemap.xml, /robots.txt) RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] </IfModule> # Interdire la lecture des fichiers sensibles (réglages, sauvegardes, bases, journaux, scripts) <FilesMatch "^\.|^(artisan|composer\.(json|lock)|package(-lock)?\.json|INSTALLATION\.txt|env\.example\.txt)$|\.(log|sql|sqlite|bak|backup|old|orig|swp|ini|sh|zip|7z|tar|gz|rar)$"> Require all denied </FilesMatch> # Masquer la version du serveur et de PHP ServerSignature Off # Compression des pages, scripts et styles (fichiers ~70 % plus légers) <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/css text/plain application/javascript text/javascript application/json image/svg+xml application/manifest+json </IfModule> <IfModule mod_brotli.c> AddOutputFilterByType BROTLI_COMPRESS text/html text/css text/plain application/javascript text/javascript application/json image/svg+xml </IfModule> # Mise en cache navigateur : images 30 jours, CSS/JS 7 jours, pages HTML toujours fraîches <IfModule mod_expires.c> ExpiresActive On ExpiresByType image/png "access plus 30 days" ExpiresByType image/jpeg "access plus 30 days" ExpiresByType image/webp "access plus 30 days" ExpiresByType image/avif "access plus 30 days" ExpiresByType image/svg+xml "access plus 30 days" ExpiresByType font/woff2 "access plus 1 year" ExpiresByType text/css "access plus 7 days" ExpiresByType application/javascript "access plus 7 days" ExpiresByType text/html "access plus 0 seconds" </IfModule> # Pages HTML, service worker et manifeste : toujours revérifiés (les nouvelles versions s'affichent tout de suite) # CSS/JS : gardés en cache, mais chaque version porte un numéro (?v=47.0) qui force le rechargement <IfModule mod_headers.c> <FilesMatch "\.(html|webmanifest)$|^sw\.js$"> Header set Cache-Control "no-cache, must-revalidate" </FilesMatch> # ---- VERSION 65 : PROTECTIONS DU NAVIGATEUR ---- Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set X-Frame-Options "SAMEORIGIN" # HSTS : le navigateur retient d'utiliser TOUJOURS https:// pendant 1 an (envoyé seulement en HTTPS) Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" "expr=%{HTTPS} == 'on' || %{HTTP:X-Forwarded-Proto} == 'https'" # Caméra, micro, paiement par navigateur… désactivés ; position autorisée seulement pour le site Header always set Permissions-Policy "camera=(), microphone=(), payment=(), usb=(), interest-cohort=(), geolocation=(self)" Header always set Cross-Origin-Opener-Policy "same-origin-allow-popups" Header always set X-Permitted-Cross-Domain-Policies "none" Header always unset X-Powered-By Header unset X-Powered-By # Politique de contenu : seules les sources utilisées par la boutique sont autorisées # (polices Google, Font Awesome, Swiper, Chart.js, cartes Google). Bloque les plug-ins, l'intégration # du site dans un autre site, et transforme automatiquement tout lien http:// restant en https://. Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; img-src 'self' data: blob: https:; media-src 'self' https:; connect-src 'self' https:; frame-src 'self' https://www.google.com https://maps.google.com https://www.youtube.com https://www.youtube-nocookie.com; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; upgrade-insecure-requests" </IfModule>
index.html, product.html et shop.html, sans passer par Laravel. Google ne reçoit alors ni le titre ni la description de chaque produit, et les anciennes adresses ne sont pas redirigées vers les adresses propres (/produit/...).Nginx ne lit pas le fichier .htaccess. Le modèle complet est fourni dans docs/nginx-securite.conf : redirection http → https, redirection sans www → www, certificat Let’s Encrypt, en-têtes de sécurité et fichiers interdits. Remplacez le domaine, les chemins et la version de PHP, puis testez avec sudo nginx -t && sudo systemctl reload nginx. Même sans ce fichier, Laravel force le HTTPS et ajoute les en-têtes (fichier SecureHeaders.php).
# ============================================================ # AMYEVOLUTION — VERSION 65 : exemple nginx (HTTPS obligatoire + sécurité) # À utiliser seulement si l'hébergeur fonctionne avec nginx (nginx ne lit pas le .htaccess). # Remplacez les chemins et le domaine, puis : sudo nginx -t && sudo systemctl reload nginx # ============================================================ # 1) Tout ce qui arrive en http:// part vers https:// (301 définitive) server { listen 80; listen [::]:80; server_name amyevolution.tn www.amyevolution.tn; # Renouvellement du certificat Let's Encrypt location ^~ /.well-known/acme-challenge/ { root /var/www/letsencrypt; } location / { return 301 https://www.amyevolution.tn$request_uri; } } # 2) Sans « www » en https -> avec « www » (une seule adresse pour Google) server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name amyevolution.tn; ssl_certificate /etc/letsencrypt/live/amyevolution.tn/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/amyevolution.tn/privkey.pem; return 301 https://www.amyevolution.tn$request_uri; } # 3) Le site server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name www.amyevolution.tn; root /var/www/amyevolution/public; index index.php index.html; ssl_certificate /etc/letsencrypt/live/amyevolution.tn/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/amyevolution.tn/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; server_tokens off; client_max_body_size 8m; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), payment=(), usb=(), interest-cohort=(), geolocation=(self)" always; # Fichiers cachés et sensibles interdits (sauf .well-known) location ~ /\.(?!well-known) { deny all; } location ~* \.(sql|sqlite|bak|backup|old|orig|swp|log|ini|sh|zip|7z|tar|gz|rar)$ { deny all; } location ~* ^/(artisan|composer\.(json|lock)|package(-lock)?\.json)$ { deny all; } # Aucun PHP dans le dossier des images envoyées location ~* ^/storage/.*\.(php\d?|phtml|phar)$ { deny all; } location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param HTTPS on; fastcgi_pass unix:/run/php/php8.3-fpm.sock; fastcgi_hide_header X-Powered-By; } }
https:// s'ouvre avec le cadenas → 3) seulement ensuite envoyer le .htaccess V65 et la rubrique « Sécurité » du .env. Si la redirection est active sans certificat, les visiteurs voient « Votre connexion n'est pas privée ».Chez le vendeur du domaine, faites pointer les DNS vers l'hébergeur (enregistrements A pour @ et www, ou les serveurs DNS de l'hébergeur). La propagation peut prendre de 1 à 24 heures.
| Type d'hébergement | Comment faire |
|---|---|
| cPanel (mutualisé) | cPanel > SSL/TLS Status > cocher le domaine et www > Run AutoSSL. Renouvellement automatique. |
| Plesk | Sites web et domaines > SSL/TLS Certificates > « Let's Encrypt » > cocher « Inclure www ». |
| VPS Apache | sudo apt install certbot python3-certbot-apache puis sudo certbot --apache -d votre-domaine.tn -d www.votre-domaine.tn |
| VPS nginx | sudo apt install certbot python3-certbot-nginx puis sudo certbot --nginx -d votre-domaine.tn -d www.votre-domaine.tn. Ensuite, reprenez docs/nginx-securite.conf (section 10). |
| Cloudflare devant le site | SSL/TLS > mode Full (strict) (jamais « Flexible », qui crée une boucle de redirection). Le site reconnaît Cloudflare grâce à l'en-tête X-Forwarded-Proto. |
Test du renouvellement automatique (VPS) : sudo certbot renew --dry-run
Ouvrez https://www.votre-domaine.tn : le cadenas doit apparaître, sans alerte.
.htaccess V65 (section 10) dans public/ (ou public_html/). Les lignes « HTTPS FORCÉ » sont déjà actives.backend/env.example.txt dans le .env du serveur (section 7)..env : APP_URL doit être exactement l'adresse finale, avec https et www si vous l'utilisez.php artisan config:clear && php artisan route:clear puis php artisan config:cache.# des 2 lignes « forcer aussi www » du .htaccess (adapter le domaine).# Doit répondre « 301 » et « Location: https://... » curl -I http://www.votre-domaine.tn curl -I http://www.votre-domaine.tn/shop.html # Doit répondre « 200 » avec la ligne strict-transport-security curl -I https://www.votre-domaine.tn
Sans terminal : tapez http://www.votre-domaine.tn dans le navigateur, l'adresse doit devenir https://. Puis notez la sécurité sur https://securityheaders.com (note A attendue) et https://www.ssllabs.com/ssltest/ (note A attendue).
.htaccess redirige avant même que PHP démarre (le plus rapide).app/Http/Middleware/SecureHeaders.php refait la même vérification sur toutes les pages et l'API. Il fonctionne aussi sous nginx. Une page est redirigée en 301 ; un envoi de formulaire en 308 pour ne jamais perdre les données.http://.localhost et 127.0.0.1 ne sont jamais redirigées (tests sur l'ordinateur).| Quand | Destinataire | |
|---|---|---|
| Confirmation de commande | Après une commande | Client |
| Changement de statut | Commande en cours, expédiée, livrée ou annulée, si la case « Prévenir le client » est cochée | Client |
| Commande modifiée | L'administrateur modifie les articles ou l'adresse, avec la case cochée | Client |
| Mot de passe oublié | Le client clique sur « Mot de passe oublié » (le lien ouvre mot-de-passe.html) | Client |
| Alerte administrateur | Nouvelle commande, nouveau message de contact, demande de rappel du chatbot | MAIL_ADMIN_ADDRESS ou email de la boutique |
| Email d'essai | Bouton de test du back office ou php artisan amy:mail-test | Adresse saisie |
Les modèles d'emails se trouvent dans resources/views/emails/*.blade.php.
| Fournisseur | Serveur | Port / chiffrement | Identifiant |
|---|---|---|---|
| Boîte cPanel de votre domaine (conseillé) | mail.votre-domaine.tn | 465 / SSL | adresse email complète |
| OVH (Zimbra / MX Plan) | ssl0.ovh.net | 465 / SSL | adresse email complète |
| Gmail / Google Workspace | smtp.gmail.com | 587 / TLS | adresse + mot de passe d'application (validation en 2 étapes obligatoire) |
| Microsoft 365 | smtp.office365.com | 587 / TLS | adresse complète (SMTP authentifié à activer) |
php artisan amy:mail-test vous@gmail.com
# → « Email d'essai envoyé » ou l'erreur exacte du serveur SMTP
Pour tester sans rien envoyer : MAIL_MAILER=log. Les emails sont alors écrits dans storage/logs/laravel.log.
MAIL_FROM_ADDRESS) doit appartenir à votre domaine._dmarc TXT "v=DMARC1; p=none; rua=mailto:contact@votre-domaine.tn".Elle relance les envois automatiques ratés vers vos logiciels partenaires et nettoie le journal des connecteurs (journal API gardé 90 jours, envois gardés 30 jours).
cPanel > Tâches Cron > « Une fois par minute » (ou toutes les 5 minutes si l'offre l'impose) :
cd /home/votrecompte/amyevolution && /usr/local/bin/php artisan schedule:run >> /dev/null 2>&1
Le chemin de PHP varie selon l'hébergeur (/usr/local/bin/php, /opt/cpanel/ea-php83/root/usr/bin/php…). En SSH, la commande which php le donne. Vérifiez que c'est bien la version 8.2 ou plus.
Les articles de blog programmés n'ont pas besoin du cron : ils apparaissent tout seuls à leur date (dans les 5 minutes, à cause du cache).
Par défaut, le paiement à la livraison fonctionne sans rien configurer. Le serveur recalcule toujours prix, stock, code promo, livraison et total : un client ne peut pas modifier les prix depuis son navigateur.
| Kit | Clés à obtenir auprès du prestataire | Mode test |
|---|---|---|
| Flouci | Clé publique (app public) + clé privée (app secret) | Case « Mode test » du moyen de paiement |
| Konnect | Identifiant du portefeuille (wallet ID) + clé API (x-api-key) | Bac à sable api.sandbox.konnect.network |
| ClicToPay (SMT) | Identifiant API marchand + mot de passe API | Bac à sable test.clictopay.com |
Au retour de la page du prestataire, le site appelle GET /api/v1/payments/verify : le serveur vérifie lui-même le paiement auprès du prestataire avant de marquer la commande comme payée. Un moyen de paiement en ligne n'apparaît au client que lorsque ses clés sont enregistrées.
Ajouter un autre prestataire : créer une classe qui implémente app/Payments/PaymentGateway.php et l'inscrire dans PaymentGatewayRegistry.php.
Sans réglage, le chatbot AMYbot fonctionne entièrement dans le navigateur. Il lit le catalogue, les prix, le stock, la FAQ et les pages Livraison, Retours, Garantie et CGV. Il comprend aussi le tounsi, l'anglais, l'écriture SMS et les fautes de frappe.
Avec une clé d'IA, il formule des réponses plus naturelles. Le serveur lui fournit seulement les produits trouvés en base, les documents et les réglages : il ne peut pas inventer de prix ni de stock.
AI_API_KEY=sk-... # clé du fournisseur AI_BASE_URL=https://api.openai.com/v1 # tout fournisseur compatible OpenAI (Mistral, Groq, OpenRouter…) AI_MODEL=gpt-4o-mini # modèle économique conseillé
POST /api/v1/chatbot/ask), pour maîtriser le coût.Base : https://www.votre-domaine.tn/api/v1. Réponses en JSON. Les limites (« 10/min ») sont par visiteur.
| Adresse | Rôle | Limite |
|---|---|---|
GET /catalog · /catalog.js | Catalogue allégé pour les listes (cache serveur + réponse 304) | — |
GET /products | Filtres : cat, brand, q, min, max, in_stock=1, sort=newest|price_asc|price_desc|popular|rating|name, per_page | — |
GET /products/featured · flash-sale · new · bestsellers | Listes de la page d'accueil | — |
GET /products/{slug ou id} | Fiche complète | — |
GET /products/{id}/related | Produits similaires | — |
GET · POST /products/{id}/reviews | Lire / déposer un avis (publié après modération) | 5/min |
GET /categories · /categories/{slug} · /brands | Catégories et marques | — |
GET /search?q= · /search/suggestions?q= | Recherche (nom, référence, description complète) | 60/min |
POST /orders | Passer une commande (total recalculé par le serveur) | 10/min |
POST /orders/track | Suivi par téléphone + numéro de commande | 30/min |
GET /payments/verify | Retour de la page de paiement | 30/min |
POST /coupons/check | { code, subtotal } → validité du code promo | 20/min |
GET /blog | Articles publiés | — |
POST /contact · /newsletter/subscribe | Formulaire de contact / inscription newsletter (champ piège anti-robots) | 5 · 10/min |
POST /chatbot/ask · GET /chatbot/knowledge · POST /chatbot/log · PATCH /chatbot/log/{id} · POST /chatbot/handoff | Chatbot : réponse IA, documents, questions pour l'apprentissage, pouce haut/bas, demande de rappel | 12 · — · 30 · 30 · 5/min |
POST /auth/register · login · forgot-password · reset-password | Comptes clients | 10/min |
POST /auth/logout · GET /auth/me · PUT /auth/profile · PUT /auth/password · GET /me/orders · /me/wishlist… | Avec Authorization: Bearer <jeton client> (valable 30 jours) | — |
Adresses SEO servies par Laravel : /, /boutique, /produit/{slug}, /categorie/{slug}, /marque/{slug}, /sitemap.xml, /robots.txt. Contrôle de santé : /up.
Connexion : POST /api/v1/admin/login { email, password } → { token, user }. 5 essais par minute au maximum. Le jeton « back-office » est valable 12 heures. Un jeton client de la boutique ne donne pas accès à l'admin.
Toutes les adresses ci-dessous commencent par /api/v1/admin et exigent Authorization: Bearer <jeton admin>.
| Domaine | Adresses |
|---|---|
| Session | POST /logout · GET /me |
| Utilisateurs | GET · POST /users · PUT · DELETE /users/{id} (modification : Super Admin) |
| Commandes | GET /orders (500 plus récentes) · PATCH /orders/{numéro} { status } · PUT /orders/{numéro} · GET /orders/{numéro}/history |
| Produits | GET · POST /products · PUT · DELETE /products/{id} · PATCH /products/{id}/stock |
| Catégories | GET · POST /categories · PATCH /categories/reorder · PUT · DELETE /categories/{id} |
| Marques | GET · POST /brands · PUT · DELETE /brands/{id} |
| Coupons | GET · POST /coupons · PUT · DELETE /coupons/{id} — corps : { code, type: percent|fixed|shipping, value, min, max, expires: AAAA-MM-JJ, active } |
| Blog | GET · POST /blog · PUT · DELETE /blog/{id} |
| Messages et newsletter | GET /messages · PATCH · DELETE /messages/{id} · GET /newsletter · DELETE /newsletter/{id} |
| Avis et clients | GET /reviews · PATCH · DELETE /reviews/{id} · GET · POST /customers · PUT · DELETE /customers/{id} |
| Réglages | GET · PUT /settings · PUT /settings/mail · POST /settings/mail/test · POST /settings/smtp/test · PUT /settings/gateways/{kit} |
| Images | POST /media → { ok, url } (fichier rangé dans storage/app/public/uploads) |
| Chatbot | GET /chatbot · POST /chatbot/questions/bulk · PATCH · DELETE /chatbot/questions/{id} · POST /chatbot/documents · DELETE /chatbot/documents/{id} |
| Connecteurs | GET /connectors · clés : POST /connectors/keys, PATCH · DELETE /connectors/keys/{id}, POST /connectors/keys/{id}/rotate · destinataires : POST /connectors/webhooks, PUT · DELETE /connectors/webhooks/{id}, POST …/{id}/test, POST …/{id}/rotate |
Les connecteurs font travailler le site avec vos autres logiciels, dans les deux sens. Ils exigent HTTPS, CACHE_STORE=database (ou redis) et la tâche cron.
Base : https://www.votre-domaine.tn/api/connect/v1. La clé se crée dans Back office > Connecteurs API. Elle n'est affichée qu'une seule fois.
| En-tête | Valeur |
|---|---|
Authorization | Bearer amy_live_… |
X-Amy-Timestamp | Heure actuelle en secondes UTC (refusée au-delà de 5 minutes d'écart) |
X-Amy-Nonce | 16 à 64 caractères aléatoires, différents à chaque requête (anti-rejeu) |
X-Amy-Signature | HMAC-SHA256 en hexadécimal, calculé avec le code de signature |
Texte à signer, une valeur par ligne :
horodatage
nonce
MÉTHODE
/api/connect/v1/orders?created_from=2026-11-01
sha256(corps) ← corps vide = sha256 de ""
| Action | Adresse | Permission |
|---|---|---|
| Lister / lire les clients | GET /customers · GET /customers/{id} | customers:read |
| Créer / modifier un client | POST /customers · PUT /customers/{id} | customers:write |
| Lister / lire les produits | GET /products · GET /products/{référence} | products:read |
| Modifier prix, stock, désignation | PATCH /products/{référence} · PUT /products (lot de 500) | products:write |
| Lister / lire les commandes | GET /orders · GET /orders/{numéro} | orders:read |
| Créer une commande | POST /orders (external_ref unique : pas de doublon si renvoyée) | orders:write |
Filtres : ?created_from=2026-11-01&created_to=2026-11-30 ou ?updated_since=2026-11-01T00:00:00Z. Pages : ?page=2&per_page=100 (200 maximum). Montants en millimes (3 799,000 TND = 3799000). Dates ISO 8601 en UTC.
Événements : customer.created, customer.updated, nouvelle commande, commande modifiée. En-têtes reçus : X-Amy-Event, X-Amy-Delivery, X-Amy-Timestamp, X-Amy-Signature = HMAC-SHA256(secret, horodatage + "." + corps). Le logiciel doit répondre avec un code 2xx. En cas d'échec, le site réessaie après 1 min, 5 min, 15 min, 1 h, 4 h et 12 h (grâce au cron).
<!--SSR:...--> des pages : titre, description, adresse canonique, Open Graph, données produit (prix, stock, étoiles, livraison, retours) et fil d'Ariane./sitemap.xml (pages, catégories, marques, produits avec images, 5 000 produits par fichier)./robots.txt automatique : bloque admin, panier et compte. Tout est bloqué si APP_ENV n'est pas production./produit/un-produit > clic droit > « Code source » : le titre du produit doit apparaître dans le code.search.google.com/test/rich-results./sitemap.xml.php artisan config:cache && php artisan route:cache && php artisan view:cache après chaque mise à jour.CACHE_STORE=redis si l'hébergeur propose Redis, sinon database.?v=51.0) : augmentez-le après une modification pour forcer le rechargement chez les visiteurs.APP_ENV=production et APP_DEBUG=false.env hors de la racine web, droits 640, jamais envoyé par email.htaccess + SecureHeaders.php, test curl -I http://... → 301)env.example.txt copiée dans le .env (cookies sécurisés)composer update tous les 3 mois, en testant d'abord sur une copie| Fichier | Rôle |
|---|---|
frontend/.htaccess | Redirection http → https, fichiers sensibles bloqués, aucun PHP dans storage/, en-têtes de sécurité (Apache) |
backend/app/Http/Middleware/SecureHeaders.php (nouveau) | Même protection côté Laravel, pour Apache et nginx |
backend/bootstrap/app.php | Active SecureHeaders sur toutes les réponses ; liens générés en https:// en production |
backend/config/shop.php | Nouveau réglage force_https (lit FORCE_HTTPS du .env) |
backend/env.example.txt | Nouvelle rubrique « Sécurité » à copier dans le .env |
docs/nginx-securite.conf (nouveau) | Modèle complet pour les serveurs nginx |
| En-tête | Protection |
|---|---|
Strict-Transport-Security | Le navigateur utilise toujours HTTPS pendant 1 an (envoyé seulement en HTTPS) |
Content-Security-Policy | Seules les sources de la boutique peuvent charger scripts, styles et polices (site, Google Fonts, Font Awesome, Swiper, Chart.js, cartes Google, YouTube). Plug-ins interdits, liens http:// restants passés en https:// |
X-Frame-Options + frame-ancestors | Le site ne peut pas être affiché dans un autre site (anti « clickjacking ») |
X-Content-Type-Options | Le navigateur ne devine pas le type d'un fichier (anti faux fichier image) |
Referrer-Policy | Les adresses complètes ne sont pas transmises aux autres sites |
Permissions-Policy | Caméra, micro, USB et paiement navigateur désactivés ; position autorisée seulement pour le site |
Cross-Origin-Opener-Policy | Isole les fenêtres (les pop-ups de paiement restent possibles) |
Cache-Control: no-store | Compte client, commandes, paiements, admin et connecteurs jamais gardés en cache |
X-Powered-By / ServerSignature | Retirés : les versions d'Apache et de PHP ne sont plus affichées |
Fichiers cachés (.env, .git, .htpasswd…) sauf .well-known (certificat), sauvegardes et archives (.sql .sqlite .bak .old .zip .7z .tar .gz .rar), journaux (.log), .ini .sh, artisan, composer.json/lock, package.json, INSTALLATION.txt, env.example.txt. Les fichiers .php placés dans storage/ ne s'exécutent jamais.
Content-Security-Policy du .htaccess et la fonction csp() de SecureHeaders.php (même liste). Exemple Google Analytics : ajouter https://www.googletagmanager.com dans script-src.| Quoi | Comment | Fréquence |
|---|---|---|
| Base PostgreSQL | cPanel > Sauvegarde > base PostgreSQL, ou pg_dump -Fc -U utilisateur base > amy-$(date +%F).dump | Chaque jour |
| Images importées | storage/app/public/ | Chaque semaine |
Fichier .env | Copie chiffrée dans un coffre (gestionnaire de mots de passe) | À chaque changement |
| Code | Archive du projet (ou dépôt Git privé) | À chaque mise à jour |
Restauration de la base : pg_restore -c -U utilisateur -d base amy-2026-11-08.dump. Testez une restauration sur une base vide au moins une fois.
php artisan down --secret="un-code" (vous gardez l'accès via /un-code).INSTALLATION.txt pour chaque version. Pour frontend/ : penser aussi à la copie dans public_html/frontend/ (piège n°2) et ne jamais écraser le .htaccess fusionné.php artisan migrate --force si la version ajoute une migration.php artisan optimize:clear puis php artisan config:cache && php artisan route:cache && php artisan view:cachephp artisan up, puis vérifier la boutique, une commande test et le back office.| Symptôme | Cause probable | Solution |
|---|---|---|
| Page blanche ou « 500 Server Error » | Erreur PHP, droits, .env | Lire storage/logs/laravel.log. Vérifier les droits de storage/ et bootstrap/cache. Passer APP_DEBUG=true quelques minutes seulement. |
/api/v1/catalog renvoie 404 et la boutique reste en mode démo | .htaccess de Laravel écrasé (piège n°1) | Remettre le .htaccess fusionné (section 10). |
| « could not find driver » | Extension pdo_pgsql absente | L'activer dans le sélecteur PHP de cPanel. |
| « SQLSTATE[08006] connection refused » | Hôte, port ou mot de passe de la base | Vérifier DB_*, essayer localhost au lieu de 127.0.0.1, puis config:clear. |
| « column first_name does not exist » | Migration users de Laravel lancée (piège n°3) | Base vide : supprimer les tables, retirer les 3 migrations d'origine, relancer migrate. |
| Connexion admin : page introuvable après l'identification | Chemins relatifs (piège n°2) | Copie de frontend/ dans public_html/frontend/ et backend/login.html dans public_html/backend/. |
| Connexion admin : « 401 » alors que le mot de passe est juste | En-tête Authorization perdu par Apache | Lignes HTTP_AUTHORIZATION du .htaccess fusionné. |
| Images importées invisibles | Lien storage absent | php artisan storage:link (ou la commande ln -s du cas B). |
| Emails non reçus | SMTP, port bloqué, spam | php artisan amy:mail-test, lire l'erreur, vérifier SPF/DKIM, essayer le port 465 puis 587. |
| Les modifications n'apparaissent pas | Cache serveur ou navigateur | php artisan optimize:clear, augmenter le ?v= des fichiers, rechargement forcé (Ctrl+F5). |
| Google ne voit pas les produits | APP_ENV différent de production, ou pages HTML servies sans Laravel | Vérifier /robots.txt et la règle « Pages SEO » du .htaccess. |
| « 429 Too Many Requests » | Limite anti-robots atteinte | Attendre une minute (normal en cas d'essais répétés). |
| Connecteur API : « signature invalide » | Horloge, texte signé, corps différent | Heure UTC exacte, chemin avec paramètres, sha256 du corps exact envoyé. |
| Kits de paiement ou SMTP illisibles après un déplacement | APP_KEY modifiée | Remettre l'ancienne clé, ou ressaisir les mots de passe et renouveler les clés. |
| « Votre connexion n'est pas privée » (V65) | Redirection HTTPS active mais certificat SSL absent ou expiré | Activer le certificat (section 11). En urgence : FORCE_HTTPS=false dans .env + config:clear, et remettre le # devant les lignes « HTTPS FORCÉ » du .htaccess. |
| « Trop de redirections » / ERR_TOO_MANY_REDIRECTS | Cloudflare en mode « Flexible », ou proxy qui n'envoie pas X-Forwarded-Proto | Cloudflare : SSL/TLS en Full (strict). Proxy nginx : ajouter proxy_set_header X-Forwarded-Proto $scheme;. |
| Une police, une vidéo ou un script ne s'affiche plus (V65) | Bloqué par la politique de contenu (CSP) | F12 > Console : lire l'adresse bloquée et l'ajouter (section 21 bis). |
| Cadenas barré / « contenu mixte » | Image ou lien saisi en http:// dans l'admin | Corriger l'adresse en https:// (la CSP tente déjà de la passer en https automatiquement). |
Erreur 500 juste après l'envoi du .htaccess | Module Apache mod_headers ou mod_rewrite absent, ou directive refusée par l'hébergeur | Demander l'activation à l'hébergeur ; en attendant, mettre un # devant la ligne ServerSignature Off. |
| Commande | Effet |
|---|---|
php artisan amy:create-admin email "Nom" | Créer un Super Admin ou réinitialiser son mot de passe |
php artisan amy:mail-test email | Envoyer un email d'essai |
php artisan amy:connectors-maintenance | Relancer les envois ratés et nettoyer le journal (lancée par le cron) |
php artisan migrate --force | Créer les nouvelles tables |
php artisan migrate:status | Voir les migrations déjà passées |
php artisan db:seed --class=CatalogSeeder | Produits de démonstration (sans doublons) |
php artisan db:seed --class=CouponSeeder | Codes BIENVENUE10 et LIVRAISON |
php artisan storage:link | Lien des images importées |
php artisan optimize:clear | Vider tous les caches |
php artisan config:cache · route:cache · view:cache | Accélérer le site en production |
php artisan route:list --path=api | Lister les adresses de l'API |
php artisan down --secret="code" / php artisan up | Maintenance on / off |
tail -n 100 storage/logs/laravel.log | Lire les dernières erreurs |
https://www.votre-domaine.tn/up répond (Laravel fonctionne)http://www.votre-domaine.tn s'ouvre automatiquement en https:// avec le cadenas (V65)/api/v1/catalog affiche les produits en JSON/backend/login.html avec le compte Super Admin/sitemap.xml et /robots.txt corrects, site déclaré dans Search Console