Skip to main content

Storage buckets

Four Supabase Storage buckets:

BucketPublic?HoldsPolicy
case-attachmentsprivateeverything case-related: evidence, deliverables, dossier ZIPs (dossiers/{case_id}/{export_id}.zip), portal uploads ({case_id}/{uuid}.{ext})authenticated INSERT/SELECT gated only on bucket_idno per-company path check
company-logospubliccompany logos at {company_id}/logo.{ext}write requires is_super_admin() OR is_company_admin(first-path-segment); anyone reads
user-avatarspublic{user_id}/avatar.{ext}write scoped to auth.uid(); anyone reads
email-assetspublicthe email logoanyone reads; authenticated INSERT

The critical problem

case-attachments — which holds all confidential case evidence, legal deliverables, and the final dossiers — has no tenant path isolation. Any authenticated user of any company can read or write any path. This is the single most severe data-isolation hole in the PoC, and it directly contradicts the "Encriptação ponta-a-ponta" marketing claim.

See storage has no tenant isolation.

Inconsistent pathing

File paths are ad-hoc and inconsistent: some are tenant-scoped ({companyId}/{caseId}/deliverables/{phase}/{uuid} in InquiryReportDrawer), most are only case-scoped ({caseId}/{uuid} in checklist/portal uploads). No convention.

Signed-URL expiries also vary by call site: 60s (dossier download, evidence vault), 300s (deliverables), 3600s (portal items).

Rebuild implication

One private bucket with enforced per-company path prefixes in the storage policy (or a proxied download endpoint that checks authorization), a single path convention, and consistent, short signed-URL lifetimes. If the E2E-encryption claim is to be real, encrypt at rest with per-tenant keys.