HELP — Setup, Run & Ops

All project docs render at /docs on the site. This file is the ops manual.

1. Requirements

  • PHP 8.3+ (extensions: pdo_mysql, gd, curl, intl, opcache)
  • MariaDB 10.11+ (this host has it)
  • Nginx (+ certbot) on the production host
  • Composer (optional — a built-in autoloader fallback exists)

2. First-time setup (host)

# 1) code at /home/fla — docroot is /home/fla/public
# 2) environment
cp .env.example .env            # then edit values (never commit .env)
# 3) database (one-time, as root)
mariadb -u root <<'SQL'
CREATE DATABASE IF NOT EXISTS fla_event CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'fla'@'%' IDENTIFIED BY '<strong-password>';
GRANT ALL PRIVILEGES ON fla_event.* TO 'fla'@'%';
FLUSH PRIVILEGES;
SQL
# 4) tables + seeds
./database/migrate.sh           # uses DB_* env overrides if needed
# 5) autoloader (optional optimization)
composer dump-autoload -o
# 6) writable runtime dirs
mkdir -p storage/{cards,uploads,cache,logs} && chmod -R 775 storage

3. Web server — subdomain on plain 443

Nginx server block (template also kept in the repo under deploy/nginx.conf):

server {
    listen 80;
    server_name event.production1.jugaar.ai;
    root /home/fla/public;
    index index.php;
    location / { try_files $uri $uri/ /index.php?$query_string; }
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
    location ~ /\. { deny all; }
}

Then HTTPS (plain 443, no ports):

certbot --nginx -d event.production1.jugaar.ai   # creates :443 vhost + auto-redirect

APP_URL in .env must stay https://event.production1.jugaar.ai — share links use absolute_url() so they're always canonical.

4. Daily ops

TaskCommand / location
Health checkcurl https://event.production1.jugaar.ai/health
Docs in browserhttps://event.production1.jugaar.ai/docs
QA suite (29 checks)./bin/qa.sh
Re-run migrations./database/migrate.sh (idempotent; reads creds from .env)
Demo share cardsphp bin/card-demo.php → PNGs in storage/cards/
Logs (app)PHP error log (fpm) + storage/logs/whatsapp.log
Back up DBmysqldump fla_event > db-dump-$(date +%F).sql (nightly cron recommended — git-ignored)

5. Feature toggles & branding

  • feature_toggles table: branding.panel, registration.*, ai.qa, voting,

cards.gd, judges.panel, tickets, comms.mass, winners.announce, audit.ui, docs.public.

  • settings table: brand.name, brand.tagline, brand.primary_color,

brand.logo_path, campaign.{applied|visiting|winner}_text (placeholders {event} {name} {category}), voting.weight_{public|admin}, voting.mode, vote.reason_enabled.

  • From v0.2.0 these are edited in /admin/branding — until then SQL is fine.

6. External keys (when they arrive)

KeyPut in .envEffect
MiniMaxAI_API_KEY, AI_BASE_URL, AI_MODEL, AI_MOCK=falselive AI interviews
LinkedInLINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRETreal OAuth
WhatsAppWHATSAPP_PROVIDER, WHATSAPP_API_KEYreal messaging
SMTP/mail(added alongside comms milestone)real emails

7. Troubleshooting

  • 500 on every page → check .env exists, PHP fpm socket path in nginx, then error log.
  • "View not found" → route references a missing views/… file; check module.
  • DB down/health shows db:down; verify fla grants + DB_* values.
  • Cards blank text → DejaVu font missing at /usr/share/fonts/truetype/dejavu/

(GD falls back to a small built-in font).

  • Migrations fail → run mariadb fla_event manually and execute the failing file to see the error.