Help centre Families Coaches Support

Littles Baby Tracker

Help for families and coaches

Site Tools


technical:features:30_signed_files_and_profile_media

30 — Signed files and profile media

Technical reference. For task-based help, see the corresponding user guide.
Documentation status: reviewed against implementation · Reviewed: 2026-07-21 · Primary users: family/coach in an authorized subject context; owner for guide publishing · Surfaces: mobile web, coach portal, storage and platform API

Purpose

Private media is referenced by bucket/object path and accessed through short-lived signed URLs. The platform authorizes the relationship between actor, subject, record and path before asking storage to issue a URL; knowing an object path is never enough.

Bucket and purpose map

Bucket Expected context and object prefix Typical content
profile-images Own users/<actorUserId>/…; coach download of another profile additionally names the authorized family subject User avatar/profile image.
baby-images families/<familyUserId>/babies/<babyId>/… with baby and subject context Baby profile image.
activity-images families/<familyUserId>/activities/<activityId>/… with activity context Activity/nappy attachment.
organization-branding organizations/<organizationId>/… Practice logo.
getting-started-guides guides/… Published audience PDF.
sleep-plan-pdfs families/<familyUserId>/sleep-plans/… Attached sleep-plan PDF.
sleep-plan-images families/<familyUserId>/sleep-plans/… Images embedded/attached to a sleep plan.

Upload flow

  1. The client validates file type/size for the feature and prepares an image when applicable.
  2. It constructs the required bucket, safe prefix and record context (family, baby, activity or organization).
  3. POST /files/signed-upload-url validates the context and returns a signed URL, expiry and—when supported—an upload token/method.
  4. The client uploads directly to storage using the returned authorization. It can use the token path or signed PUT fallback.
  5. Only after upload succeeds does the feature save the object path/asset ID onto the profile, baby, activity, organization or plan record.
  6. A replacement changes the stored reference. A removal clears the reference through the owning record API.

Image preparation

Use Client preparation
Coach/family profile Maximum side 512 px, quality around 0.8.
Baby image Maximum side 768 px, quality around 0.8.
Activity image Maximum side 1,280 px, quality around 0.8.
Organization logo Maximum side 1,024 px, quality around 0.8; animated GIF is not recompressed.
Sleep-plan image in portal JPEG/PNG/WebP/GIF, maximum 10 MB; non-GIF resized up to 2,000 px at about 0.82 quality.
Sleep-plan PDF in portal PDF only, maximum 20 MB.

The common image helper decodes/orients the image, previews it, chooses WebP/JPEG when the prepared result is smaller, and retains the original when conversion would not help. Preparation, signing and storage-upload errors remain distinguishable.

Download flow

  1. A feature sends POST /files/signed-download-url with the stored path and required subject/record identifiers.
  2. The platform resolves the referenced database record and re-runs read permission before signing.
  3. Default expiry is 900 seconds; callers may request up to 3,600 seconds.
  4. The client uses the URL for image/PDF rendering. Baby/profile helpers may cache the URL only until shortly before expiry (for example, a 30-second safety margin), then request a fresh one.

Server authorization matrix

Asset Upload rule Download rule
Profile Actor's own user prefix only. Actor's own; coach may read a family profile only with subject context and current log-read access.
Baby Current subject plus baby; caller must have activity-write access. Current subject plus baby; caller must have activity-read access.
Activity Existing activity plus matching family prefix; caller must have write access. Existing activity plus matching subject; caller must have read access.
Organization logo Eligible organization branding editor. Active organization member or currently linked/assigned authorized family context.
Getting-started PDF Super-admin upload, PDF, guides/ prefix. Object must back a published guide whose audience the actor may read.
Sleep-plan PDF/image Authorized coach assignment for upload; enforced type/prefix. Coach needs current family access; family can read only the asset attached to a published plan.

Validation and user-visible states

State Behaviour
Unsupported/oversized file Feature rejects before signing/upload and explains the allowed type/size.
Image preparation failure Existing asset stays in place; user can choose another file.
Signing denied No storage URL is issued; surface shows access/error state.
Storage upload failure Record reference is not advanced to the failed object.
Save-after-upload failure Uploaded object can be orphaned; retrying the record save or re-upload is required.
URL expired Rendering/open may fail; reload/reopen requests a fresh URL.
Missing object Broken media state is contained; core record remains available.
Clear reference UI returns to initials/placeholder or no attachment.

Platform API contract

Method and route Request highlights Response
POST /files/signed-upload-url bucket, objectPath, contentType, optional subject/record context and expiry signedUrl, optional uploadToken, method and expiresAt.
POST /files/signed-download-url bucket, objectPath, required context and expiry Short-lived signedUrl and expiresAt.

The shared schemas enumerate the seven supported buckets, require safe object paths, cap expiry at one hour and reject unknown request fields.

Security and privacy

  • Supabase Auth identifies the actor; the platform API performs tenant/assignment/record authorization before storage signing.
  • Signed URLs are bearer credentials until expiry. Never persist them as the asset ID, put them in app analytics, or share them as permanent links.
  • Prefix validation prevents an authorized call for one record from signing a different actor/tenant path.
  • Family reads of sleep-plan media are publication-bound; an unpublished/draft attachment is not exposed by its path.
  • Clearing a database reference is not guaranteed to delete the underlying storage object. There is no general user-facing storage-delete endpoint in this feature.
A signed URL is an authorization snapshot, not ongoing permission. Keep expiries short, request it just in time, and never infer access from a URL cached before assignment/publication changed.

Acceptance checklist

  1. [ ] Every bucket rejects paths outside its actor/family/organization prefix.
  2. [ ] Baby/activity/sleep-plan requests bind both identifiers and current permissions.
  3. [ ] Upload updates the owning record only after successful storage transfer.
  4. [ ] Type, size and image-preparation failures are actionable.
  5. [ ] Download URLs expire, refresh safely and are absent from durable app records/logs.
  6. [ ] Published-guide and published-sleep-plan rules are rechecked at signing time.
  7. [ ] Cross-tenant, revoked-assignment and stale-record signing tests fail closed.
  8. [ ] Product copy does not promise storage deletion when only a reference was cleared.

Source evidence

  • Mobile web: mobile-web/src/utils/image-upload.ts, signed-file/profile/baby/activity consumers and mobile-web/src/components/SignedFilePanel.tsx
  • Coach portal: admin-web/src/routes/AccountPanel.tsx, admin-web/src/routes/BrandingPanel.tsx, admin-web/src/api/familyProfileArtifacts.ts
  • Platform: platform/packages/shared/src/files.ts, platform/apps/api/src/routes/file-routes.ts, platform/apps/api/src/services/prisma-file-url-service.ts, platform/apps/api/src/services/storage-service.ts, platform/apps/api/src/services/getting-started-guide-service.ts