# Supabase

Crystal Save includes built-in support for **Supabase Storage** as a cloud save backend.\
This allows you to store save files, metadata, and screenshots in a Supabase bucket with configurable authentication and folder strategies.

### 1. Prepare Your Supabase Project

1.  **Create a Supabase Project**

    * Go to supabase.com and create a new project.

    <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2F2bT7dGuvwwzHAXO3WYRo%2Fimage.png?alt=media&#x26;token=9d5d3c7d-72c7-49ac-9b80-fa54ca70c54b" alt=""><figcaption></figcaption></figure>
2.  **Create a Storage Bucket**

    * Navigate to **Storage → New Bucket**.
    * Example name: `game-saves`.

    <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2FEvu6DNs1w8c3h5nf3W0N%2Fimage.png?alt=media&#x26;token=3b887f0a-8949-451d-80a6-3205336074f4" alt=""><figcaption></figcaption></figure>
3.  **Set Storage Policies**

    * Go to **Storage → Policies → Other policies (storage.objects)**.

    <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2FeRrQ2vk2NGIzSB1roLXn%2Fimage.png?alt=media&#x26;token=e160656d-9080-42d4-9f2c-cff641b257bf" alt=""><figcaption></figcaption></figure>

    * Create policies for **SELECT**, **INSERT**, **UPDATE**, and **DELETE** according to your chosen folder strategy.

    <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2Fj547b2WOoE8ZT2hRpi3h%2Fimage.png?alt=media&#x26;token=ca2b9011-f0c0-4c7a-818e-48f6ca1cf822" alt=""><figcaption></figcaption></figure>

    <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2FIjzSYZ8guqIffiRkCzuR%2Fimage.png?alt=media&#x26;token=c1127a94-e0ec-488b-a0aa-9a9062cb9340" alt=""><figcaption></figcaption></figure>

    *

        <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2FztEDFZRVYFbhr6Dw8ELR%2Fimage.png?alt=media&#x26;token=3395675d-08fd-4ae8-97cb-71f96e8d1340" alt=""><figcaption></figcaption></figure>
    * Example for a public/shared bucket:



```sql
CREATE POLICY "Anon read game-saves"
ON storage.objects
FOR SELECT TO anon
USING (bucket_id = 'game-saves');

```

* Repeat for insert/update/delete with the appropriate clauses.
*

    <figure><img src="https://166712561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp47l4hoFKIHGBwL1Cm4D%2Fuploads%2FqVJnvmWovliaWmgRZgjZ%2Fimage.png?alt=media&#x26;token=38c59e70-d2a0-4413-abcf-331f4d6ab2cd" alt=""><figcaption></figcaption></figure>



4. If you want **per-user isolation**:

* Use RLS with `auth.uid()` in the policy.
* Example for Unity Authentication:

```sql
CREATE POLICY "Player read own saves"
ON storage.objects
FOR SELECT TO authenticated
USING (
  bucket_id = 'game-saves'
  AND name LIKE ('users/' || auth.uid() || '/%')
);

```

***

### 2. Configure Crystal Save

1. **Create and Open Save Settings**
   * `Create → Crystal Save → Settings → Create Save Settings File`.
2. **Enable Cloud Save** and set:
   * **Save Backend** → `Supabase`
   * **Supabase URL** → Found in your Supabase Project dashboard.
   * **Supabase Anon Key** → API key from Supabase Project settings.
   * **Bucket Name** → e.g., `game-saves`.
3. **Choose a User Folder Strategy** (`userFolderStrategy`):
   * **Shared** – All saves in one folder.
   * **UnityAuthentication** – Folders per Unity Auth user.
   * **GuidPerDevice** – Random GUID stored locally.
   * **PublicPerBuild** – Different public folder per build.
   * **Custom** – Fully controlled by your own resolver.
4. **If using Custom strategy**:
   * Assign a `CustomFolderAuthResolver` or your own implementation of `IUserAuthorizationResolver`.
   *   After login, call:

       ```csharp
       resolver.SetUserId(uid);
       resolver.SetToken(jwt);
       SupabaseAuthRelay.FireLoggedIn(uid);
       ```

***

### 3. Handle Authentication

Crystal Save does not force a specific login flow, but provides utilities:

*   **Email/Password Signup**:

    ```csharp
    StartCoroutine(SupabaseRestAuth.SignUpWithEmailPassword(
        supabaseUrl, supabaseAnonKey, email, password,
        (jwt, uid, needsConfirm) => { resolver.SetUserId(uid); resolver.SetToken(jwt); },
        error => Debug.LogError(error)));
    ```
*   **Email/Password Signin**:

    ```csharp
    StartCoroutine(SupabaseRestAuth.SignInWithPassword(
        supabaseUrl, supabaseAnonKey, email, password,
        (jwt, uid) => { resolver.SetUserId(uid); resolver.SetToken(jwt); },
        error => Debug.LogError(error)));
    ```
* Use `SupabaseAuthRelay` events to react to login/logout.

***

### 4. Wait for Cloud Connection (Optional)

If your game must wait for a successful Supabase login before proceeding:

```csharp
await SaveManager.Instance.WaitForSupabaseLoginAsync();
```

This waits until `SupabaseAuthRelay` reports a login or times out.

***

### 5. Saving and Loading

Once logged in:

* Call `SaveManager.SaveAsync(slotNumber)` to upload the save.
* Call `SaveManager.LoadAsync(slotNumber)` to download and load the save.
* Crystal Save:
  * Resolves the **user folder** based on strategy or resolver.
  * Uploads `.sav` or `.json` file.
  * Uploads `.meta.json` with slot details.
  * Optionally uploads screenshots.
  * If `keepLocalMirror` is enabled, stores local copies for offline play.

***

### 6. Logging Out

```csharp
SaveManager.Instance.LogoutFromSupabase();
```

* Clears stored credentials from the resolver.
* Resets cloud save state.

***

### Mermaid Flow Diagram

{% @mermaid/diagram content="graph TD
A[Game Start] --> B[Load SaveSettings]
B --> C[Enable Cloud Save and Select Supabase Backend]
C --> D{Choose User Folder Strategy}
D -->|Custom| E[Assign CustomFolderAuthResolver]
D -->|Other| F[Use Built-in Resolver]
E --> G[Login Flow SupabaseRestAuth]
F --> G
G --> H[SetUserId and SetToken]
H --> I[SupabaseAuthRelay FireLoggedIn]
I --> J[WaitForSupabaseLoginAsync optional]
J --> K[SaveManager SaveAsync LoadAsync]
K --> L[SupabaseSaveSystem]
L --> M[Resolve User Folder Path]
M --> N[Upload Download sav json meta screenshots]
N --> O[Optional Local Mirror]
O --> P[Cloud Saves in Supabase Bucket]" %}

***

