# Export Storage Readiness

## Current Mode

Async export result files are written to `EXPORT_STORAGE_DIR`. Metadata remains in Postgres table `export_jobs`.

Required production properties:

- Absolute path, for example `/var/lib/qris/exports`.
- Writable by the app/worker process.
- Included in backup or mounted on durable storage.
- Same mount visible to all app instances that serve `GET /admin/exports/:jobId/download`.

## Single-Node Pilot

Recommended:

```bash
EXPORT_STORAGE_DIR=/var/lib/qris/exports
EXPORT_RETENTION_DAYS=7
```

Filesystem setup example:

```bash
sudo mkdir -p /var/lib/qris/exports
sudo chown <app-user>:<app-group> /var/lib/qris/exports
sudo chmod 750 /var/lib/qris/exports
```

## Multi-Node Production

Do not use node-local disk unless traffic is sticky to the same node that processed the export job.

Preferred options:

- Shared filesystem mounted at the same `EXPORT_STORAGE_DIR` on every app node.
- S3-compatible object storage adapter in a future implementation.

Until object storage exists, run one export worker/app instance or ensure all download-serving instances share the export directory.

## Retention

Worker clears downloadable file references after `EXPORT_RETENTION_DAYS`. If a finance user needs an expired file, create a new export job.

## Validation

```bash
npm run deploy:check-env
POST /admin/exports/settlement-adjustments
GET /admin/exports/:jobId
GET /admin/exports/:jobId/download
```

Check `/admin/observability/summary` for worker state and export job counts.
