Android Cast — crash reporter backend deployment (checklist)
================================================================

PUBLIC URL (example)
  https://apps.f0xx.org/app/androidcast_project/crashes/
  Upload API: .../crashes/api/upload.php

FILES ON VM
  Deploy backend so web root is:
    .../androidcast_project/backend/public/
  Symlink is fine, e.g.:
    backend -> android_cast/examples/crash_reporter/backend/

  config: backend/config/config.php  (copy from config.example.php)
  DB (SQLite default): backend/data/crashes.sqlite
  Writable dirs: backend/data/  backend/storage/

ALPINE + PHP-FPM 8.1 (required modules)
  apk add php81-fpm php81-session php81-pdo php81-pdo_sqlite php81-sqlite3
  rc-service php-fpm81 restart
  Verify FPM (not only CLI): php-fpm81 -m | grep -E 'session|pdo_sqlite|PDO'
  If "session_name() undefined" -> php81-session missing or FPM not restarted

INIT DB (SQLite)
  mkdir -p backend/data backend/storage
  sqlite3 backend/data/crashes.sqlite < backend/sql/schema.sqlite.sql
  chown -R www-data:www-data backend/data backend/storage   # user = php-fpm pool user

config.php
  base_path MUST match URL prefix exactly:
    'base_path' => '/app/androidcast_project/crashes'
  (empty base_path only for local: php -S -t public)

INNER NGINX (VM behind reverse proxy)
  - ONE location for the app prefix only:
      location ^~ /app/androidcast_project/crashes/ {
        alias .../backend/public/;
        try_files + nested .php -> php-fpm socket
      }
  - See: examples/crash_reporter/backend/nginx.vm.conf
  - DO NOT mix proxy_*, try_files, and fastcgi in one broken /app/androidcast_project/ block
  - DO NOT set root = androidcast_project/ for crash URLs (doubles path on disk)
  - Optional redirects:
      /app/androidcast_project/ -> /app/androidcast_project/crashes/
  - fastcgi_pass: unix:/run/php-fpm.socket  (match your install)
  - client_max_body_size 4m (upload JSON)
  - Every adb/php-fpm call: use </dev/null if testing from scripts (not required in nginx)

OUTER REVERSE PROXY (apps.f0xx.org -> artc0 VM)
  - proxy_pass with full URI preserved
  - proxy_set_header Host $host;
  - proxy_set_header X-Forwarded-Proto $scheme;
  - TLS terminate at outer nginx

ANDROID APP (device settings.json)
  "crash": {
    "enabled": "true",
    "upload_url": "https://apps.f0xx.org/app/androidcast_project/crashes/api/upload.php",
    "prune_after_upload": "true",
    "upload_interval": "5m"
  }
  Enable "Send anonymous crash logs" in app settings.

SMOKE TESTS
  curl -vk -H 'Host: apps.f0xx.org' \
    https://127.0.0.1/app/androidcast_project/crashes/

  curl -vk -H 'Host: apps.f0xx.org' -H 'Content-Type: application/json' \
    -d '{"schema_version":1,"report_id":"test","generated_at_epoch_ms":1,"crash_type":"java","fingerprint":"x","device":{},"app":{}}' \
    https://127.0.0.1/app/androidcast_project/crashes/api/upload.php

  Web UI login (change in prod): admin / admin

COMMON MISTAKES
  - 400 on GET /app/androidcast_project/ only -> health check wrong path; add redirect or ignore
  - 500 session_name() -> install php81-session for FPM
  - Location /crashes/ without /app/androidcast_project/ prefix -> no match behind full URI proxy
  - "Primary script unknown" in nginx error log:
      php-fpm got a SCRIPT_FILENAME that does not exist on disk
      usual cause: fastcgi.conf + alias + try_files (wrong path)
      fix: examples/crash_reporter/backend/nginx.vm.conf (explicit paths, fastcgi_params)
      verify: ls .../backend/public/index.php
      compare: php-fpm pool user can read that file
  - Pending reports deleted before pull: prune_after_upload uploads then deletes on device

CURL WHERE
  127.0.0.1 tests only ON the VM (loopback on that machine)
  From laptop use: curl -vk https://apps.f0xx.org/app/androidcast_project/crashes/
  -H Host only needed when URL is 127.0.0.1 but vhost is apps.f0xx.org

PULL REPORTS FROM DEVICE (laptop)
  ./pull_stats.sh  (also pulls log_capture/crash_reports/<serial>/)

PROD HARDENING (when ready)
  - Change admin password (users table password_hash)
  - TLS only, restrict /api/upload.php by firewall if desired
  - MariaDB: use sql/schema.mariadb.sql + db.driver mysql in config.php
  - nginx/php-fpm error logs: check on 500, not only access log

REF IN REPO
  examples/crash_reporter/backend/README.md
  examples/crash_reporter/backend/nginx.vm.conf
  docs/CRASH_REPORTER.md
