{"result":{"depiction_url":null,"edges":{"in_module":{"objects":[{"created":"2020-05-30T05:48:07Z","object_id":{"id":1329,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_filestore","title":"mod_filestore","uri":"https:\/\/zotonic.com\/id\/1329"},"seq":1000000}],"predicate":{"id":333,"is_a":["meta","predicate"],"name":"in_module","title":{"_type":"trans","tr":{"en":"In module"}},"uri":"https:\/\/zotonic.com\/id\/in_module"}},"refers":{"objects":[{"created":"2026-10-07T21:20:18Z","object_id":{"id":1329,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_filestore","title":"mod_filestore","uri":"https:\/\/zotonic.com\/id\/1329"},"seq":1000000}],"predicate":{"id":2409,"is_a":["meta","predicate"],"name":"refers","title":{"_type":"trans","tr":{"en":"Refers"}},"uri":"https:\/\/zotonic.com\/id\/refers"}},"subject":{"objects":[{"created":"2026-09-09T13:48:09Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-09-09T13:48:09Z","object_id":{"id":2566,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_operator","title":"Operator","uri":"https:\/\/zotonic.com\/id\/2566"},"seq":2},{"created":"2026-09-09T13:48:09Z","object_id":{"id":2581,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_file_storage","title":"File storage","uri":"https:\/\/zotonic.com\/id\/2581"},"seq":3},{"created":"2026-09-09T13:48:09Z","object_id":{"id":2625,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_model","title":"Model","uri":"https:\/\/zotonic.com\/id\/2625"},"seq":4},{"created":"2026-09-09T13:48:09Z","object_id":{"id":2632,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_file_store","title":"File store","uri":"https:\/\/zotonic.com\/id\/2632"},"seq":5},{"created":"2026-09-09T13:48:09Z","object_id":{"id":2689,"is_a":["categorization","keyword","keyword_quality"],"name":"zotonic_topic_reliability","title":"Reliability","uri":"https:\/\/zotonic.com\/id\/2689"},"seq":6}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"export_revision":3493,"id":2140,"is_a":["text","documentation","reference","model"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/2140"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_model_model_filestore","page_url":{"en":"https:\/\/zotonic.com\/docs\/2140\/filestore","x-default":"https:\/\/zotonic.com\/docs\/2140\/filestore"},"preview_url":null,"resource":{"version":3493,"pivot_location_lat":null,"title":"filestore","is_authoritative":true,"body":"<p>Read filestore configuration and statistics through <code>m.filestore<\/code>, for example\n<code>{{ m.filestore.service }}<\/code> or <code>{{ m.filestore.stats.cloud }}<\/code> in an admin template.\nAll model paths below require an administrator context; unauthorized calls return\n<code>{error, eacces}<\/code>. The secret is also unavailable when system configuration is locked.\nSee <a href=\"\/id\/doc_module_mod_filestore\" class=\"doc-reference doc-reference-module\"><code>module#mod_filestore<\/code><\/a> for setup, protocols, configuration precedence and migration.<\/p>\n<h2>File registry and upload queue<\/h2>\n<p>The <code>filestore<\/code> table records each relative local path, its backend (<code>s3<\/code>, <code>ftp<\/code>,\nor <code>webdav<\/code>), full remote URL and size. It also tracks local copies, errors, deletion\nand moves back to local disk. Use the filestore APIs rather than editing the table.<\/p>\n<p>Paths are relative to the site&#39;s files directory, for example\n<code>archive\/2026\/10\/07\/image.jpg<\/code>. Remote locations retain the URL used for upload;\nchanging configuration does not rewrite them or move the remote files.<\/p>\n<p>The <code>filestore_queue<\/code> table holds pending uploads. Entries become eligible after\none minute; bounded background batches and backoff determine when they complete.\nStatistics are database-derived counts and estimates, not remote or local disk scans.<\/p>\n<p>Remote cache reads retain failed entries and retry on demand with exponential\nbackoff (nominally 5 seconds initially, 80–100% jitter, capped at 10 minutes).\nThere is no automatic permanent cutoff. Successful reads reset the error history. Cached copies remain\navailable during a cooldown. A ten-minute database claim limits simultaneous\nprobes across nodes and expires if the worker dies. Only its current token can\nrecord a result. Existing file-serving negative caches can delay the next lookup.<\/p>\n<p><code>health<\/code> reports completed remote cache reads in the current and preceding fourteen\nminute buckets, shared across nodes. A warning requires at least five failures\nand a failure rate of at least 20%. Unresolved errors older than 24 hours also warn.\nUser 1 can mark an error older than 24 hours as unrecoverable. This stops read\nretries and excludes the entry from active error counts, while retaining its\nrecord and details. A new successful upload resets this flag. This action never\ndeletes local or remote files. Historical request-rate statistics remain unchanged.\nCache hits and suppressed retries are excluded. Buckets are retained for one day\nand pruned when the first result of a new minute is recorded.<\/p>\n<h3>Inspecting prolonged errors<\/h3>\n<p>Templates can read <code>m.filestore.prolonged_errors[1]<\/code>. The result is a map with\n<code>entries<\/code>, <code>page<\/code>, <code>previous<\/code>, and <code>next<\/code>. Pages contain at most 50 entries, ordered\nby first failure time and then entry ID. <code>previous<\/code> and <code>next<\/code> are page numbers or\n<code>undefined<\/code>. Invalid or non-positive page numbers select page 1. Deleted entries\nare excluded; unrecoverable entries remain visible. Both this endpoint and\n<code>m.filestore.health<\/code> enforce administrator access and return <code>{error, eacces}<\/code>\nfor unauthorized callers.<\/p>\n<p>The direct Erlang API <code>m_filestore:mark_unrecoverable(Id, Context)<\/code> is used by the\nadmin postback. It requires user 1 and a writable context, and atomically checks\nthat the error is older than 24 hours. It returns <code>ok<\/code>, <code>{error, eacces}<\/code>,\n<code>{error, badarg}<\/code>, or <code>{error, not_eligible}<\/code>. It is not a public model POST path.<\/p>\n<h2>Available Model API Paths<\/h2>\n<table class=\"table\"><thead><tr><th>Method<\/th><th>Path pattern<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>get<\/code><\/td><td><code>\/prolonged_errors\/+page\/...<\/code><\/td><td>Return admin-only pages of 50 unresolved read errors older than 24 hours, oldest first. Includes entry IDs, relative file paths, service, last error, consecutive failure count, first failure time, retry eligibility and unrecoverable status. Marked unrecoverable entries remain listed.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/health\/...<\/code><\/td><td>Return admin-only remote read attempts, failures, high-error-rate flag, and unresolved\/prolonged error counts.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/stats\/...<\/code><\/td><td>Return admin-only filestore totals: archived media count\/size, queued upload count, queued move\/delete counts, cloud-stored count\/size, and estimated local count\/size.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/service\/...<\/code><\/td><td>Return the configured filestore backend service identifier from <code>filestore_config:service\/1<\/code> (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/s3url\/...<\/code><\/td><td>Return the configured S3, FTP\/FTPS or WebDAV base URL used for remote object location resolution (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/s3region\/...<\/code><\/td><td>Return the S3 signing region; empty selects Signature V2 (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/s3key\/...<\/code><\/td><td>Return the configured S3 access key or FTP\/WebDAV username for filestore credentials (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/s3secret\/...<\/code><\/td><td>Return the configured S3 secret key or FTP\/WebDAV password only when caller is admin and filestore config is not locked.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/is_config_locked\/...<\/code><\/td><td>Return whether filestore credential\/config values are locked (non-editable\/hidden) in this site instance (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/is_read_only\/...<\/code><\/td><td>Return the effective download-only restriction (admin-only). Global and site-file restrictions cannot be overridden by database settings.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/is_upload_enabled\/...<\/code><\/td><td>Return whether background upload\/offload from local <code>files<\/code> storage to remote filestore is enabled (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/is_local_keep\/...<\/code><\/td><td>Return whether local files are retained after successful remote storage, instead of being scheduled for deletion (admin-only).<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/delete_interval\/...<\/code><\/td><td>Return the configured extra delay before deleting files marked for remote deletion (admin-only).<\/td><\/tr><\/tbody><\/table>\n<p><code>\/+name<\/code> marks a variable path segment. A trailing <code>\/...<\/code> means extra path segments are accepted for further lookups.<\/p>","slug":"filestore","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"8bba5f09ebacc8743fa58a6b7de69868447e02fa98e8ad10c7c3e436a13f39b8","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":322,"is_a":["meta","category"],"name":"model","title":"Models","uri":"https:\/\/test.zotonic.com\/id\/322"},"doc_source_path":"apps\/zotonic_mod_filestore\/src\/models\/m_filestore.erl","publication_start":"2023-01-30T19:23:57Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/apps\/zotonic_mod_filestore\/src\/models\/m_filestore.erl","pivot_location_lng":null,"doc_source_kind":"model","name":"doc_model_model_filestore","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2020-05-30T05:48:07Z","uri":null,"doc_status":"current","is_dependent":false,"erlang_app":"zotonic_mod_filestore","publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"f3c6a9a2dde17cb5b121dd3e3018d9ef4b1b3943\n","erlang_module":"m_filestore","creator_id":{"id":336,"is_a":["person","robot"],"name":"gitbot","title":"Git","uri":"https:\/\/zotonic.com\/id\/336"},"modified":"2026-11-09T21:39:43Z","title_slug":"filestore"},"uri":"https:\/\/zotonic.com\/id\/2140","uri_template":"https:\/\/zotonic.com\/id\/:id","version":3493,"websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/2140"}},"status":"ok"}