> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erp.arukz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Operate ARUKZ ERP: caches, backups, debugging

> Running a copy of ARUKZ ERP day to day: run artisan as www-data, rebuild caches and reload PHP-FPM after changes, nightly backups and restore, and debugging.

Running ARUKZ ERP comes down to four habits: run `artisan` as `www-data`, reload PHP-FPM after every code change, rebuild the caches after every code or `.env` change, and rebuild the front-end after CSS or Blade class changes. Backups run every night at 01:30 and keep the newest 14 dumps; copy them off the server yourself. The commands below use `erp` as the Docker Compose service name from [Self-hosting with Docker](https://docs.erp.arukz.com/developers/self-hosting-docker.md).

## Four rules

> [accordion] 1. Run artisan as www-data, never as root
>
> `docker exec` runs as root by default. Files root creates in `storage/` or `bootstrap/cache/` cannot be rewritten by PHP-FPM, and random pages then fail with `touch(): Utime failed: Operation not permitted`.
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
> docker compose exec -u www-data -w /var/www/aureuserp erp php artisan <command>
> ```
>
> If it already happened, give the folders back:
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
> docker compose exec erp chown -R www-data:www-data /var/www/aureuserp/storage /var/www/aureuserp/bootstrap/cache
> ```

> [accordion] 2. Reload PHP-FPM after a code change
>
> PHP opcache runs with `validate_timestamps = 0`, so PHP never re-reads a file it has compiled, Blade views included. A change does nothing until PHP-FPM reloads. A graceful reload that drops no requests:
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
> docker compose exec erp sh -c 'kill -USR2 $(pgrep -o php-fpm)'
> ```

> [accordion] 3. Keep the caches warm
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
> php artisan optimize           # config, routes, events, views
> php artisan filament:optimize  # Filament components and icons
> ```
>
> Measured on ARUKZ's server, they took the public home page from 316 ms to 54 ms and admin pages from about 0.6 s to 0.3 s. Config is cached, so a changed `.env` does nothing until `optimize` runs again. Clear them with `optimize:clear` and `filament:optimize-clear`.

> [accordion] 4. The front-end is compiled
>
> The public pages and the panel theme are built by Vite into `public/build/` with `npm run build`. Run it after changing CSS or Tailwind classes in Blade files. The home page's icon font is subset by name: a new Material Symbol must be added to the `icon_names=` list in `resources/views/landing/index.blade.php`, or it shows as its name.

## Logs

Application errors go to `storage/logs/laravel.log`. Count the distinct errors instead of scrolling:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
grep -oE '^\[[0-9-]+ [0-9:]+\] [a-z]+\.[A-Z]+: .{0,200}' storage/logs/laravel.log \
  | sed -E 's/^\[([0-9-]+) [0-9:]+\]/\1/' | sort | uniq -c | sort -rn | head -30
```

## Scheduled jobs

The scheduler (`schedule:work`, run by Supervisor) runs these every day:

| Time | Command | Does |
| - | - | - |
| 01:15 and 01:25 | `audit:anchor`, `audit:anchor --verify` | Seals the day's audit-trail events into a hash chain, then checks the chain |
| 01:30 | `saas:backup` | Dumps the database |
| 02:00 | `saas:issue-renewals` | Raises renewal invoices for subscriptions ending soon |
| 03:00 | `model:prune` | Deletes expired company data exports |

The queue worker (`queue:work`) builds company data exports and posts stock valuation entries when the stock ledger is on. If those stop, check it under Supervisor before anything else.

## Backups and restore

`saas:backup` writes `storage/app/backups/<database>_<timestamp>.sql.gz`, checks it, and keeps the newest 14 (`SAAS_BACKUPS_KEEP`). The platform operator's home page shows the age of the last one and turns red after 26 hours; set `SAAS_OPS_EMAIL` with working mail to be told when a run fails.

These dumps sit on the same server as the database, so copy them elsewhere every night (for example with `rsync` from another machine). To restore one:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
gunzip -c storage/app/backups/<file>.sql.gz \
  | docker compose exec -T -e MYSQL_PWD="$DB_PASSWORD" erp mysql -u "$DB_USERNAME" "$DB_DATABASE"
```

Then rebuild the caches and reload PHP-FPM.

## Debugging

| Symptom | Look at |
| - | - |
| A page shows 500 | The log. If it names a missing `Filament\...` class, it is Filament 3 code; see the class table in [Build a custom plugin](https://docs.erp.arukz.com/developers/custom-plugin.md) |
| Every page is 500 right after an artisan command | Rule 1: files owned by root |
| A change does not show | Rule 2, then rule 3, then `npm run build` for CSS |
| The public page says `Vite manifest not found`, or panel buttons do nothing | Build output is missing: run `npm ci && npm run build`, and if `vendor/livewire/livewire/dist` is gone, reinstall Livewire and Filament with Composer |
| Slow page | Count its queries: most admin pages run 15 to 30 in about 30 ms, so slowness with fast SQL is PHP rendering |
| Can company B see company A's data? | Write a test like `tests/Feature/Saas/TenantIsolationTest.php`: two companies' admins, sign in as one, assert the other's IDs are absent |

A quick health check: `/up`, `/`, `/admin/login` and `/saas/register` should all answer `200`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.