File Storage Architecture: Current vs Target¶
Legacy File Storage Architecture (Current State)¶
Before introducing the Asset Service, file handling in the system follows a legacy interaction model. It works, but it comes with several limitations that make it harder to scale, secure, and evolve.
This section explains how file storage currently behaves so you can better understand both existing flows and why changes are being introduced.
How file access works today¶
The frontend sends a session-based request, which is exchanged through Keycloak and then handled by the BFF. For file reads, the BFF resolves metadata and constructs a direct storage path using the bucket name, file ID, and secure file name. The file is then fetched from S3 and may be cached or transformed before being returned.
At the same time, PocketBase still keeps the files metadata and a virtual link to storage. Workers also interact with this legacy model, reading and writing through older paths. Files may be uploaded directly to PocketBase, directly to storage from certain services (e.g. workers), sometimes through the BFF..
The main weakness of this design is that storage access is not fully unified, and public-access storage is still part of the flow.
Role of PocketBase¶
The PocketBase files collection plays a central role in this model.
It stores file identifiers, metadata (owner, usage, relations), a virtual reference to where the file lives in storage. Even though the actual file is stored in S3, PocketBase acts as the source of truth for file metadata and relationships.
Key limitations of the legacy model¶
While functional, this approach introduces several important issues:
- Storage is publicly accessible
- Files in S3 are readable via public access. The only protection is the randomness of file names, which is not a reliable security mechanism.
- Storage logic leaks into the application layer
- The BFF is responsible for constructing storage URLs, which tightly couples application logic with storage structure.
- No unified upload pipeline
- Different parts of the system write files in different ways, making behavior unpredictable and harder to debug.
- Difficult to evolve architecture
-
Because metadata and storage access are tightly linked, it becomes difficult to:
- replace storage backends
- migrate databases (e.g. from PocketBase to PostgreSQL)
- introduce proper access control
Understanding this legacy model is important because many parts of the system still depend on it. The goal of the new architecture is not to break this behavior immediately, but to gradually replace it with a more secure and maintainable approach.
In the next sections, you will see how the Asset Service introduces a cleaner, unified way to handle file reads and writes.
Phase 1: Moving to a Unified File Handling Model¶
Phase 1 introduces a controlled and consistent way of working with files by routing all operations through the Asset Service. The goal is not to replace everything at once, but to remove fragmentation and regain control over how files are stored and accessed.
At the moment, file handling is inconsistent: reads go through the BFF, while writes may bypass it entirely. Storage is also loosely controlled, with public access and logic spread across services. This makes the system hard to secure and even harder to evolve.
What changes in Phase 1¶
The key idea is simple: one service becomes responsible for all file operations.
From now on, any file interaction — whether it is reading, uploading, or updating metadata — should go through the Asset Service. The BFF remains the entry point, but instead of constructing storage paths or interacting with S3 directly, it delegates this responsibility.
For file reads, the behavior does not change much from the outside. The frontend still requests files through the BFF, but internally the BFF now asks the Asset Service for a file URL instead of building it itself. This removes knowledge of storage structure from the application layer.
Writes are where the real shift happens. Uploading files directly to PocketBase or from workers is no longer allowed. All writes must go through the Asset Service, which handles storage and returns a file identifier. That identifier is then used to store metadata in the existing files collection.
Working Smarter with File Storage
Take a look at the Using Views in PocketBase help topic.
What stays the same¶
The files collection in PocketBase is not going away in this phase. It still plays an important role:
- It stores metadata about files
- It maintains relationships used across the system
- It supports existing views and queries
What changes is its responsibility. It no longer needs to know where the file is stored. It only needs to describe the file and reference it via an ID.
What each part of the system needs to do¶
The frontend needs to stop interacting with files directly and instead rely on the new pipeline. File uploads and reads should both go through the BFF, which in turn communicates with the Asset Service.
On the backend, the BFF must be updated to integrate with the Asset Service for both reads and writes. Any logic that constructs storage URLs or accesses S3 directly should be removed.
Workers and ML services also need to follow the same rule. Instead of reading from or writing to PocketBase or storage directly, they should use the Asset Service. This ensures that all file operations behave consistently across the system.
Why this matters¶
This change introduces something the current system lacks: a single source of truth for file operations.
By centralizing file handling:
- storage becomes secure (no more public access assumptions)
- logic is no longer duplicated across services
- future changes, like moving to PostgreSQL or replacing storage, become possible
Most importantly, it allows the system to evolve without breaking existing functionality.