AAuditPro Suite· Complete manual
Complete manual Deployment + backup

Stack requirements

PHP 8.2.12+strict_types=1 in every file · 8.2-compat syntax (avoid 8.3-only)
MariaDB 10.4+or MySQL 8.0+ · utf8mb4 · use prepared statements
Apache 2.4 + mod_rewriteor nginx + PHP-FPM
PHP extensionspdo_mysql · mbstring · gd · openssl · curl · zip · bcmath · phar · json · session
Composer 2.xFor PSR-4 autoload + dev tools
rcloneFor off-site backup sync (optional but recommended)

First-time install

  1. Clone repo + composer install

    git clone ... && cd acwms-v5 && composer install --no-dev

  2. Create database

    CREATE DATABASE acwms_v5 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

  3. Apply migrations

    php bin/migrate.php

  4. Create config files

    Copy .env.example.env · fill DB credentials. Copy config/database.local.php.exampleconfig/database.local.php + config/communication.local.php.exampleconfig/communication.local.php. Set perms chmod 0600.

  5. Apache vhost

    DocumentRoot must point to public/ only. Nothing above public/ should be web-accessible.

  6. Verify

    Hit /health — expect HTTP 200 with status=ok in < 50ms.

  7. Verify isolation

    Curl /composer.lock · /storage/sessions/ · /config/database.local.php — all should return 404 (proves DocumentRoot isolation).

  8. Storage permissions

    Web user (e.g. www-data) needs write to storage/ tree (NOT to config/).

The 7 production crons

CronSchedulePurpose
cron-backup.phpDaily 00:00db.sql.gz + storage.tar.gz + manifest
cron-offsite-backup.shDaily 00:30rclone sync to remote
cron-m17-email-queue.phpEvery 5 minProcess pending email queue
cron-m17-expiry-reminders.phpDaily 06:00Doc/visa/deadline reminders
cron-m20-deadline-generator.phpDaily 01:30Roll 12-month forward window
cron-m16-retention.phpDaily 00:00Vault retention purge
cron-m13-eosb-accrual.phpLast day of month 23:30EOSB monthly snapshot
cron-m13-leave-carry-forward.php1 January 02:00Leave year-end carry-forward

Linux crontab

# AuditPro Suite production crons
0 0 * * * /usr/bin/php /var/www/acwms-v5/bin/cron-backup.php > /var/log/acwms/backup.log 2>&1
30 0 * * * /var/www/acwms-v5/bin/cron-offsite-backup.sh > /var/log/acwms/offsite.log 2>&1
*/5 * * * * /usr/bin/php /var/www/acwms-v5/bin/cron-m17-email-queue.php > /var/log/acwms/email.log 2>&1
0 6 * * * /usr/bin/php /var/www/acwms-v5/bin/cron-m17-expiry-reminders.php > /var/log/acwms/expiry.log 2>&1
30 1 * * * /usr/bin/php /var/www/acwms-v5/bin/cron-m20-deadline-generator.php > /var/log/acwms/m20.log 2>&1
0 0 * * * /usr/bin/php /var/www/acwms-v5/bin/cron-m16-retention.php > /var/log/acwms/retention.log 2>&1
30 23 28-31 * * /usr/bin/php /var/www/acwms-v5/bin/cron-m13-eosb-accrual.php > /var/log/acwms/eosb.log 2>&1
0 2 1 1 * /usr/bin/php /var/www/acwms-v5/bin/cron-m13-leave-carry-forward.php > /var/log/acwms/leave.log 2>&1

Backup contents

Each nightly backup at storage/backups/{YYYY-MM-DD}/:

7-day local rotation. Cross-platform (Linux + Windows).

Off-site backup

cron-offsite-backup.sh wraps rclone:

Setup is documented in docs/deployment/backup-and-security-plan.md.

Restore from backup

  1. Pull from off-site

    rclone copy {remote}:backups/{YYYY-MM-DD}/ ./restore/

  2. Verify SHA-256

    sha256sum *.gz · compare to manifest.json

  3. Restore DB

    gunzip < db.sql.gz | mysql acwms_v5

  4. Restore storage

    tar xzf storage.tar.gz -C ./ (after backup of current storage)

  5. Verify

    Hit /health · open a known-good engagement · check archive integrity

Quarterly restore drill

Every quarter:

  1. Pick a random backup from off-site
  2. Restore to a sandbox environment
  3. Verify SHA-256 matches manifest
  4. Open the restored engagement · verify report PDF + workpapers + audit log
  5. Log the drill result in backup_drills table

Backup that hasn't been tested = hope, not preparedness.

Health monitoring

Plug /health into:

Hardening checklist

Try this

Run php bin/cron-backup.php manually. Within ~10s, today's backup folder appears at storage/backups/{YYYY-MM-DD}/. Inspect manifest.json. Verify SHA-256 of db.sql.gz matches what's recorded. This is your verifiable disaster-recovery proof.

Watch out

If off-site sync fails 2 nights in a row, you're one disk-failure away from data loss. Configure paging on cron failures. Audit firms have lost their licence over evidence-file destruction. Backup is non-negotiable.

Tip — separate backup user

Create a dedicated MySQL user with only SELECT, LOCK TABLES, and EVENT permissions for the backup cron. mysqldump doesn't need INSERT/UPDATE/DELETE. Reduces blast radius if the backup credentials leak.