Skip to content

Latest commit

 

History

History
148 lines (108 loc) · 5.44 KB

File metadata and controls

148 lines (108 loc) · 5.44 KB

PowerChat - Demo app for the PowerSync React Native Client SDK

An offline-first group chat app built with Expo/React Native, using Supabase as the backend and PowerSync for offline sync.

This demo uses Sync Streams (edition 3). User data (profile, contacts, groups, memberships, DM messages) is auto-subscribed, while group messages are subscribed on-demand when a user opens a specific group chat and unsubscribed when navigating away.

The following video gives an overview of the implemented functionality:

PowerChat.Public.Demo.4K.mp4

Local Development (Recommended)

Run the full backend locally with a single command using the Supabase CLI and Docker.

Prerequisites

Setup

  1. Start Supabase and PowerSync:

    pnpm local:up

    This runs supabase start (which applies all migrations from ./supabase/migrations/) and starts a local PowerSync service container via Docker Compose.

  2. The .env.local file is pre-configured to point to the local services.

    Physical device: Replace 127.0.0.1 in .env.local with your Mac's LAN IP address (the same one shown in the Metro bundler URL, e.g. 192.168.x.x). This is required because 127.0.0.1 on the device refers to the device itself, not your Mac.

  3. Start the Expo dev server:

    pnpm dev
  4. Run ios

    pnpm ios
  5. Run Android

    pnpm android
  6. To stop everything:

    pnpm local:down

Local service URLs

Service URL
Supabase API http://127.0.0.1:54321
Supabase Studio http://127.0.0.1:54323
PowerSync http://127.0.0.1:8080
Inbucket (email) http://127.0.0.1:54324

Cloud Setup

To run against cloud-hosted Supabase and PowerSync instances:

  1. Deploy a Supabase project using the config and migrations in the supabase folder. Update EXPO_PUBLIC_SUPABASE_URL and EXPO_PUBLIC_SUPABASE_ANON_KEY in .env.local.

  2. Create a PowerSync instance via the PowerSync Dashboard and connect it to your Supabase project. Deploy the following sync streams configuration (also available in sync-config.yaml):

    config:
      edition: 3
    
    streams:
      user:
        auto_subscribe: true
        queries:
          - SELECT * FROM profiles WHERE id = auth.user_id()
          - SELECT * FROM contacts WHERE owner_id = auth.user_id()
          - SELECT * FROM memberships WHERE profile_id = auth.user_id()
          - SELECT * FROM groups WHERE owner_id = auth.user_id()
          - SELECT * FROM messages WHERE sender_id = auth.user_id()
          - SELECT * FROM messages WHERE recipient_id = auth.user_id() AND sent_at IS NOT NULL
          - SELECT *, '...' as content FROM messages WHERE recipient_id = auth.user_id() AND sent_at IS NULL
    
      contact_profiles:
        auto_subscribe: true
        query: |
          SELECT profiles.* FROM profiles
            JOIN contacts ON contacts.profile_id = profiles.id
          WHERE contacts.owner_id = auth.user_id()
    
      member_groups:
        auto_subscribe: true
        query: |
          SELECT groups.* FROM groups
            JOIN memberships ON memberships.group_id = groups.id
          WHERE memberships.profile_id = auth.user_id()
    
      chats:
        auto_subscribe: true
        queries:
          - SELECT profiles.id, profiles.id as profile_id FROM profiles
              JOIN messages ON messages.recipient_id = profiles.id
            WHERE messages.sender_id = auth.user_id()
          - SELECT profiles.id, profiles.id as profile_id FROM profiles
              JOIN messages ON messages.sender_id = profiles.id
            WHERE messages.recipient_id = auth.user_id()
    
      chat_profiles:
        auto_subscribe: true
        queries:
          - SELECT profiles.* FROM profiles
              JOIN messages ON messages.recipient_id = profiles.id
            WHERE messages.sender_id = auth.user_id()
          - SELECT profiles.* FROM profiles
              JOIN messages ON messages.sender_id = profiles.id
            WHERE messages.recipient_id = auth.user_id()
    
      group_messages:
        queries:
          - SELECT * FROM messages WHERE group_id = subscription.parameter('group_id') AND sent_at IS NOT NULL
          - SELECT * FROM messages WHERE group_id = subscription.parameter('group_id') AND sender_id = auth.user_id() AND sent_at IS NULL
    
      group_memberships:
        query: SELECT * FROM memberships WHERE group_id = subscription.parameter('group_id')
    
      group_member_profiles:
        query: |
          SELECT profiles.* FROM profiles
            JOIN memberships ON memberships.profile_id = profiles.id
          WHERE memberships.group_id = subscription.parameter('group_id')

    Update EXPO_PUBLIC_POWERSYNC_URL in .env.local.

Helpful Links