Service Layer low complexity mobile
1
Dependencies
2
Dependents
1
Entities
1
Integrations

Description

Generates time-limited signed URLs for downloading attachment files from the private Supabase Storage bucket. Caches URLs briefly to avoid redundant API calls when the same attachment is accessed multiple times in a session.

Feature: Document Attachments for Activities

attachment-signed-url-service

Summaries

The Signed URL Service is an efficiency component that ensures staff can open attachment previews quickly without incurring repeated API call overhead within a session. By caching short-lived download URLs in memory, the service reduces latency when a coordinator opens the same attachment multiple times during a workflow — for example, when reviewing evidence before submitting a Bufdir report. Because the underlying storage bucket is private, signed URLs are the only mechanism that allows the mobile app to display files without exposing permanent credentials, making this service a direct enabler of the security model that protects sensitive participant documentation from unauthorised access.

The Signed URL Service is a low-complexity service with a single dependency on the Supabase Storage Adapter. The main delivery consideration is aligning the URL expiry duration with realistic usage sessions: too short an expiry forces re-fetching during active use, too long increases the window for a leaked URL to be misused. The in-memory cache must be sized and tested to prevent excessive memory growth on low-RAM mobile devices if many attachments are prefetched. Coordinate with the Attachment Preview Modal team on the `prefetchUrls(storagePaths)` interface to define how many paths may be prefetched simultaneously.

Cache invalidation on deletion must be verified in integration tests to prevent stale URLs being served after an attachment is removed.

The Signed URL Service wraps `supabase-storage-adapter.createSignedUrl()` with a TTL-keyed in-memory cache (a `Map` is sufficient). On `getSignedUrl()`, check if a cached entry exists and `expiresAt > Date.now() + safetyMarginMs` before returning it; otherwise fetch a fresh URL and update the cache. Choose an expiry of 15–60 minutes depending on session length expectations. `invalidateCache(storagePath)` should delete the specific map entry; `clearAllCache()` clears the entire map and should be called on session logout.

`prefetchUrls(storagePaths)` should fan out requests concurrently using `Promise.all` with an internal concurrency limit to avoid overwhelming the Supabase API. The service is consumed by both the Attachment Preview Modal and the Bufdir export pipeline, so keep the interface stateless and side-effect-free beyond cache mutation.

Responsibilities

  • Request signed URL from Supabase Storage for a given storage path
  • Cache signed URLs in memory with TTL to reduce API calls
  • Invalidate cache entry on attachment deletion
  • Return signed URL for use in preview modal and Bufdir export

Interfaces

getSignedUrl(storagePath, expiresInSeconds)
invalidateCache(storagePath)
clearAllCache()
prefetchUrls(storagePaths)

Relationships

Dependencies (1)

Components this component depends on

Dependents (2)

Components that depend on this component

Related Data Entities (1)

Data entities managed by this component

Used Integrations (1)

External integrations and APIs this component relies on

API Contract

View full contract →
REST /api/v1/attachment-signed-urls 6 endpoints
GET /api/v1/attachment-signed-urls
GET /api/v1/attachment-signed-urls/:id
POST /api/v1/attachment-signed-urls
PUT /api/v1/attachment-signed-urls/:id
DELETE /api/v1/attachment-signed-urls/:id
DELETE /api/v1/attachment-signed-urls