> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swiftaiboilerplate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Profile Photo Setup

> Store profile photos in Supabase Storage for cross-device access.

<Info>
  **Complete setup guide:** see `docs/integrations/ProfilePhotos.md` in your project repo.
</Info>

## What Is Profile Photo Storage?

<CardGroup cols={2}>
  <Card title="Cloud Storage" icon="cloud-arrow-up">
    Photos stored in Supabase Storage
  </Card>

  <Card title="Cross-Device" icon="mobile">
    Same photo on all devices
  </Card>

  <Card title="Automatic Compression" icon="compress">
    \~500KB target size
  </Card>

  <Card title="Fallback" icon="shield">
    Works locally if upload fails
  </Card>
</CardGroup>

## Quick Overview

<Steps>
  <Step title="Create Storage Bucket">
    In Supabase Dashboard:

    * Storage → New Bucket
    * Name: `profile-photos`
    * Public: ✅ Enable
  </Step>

  <Step title="Set RLS Policies">
    Photos are uploaded under `avatars/{userId}_{timestamp}.jpg`. Add these policies (the full setup guide also adds matching UPDATE and DELETE policies):

    ```sql theme={null}
    -- Users can upload their own photos
    CREATE POLICY "Users upload own" ON storage.objects
    FOR INSERT TO authenticated WITH CHECK (
      bucket_id = 'profile-photos' AND
      (storage.foldername(name))[1] = 'avatars' AND
      auth.uid()::text = (storage.foldername(name))[2]
    );

    -- Photos are public (read)
    CREATE POLICY "Photos public" ON storage.objects
    FOR SELECT TO public USING (bucket_id = 'profile-photos');
    ```

    The full guide also adds matching UPDATE and DELETE policies.
  </Step>

  <Step title="Uncomment Implementation">
    In `SupabaseProfilePhotoStorageClient.swift`:

    * Uncomment `import Supabase`
    * Remove comment blocks
  </Step>

  <Step title="Enable in CompositionRoot">
    ```swift theme={null}
    self.profilePhotoStorageClient = SupabaseProfilePhotoStorageClient(
        supabaseClient: supabaseClient,
        bucketName: "profile-photos"
    )
    ```
  </Step>
</Steps>

## How It Works

```text theme={null}
Upload Flow:
User selects photo → Compress (~500KB) → Upload to Supabase → Update profile

Download Flow:
App opens → Load from Supabase → Cache locally → Display
```

**Benefits:**

* ✅ Photos sync across devices
* ✅ Automatic compression
* ✅ Public CDN URLs
* ✅ Graceful fallback to local
* ✅ Privacy-first (iOS 17+ PhotosPicker)

## Prerequisites

* Supabase project configured
* Supabase dependency in Storage package
* User authenticated

## What You Get

After setup:

* ✅ Upload profile photos
* ✅ Photos sync across devices
* ✅ Automatic compression
* ✅ CDN-hosted images
* ✅ Local fallback if upload fails
* ✅ No camera permissions needed (PhotosPicker)

## Complete Guide

The **12KB comprehensive guide** includes:

* Storage bucket configuration
* Row Level Security policies
* Upload implementation
* Compression strategy
* Error handling
* Testing procedures

<Card title="View Complete Setup Guide" icon="book" href="https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/blob/main/docs/integrations/ProfilePhotos.md">
  Find complete profile photo storage guide in your project
</Card>

## Related Guides

<CardGroup cols={2}>
  <Card title="Storage Module" icon="database" href="/pages/modules/storage">
    Storage architecture
  </Card>

  <Card title="Chat Sync" icon="cloud" href="/pages/guides/chat-sync">
    Another optional sync feature
  </Card>

  <Card title="Supabase Setup" icon="server" href="/pages/guides/supabase-setup">
    Required backend
  </Card>

  <Card title="Building Your App" icon="hammer" href="/pages/guides/building-your-app">
    Customize features
  </Card>
</CardGroup>

## Need Help?

* 📖 Complete troubleshooting in full guide
* 💬 [Create an issue](https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/issues)
* 🔍 Check Supabase Storage logs
