Files
xamxam/docs/MIGRATION_CHECKLIST.md
Théophile Gervreau-Mercier 4bbbc58e24 Fix admin CSS not loading and quirks mode issues
Fixed multiple issues in admin panel:

1. CSS path: modern-normalize.css → modern-normalize.min.css
   (File is actually named .min.css)

2. Icon path: assets/icon.svg → /assets/admin_favicon.svg
   (Was relative, now absolute; correct filename)

3. Navigation: /admin/list.php → /admin/
   (list.php was renamed to index.php)

4. Short PHP tags: <? → <?php
   (Better compatibility, some servers don't enable short_open_tag)

5. Quirks mode warning was due to CSS not loading, not DOCTYPE
   (DOCTYPE was already present)

Files modified:
- public/admin/inc/head.php (main fixes)
- public/admin/index.php (short tags)
- public/admin/add.php (short tags)
- public/admin/import.php (short tags)

Need to redeploy for production: just deploy
2026-02-06 13:26:24 +01:00

9.3 KiB

Migration Checklist - Public Directory Structure

Quick reference for migrating from current flat structure to secure public/ structure.

📋 Summary of Required Changes

1. Dev Server (justfile)

Line 51 - Change from:

@php -S 127.0.0.1:8000

To:

@php -S 127.0.0.1:8000 -t public/

2. Deployment (justfile) 📤

Lines 56-75 - Replace entire deploy recipe with two-step deployment:

  • Deploy app to /var/www/posterg/ (not /var/www/html/)
  • Nginx serves from /var/www/posterg/public/

See DEPLOYMENT_MIGRATION.md for complete updated recipe.

3. Nginx Configuration 🔧

nginx/posterg.conf line 14 - Change from:

root /var/www/html;

To:

root /var/www/posterg/public;

Also update admin location (line 58) - Change from:

location ^~ /formulaire/ {

To:

location ^~ /admin/ {

(Since you're moving admin/ to public/admin/)


🚀 Quick Migration (Local Dev)

# 1. Update justfile serve command
sed -i 's/@php -S 127.0.0.1:8000/@php -S 127.0.0.1:8000 -t public\//' justfile

# 2. Test new dev server
just serve
# Visit http://localhost:8000
# Verify http://localhost:8000/database/test.db returns 404

# 3. If it works, you're ready for production migration

📁 File Movements (Do This After Testing)

# Create new structure
mkdir -p public/{admin,assets}
mkdir -p src config var/{cache,logs,tmp}

# Move public files
mv index.php search.php memoire.php public/
mv admin/* public/admin/ && rmdir admin
mv assets/* public/assets/ && rmdir assets

# Move private files  
mv inc/* config/ && rmdir inc
# OR if inc/ contains classes:
# mv inc/* src/ && rmdir inc

# Keep these as-is
# database/ (already private)
# vendor/ (already private)
# tests/ (already private)
# lib/ (decide if it goes to src/lib or stays)

⚠️ Critical Changes Required

In nginx/posterg.conf:

  1. Line 14 - DocumentRoot
# BEFORE
root /var/www/html;

# AFTER  
root /var/www/posterg/public;
  1. Line 58-76 - Admin location (already at /formulaire/, might want /admin/)
# BEFORE
location ^~ /formulaire/ {
    auth_basic "Admin Access - Post-ERG";
    auth_basic_user_file /etc/nginx/.htpasswd-posterg;
    # ... rest of config
}

# AFTER (if renaming to /admin/)
location ^~ /admin/ {
    auth_basic "Admin Access - Post-ERG";
    auth_basic_user_file /etc/nginx/.htpasswd-posterg;
    # ... rest of config
}
  1. Remove/update deny rules (lines 48-60) - These become redundant!
# BEFORE - needed because everything in DocumentRoot
location ^~ /database/ { deny all; }
location ^~ /shared/ { deny all; }
location ^~ /data/ { deny all; }

# AFTER - can remove! They're already outside public/
# But keep as defense-in-depth:
location ^~ /database/ { deny all; }  # Will never match, but safe

In justfile:

Complete replacement for lines 40-76:

[group('dev')]
serve:
    @echo "🚀 Starting Post-ERG development server"
    @echo "========================================"
    @echo ""
    @echo "📍 Public site:  http://localhost:8000"
    @echo "📍 Admin panel:  http://localhost:8000/admin/"
    @echo ""
    @echo "🔒 Serving from public/ directory (matches production)"
    @if [ -d "vendor/php-live-reload" ]; then \
        echo "✨ Live reload enabled"; \
    else \
        echo "💡 Tip: Run 'just setup' to enable live reload"; \
    fi
    @echo ""
    @echo "Press Ctrl+C to stop"
    @echo ""
    @php -S 127.0.0.1:8000 -t public/

[group('deploy')]
deploy:
    @echo "📤 Deploying Post-ERG complete site"
    @echo "===================================="
    @echo ""
    @echo "Deploying to /var/www/posterg/..."
    rsync -vur --progress \
        --chown="www-data:posterg" \
        --exclude 'vendor' \
        --exclude 'tests' \
        --exclude 'test.db' \
        --exclude '*.md' \
        --exclude '.git*' \
        --exclude '.jj' \
        --exclude '.DS_Store' \
        --exclude 'justfile*' \
        --exclude 'setup-dev.sh' \
        --exclude 'database/backup_*' \
        --exclude 'database/fixtures' \
        --exclude 'var/cache/*' \
        --exclude 'var/logs/*' \
        ./ posterg:/var/www/posterg/
    @echo ""
    @echo "Setting up directories and permissions..."
    ssh posterg "cd /var/www/posterg && \
                 mkdir -p var/{cache,logs,tmp} && \
                 chown -R www-data:posterg var/ database/ && \
                 chmod -R 775 var/ database/ && \
                 chmod 660 database/*.db"
    @echo ""
    @echo "✅ Deployment complete!"
    @echo ""
    @echo "🔍 Verify:"
    @echo "  • Public: https://posterg.erg.be/"
    @echo "  • Admin:  https://posterg.erg.be/admin/"

[group('deploy')]
test-deploy:
    @echo "⚠️  Deploying test database"
    ssh posterg "mkdir -p /var/www/posterg/database"
    rsync -vur --progress ./database/test.db posterg:/var/www/posterg/database/
    ssh posterg "chown www-data:posterg /var/www/posterg/database/test.db && \
                 chmod 660 /var/www/posterg/database/test.db"
    @echo "✅ Test database deployed"

🧪 Testing Steps

1. Test Local Dev Server

# Start server with new -t public/ flag
just serve

# In another terminal:
curl http://localhost:8000/                    # ✅ Should work
curl http://localhost:8000/admin/              # ✅ Should work (after moving)
curl http://localhost:8000/database/test.db    # ❌ Should 404
curl http://localhost:8000/config/             # ❌ Should 404
curl http://localhost:8000/vendor/             # ❌ Should 404

2. Test After File Migration

# After moving files to public/
just serve

# Test again
curl http://localhost:8000/                    # ✅ index.php serves
curl http://localhost:8000/search.php          # ✅ works
curl http://localhost:8000/admin/              # ✅ works
curl http://localhost:8000/assets/css/style.css # ✅ works

# Verify old paths don't work
curl http://localhost:8000/../database/test.db # ❌ 404
curl http://localhost:8000/../config/          # ❌ 404

3. Test Production Deployment

# After deploying to server
just server-status

# Manual checks
curl -I https://posterg.erg.be/
curl -I https://posterg.erg.be/admin/
curl -I https://posterg.erg.be/database/test.db  # Must be 404!

📝 PHP Path Updates Needed

After moving to public/, update PHP includes:

Before (from root):

<?php
require_once 'inc/config.php';
require_once 'lib/Database.php';
require_once 'database/test.db';

After (from public/):

<?php
require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../src/lib/Database.php';
$db = new PDO('sqlite:' . __DIR__ . '/../database/test.db');

Or use a bootstrap:

<?php
// public/index.php
require_once __DIR__ . '/../config/bootstrap.php';

// config/bootstrap.php
define('APP_ROOT', dirname(__DIR__));
define('PUBLIC_ROOT', APP_ROOT . '/public');
define('DATABASE_PATH', APP_ROOT . '/database/test.db');

require_once APP_ROOT . '/vendor/autoload.php';

🔍 What to Check in Your Code

Run these searches to find hardcoded paths:

# Find absolute paths
grep -r "/var/www/html" ./*.php
grep -r "/var/www/html" ./admin/*.php

# Find relative paths that need updating
grep -r "require.*inc/" ./*.php
grep -r "require.*lib/" ./*.php
grep -r "require.*database/" ./*.php

# Find database connections
grep -r "\.db" ./*.php

# Find asset references
grep -r "src=\"assets/" ./*.php
grep -r "href=\"assets/" ./*.php

Quick Start (Minimal Changes First)

If you want to test with minimal changes:

1. Only change dev server:

# Edit justfile line 51
@php -S 127.0.0.1:8000 -t public/

# Create public/ with symlinks (temporary test)
mkdir public
ln -s ../index.php public/index.php
ln -s ../search.php public/search.php
ln -s ../admin public/admin
ln -s ../assets public/assets

# Test
just serve

2. If it works, do full migration


🆘 Rollback Plan

If production deployment fails:

# On server
sudo systemctl stop nginx

# Restore old config
sudo cp /etc/nginx/sites-available/posterg.backup /etc/nginx/sites-available/posterg
sudo nginx -t
sudo systemctl start nginx

# Or restore files
sudo rm -rf /var/www/posterg
sudo mv /var/www/html.backup /var/www/html

Always backup before deploying:

# Before migration
ssh posterg "sudo cp -r /var/www/html /var/www/html.backup"
ssh posterg "sudo cp /etc/nginx/sites-available/posterg /etc/nginx/sites-available/posterg.backup"

📊 Benefits After Migration

Before After
All files in DocumentRoot Only public/ in DocumentRoot
Database accessible if nginx misconfigured Database physically unreachable
Config files one deny rule away Config files outside web root
20+ deny/exclude rules needed Physical separation, minimal rules
Dev server exposes everything Dev matches production security

Next: Check Your Current Paths

Run this to see what paths need updating:

# Find all require/include statements
find . -name "*.php" -not -path "./vendor/*" -not -path "./tests/*" \
  -exec grep -H "require\|include" {} \; > paths-audit.txt

# Review paths-audit.txt and update paths
cat paths-audit.txt

See DEPLOYMENT_MIGRATION.md for complete implementation details.