Production and multi-node operation
The default file-backed stores are deliberately simple and safe for one PHP application node. A multi-node deployment must share object storage and runtime state; do not point independent local stores at each node and expect quota, metadata or rate limits to remain consistent.
Database or Redis state
PdoAtomicStateStore supports SQLite for local integration tests and MySQL or PostgreSQL for shared deployments. RedisAtomicStateStore uses ext-redis and a bounded exclusive lock. Both implement AtomicStateStoreInterface; compose one with:
SharedMetadataStorefor favorites, tags and recent files;SharedRequestGateStorefor cross-node request/concurrency limits;SharedUsageTrackerfor atomic quota accounting.SharedMetricsStorefor cluster-wide Prometheus counters;- shared maintenance leases, status and chunk-session coordination.
Create the PDO store once with the host-owned connection; it creates the portable sofinder_state table automatically, or call install() during deployment. Register the host-owned state object as a Symfony service. Connection credentials, retry policy and TLS settings remain outside bundle configuration.
$state = new PdoAtomicStateStore($pdo);
$metadata = new SharedMetadataStore($state);
$gates = new SharedRequestGateStore($state);
$usage = new SharedUsageTracker($state);For Redis:
$state = new RedisAtomicStateStore($redis, 'myapp:sofinder:');so_finder:
cluster:
state_service: 'app.sofinder_shared_state'
chunk_upload_store_service: 'app.sofinder_shared_chunks' # optional
shared_preview_cache: true # only after mounting cache_dir/document-previewsstate_service automatically replaces metadata, request-gate, usage and metrics stores, and enables shared maintenance and chunk-session coordination. /health then performs an atomic shared-state read/write probe. The configured services implement AtomicStateStoreInterface and ChunkUploadStoreInterface.
Chunk bytes still need chunk_dir mounted as the same shared private filesystem on every node, or a host implementation of ChunkUploadStoreInterface. Remote recycle behavior belongs to the storage provider (for example bucket versioning); state storage is not a substitute for file recovery.
ClamAV
Enable the built-in ClamAV integration in SoFinder configuration. It streams the private quarantine file to clamd's INSTREAM protocol, invokes no shell and fails closed.
so_finder:
malware_scanning:
enabled: true
endpoint: 'unix:///run/clamav/clamd.ctl'
timeout_seconds: 8
history_limit: 100
status_roles: [ROLE_ADMIN]Rejected files return malware_detected; unavailable or ambiguous scanners return malware_scanner_unavailable and the quarantine file is removed. The Security status dialog and GET /api/security/status show the configured state, live clamd readiness, bounded recent results and counts. Prometheus also exports scan count, scanned bytes and cumulative duration counters by result.
Readiness and metrics
GET /healthchecks private runtime paths, built assets, image codecs, maintenance mode, every storage resource and tagged plugin checks.downreturns HTTP 503;degradedremains HTTP 200.GET /liveonly proves that PHP and the bundle initialized; it returns only{"success":true,"data":{"status":"ready"}}. Allow this exact route through the host firewall for orchestrator probes; it does not expose versions, paths, storage, queue or external-service details.GET /metricsexposes bounded Prometheus counters, storage latency totals and observations, Office queue/conversion/cache activity, ClamAV timeouts, queue backlog/failed gauges, upload failures, limiter rejections andsofinder_ready.- Every SoFinder response includes
X-Request-ID. A safe incoming value is preserved; otherwise SoFinder creates one. Audit and failure logs include it.
Keep health and metrics behind an internal firewall or dedicated monitoring role. Neither endpoint exposes credentials or absolute storage paths, but resource names and operational status are still administrative information.
Release checks
Run the security audit, health request, metrics scrape, usage recalculation and one real upload/read/delete cycle from every deployment environment. For local testing, the Symfony example exposes /integrations, /sofinder/health and /sofinder/metrics behind demo / demo authentication.