diff --git a/learn/markdown/mobile/couchbase-lite-retail-demo/couchbase-lite-retail-demo.md b/learn/markdown/mobile/couchbase-lite-retail-demo/couchbase-lite-retail-demo.md new file mode 100644 index 0000000..a7fa9d9 --- /dev/null +++ b/learn/markdown/mobile/couchbase-lite-retail-demo/couchbase-lite-retail-demo.md @@ -0,0 +1,62 @@ +--- +path: "/learn/couchbase-lite-offline-first-retail" +title: Couchbase Lite and Offline First Retail Applications +short_title: Offline First with Couchbase Lite +description: + - Learn how to build an offline-first retail inventory management application with Couchbase Lite + - Set up a cloud backend with Couchbase Capella and configure App Services for real-time sync + - Enable peer-to-peer sync between mobile devices without requiring cloud connectivity +content_type: learn +filter: mobile +technology: + - mobile + - capella + - app-services +tags: + - Android + - iOS + - App Services + - P2P +tutorials: + - offline-first-app-getting-started + - retail-demo-capella-setup + - retail-demo-app-services-sync + - retail-demo-peer-to-peer-sync +related_paths: + - /learn/android-kotlin-app-services + - /learn/swift +sdk_language: + - kotlin + - swift +download_file: null +length: 1 Hour 45 Mins +--- + +Couchbase Mobile brings the power of NoSQL to the edge, combining Couchbase Lite (an embedded, offline-capable database), Capella App Services (a synchronization layer), and Couchbase Capella (a fully managed cloud database). Together they enable applications that work seamlessly with or without internet connectivity — a pattern known as offline-first. + +This learning path walks through a multi-platform retail inventory management application built for iOS (Swift/SwiftUI) and Android (Kotlin/Jetpack Compose). The app demonstrates how a real-world retail solution can store data locally on-device, sync it to the cloud, and even sync directly between nearby devices — all powered by Couchbase Lite. + +## Prerequisites + +Before starting this learning path, you should have: + +* A [Couchbase Capella account](https://cloud.couchbase.com/) (free trial available) +* Familiarity with iOS (Swift) or Android (Kotlin) development +* For iOS: Xcode 16.4+, macOS Sonoma or later +* For Android: Android Studio Ladybug (2024.2.1)+, JDK 17+ +* Basic understanding of NoSQL and mobile application architecture + +## Retail Demo Application + +The sample application is a retail inventory management system for a fictitious supermarket chain with multiple store locations. It demonstrates how Couchbase Lite fits into a production-grade mobile architecture, covering offline data access, cloud synchronization, and direct peer-to-peer sync between devices. + +The app uses scopes and collections to isolate data per store location, with three core collections — `inventory`, `orders`, and `profile` — synchronized via Capella App Services. + +## Learning Agenda + +This learning path covers four modules: + +1. **Getting Started** — Understand the application architecture, the offline-first approach, and how to set up your development environment +2. **Capella Setup** — Create a Couchbase Capella cluster, configure buckets, scopes, and collections, set up App Services, and import sample data +3. **App Services Sync** — Learn how Couchbase Lite replicates data bidirectionally with Capella App Services, and test real-time sync across devices +4. **Peer-to-Peer Sync** — Enable direct device-to-device synchronization over a local network without requiring cloud connectivity, using Couchbase Lite's URL Endpoint Listener diff --git a/tutorial/markdown/mobile/offline-first-app-getting-started/app-setup.png b/tutorial/markdown/mobile/offline-first-app-getting-started/app-setup.png new file mode 100644 index 0000000..9d62db2 Binary files /dev/null and b/tutorial/markdown/mobile/offline-first-app-getting-started/app-setup.png differ diff --git a/tutorial/markdown/mobile/offline-first-app-getting-started/offline-first-app-getting-started.md b/tutorial/markdown/mobile/offline-first-app-getting-started/offline-first-app-getting-started.md new file mode 100644 index 0000000..5c0f064 --- /dev/null +++ b/tutorial/markdown/mobile/offline-first-app-getting-started/offline-first-app-getting-started.md @@ -0,0 +1,188 @@ +--- +path: "/offline-first-app-getting-started" +title: Getting Started with Offline First Mobile Apps using Couchbase Lite +short_title: Getting Started +description: + - Learn about the Couchbase Lite Retail Demo application architecture + - Understand the offline-first approach with Couchbase Lite + - Set up your development environment for iOS, Android, or Web +content_type: tutorial +filter: mobile +technology: + - mobile + - capella + - app-services +tags: + - Android + - iOS + - App Services +sdk_language: + - kotlin + - swift +length: 15 Mins +exclude_tutorials: true +--- + +## Introduction + +Welcome to the Couchbase Lite Retail Demo! This tutorial series will guide you through building and understanding a retail inventory management application that demonstrates Couchbase Lite's powerful features. + +In this first tutorial, you will learn: + +* The architecture of the retail demo application +* Key features including offline-first data storage, real-time sync, and peer-to-peer sync +* How to set up your development environment + +## Application Overview + +The Couchbase Lite Retail Demo is a multi-platform retail inventory management application built for: + +* **iOS** (Swift/SwiftUI) +* **Android** (Kotlin/Jetpack Compose) +* **Web** (React/TypeScript) + +### Key Features + +| Feature | Description | +|---------|-------------| +| **Offline-First** | Full functionality without internet using Couchbase Lite as a local database | +| **Real-Time Sync** | Bidirectional sync with Couchbase Capella via App Services | +| **Peer-to-Peer Sync** | Direct device-to-device sync over local network (iOS & Android) | +| **Multi-Store Support** | Manage inventory across multiple retail locations | + +### Architecture Diagram + +The complete setup looks like this: + +![App Setup Diagram](app-setup.png) + +The architecture consists of: + +1. **Couchbase Capella** - Cloud database backend +2. **Capella App Services** - Synchronization layer that connects mobile/web clients to Capella +3. **Mobile/Web Clients** - iOS, Android, and Web applications with embedded Couchbase Lite + +## Data Model + +The application manages three main types of data: + +### Collections + +Each store scope contains three collections: + +| Collection | Purpose | Example Document Count | +|------------|---------|----------------------| +| `inventory` | Product inventory items | ~80 per store | +| `orders` | Customer orders | ~150 per store | +| `profile` | Store profile information | 1 per store | + +### Scopes + +Data is organized by store using scopes: + +* `AA-Store` - AA Supermarket location +* `NYC-Store` - NYC Supermarket location + +### Sample Documents + +**Inventory Document:** +```json +{ + "_id": "Inventory_NYCStore_10000", + "docType": "Inventory", + "productId": 10000, + "sku": "NYC-10000", + "name": "Organic Milk", + "brand": "BudgetBest", + "category": "Dairy", + "price": 29.86, + "unit": "gallon", + "stockQty": 71, + "location": {"aisle": 24, "bin": 7}, + "storeId": "nyc-store-01" +} +``` + +**Order Document:** +```json +{ + "_id": "order-nyc-store-01-V1StGXR8_Z5jdHi6B-myT", + "docType": "Order", + "storeId": "nyc-store-01", + "orderDate": 1755257767451, + "orderStatus": "Submitted", + "productId": 10000, + "sku": "NYC-10000", + "unit": "gallon", + "orderQty": 30 +} +``` + +## Prerequisites + +Before you begin, ensure you have the following: + +### For All Platforms + +* **Couchbase Capella Account** - Sign up for a [free trial](https://cloud.couchbase.com/) +* **curl** or similar HTTP client for testing + +### For iOS Development + +* **Xcode**: 16.4 or later +* **iOS SDK**: 18.5 or later +* **macOS**: Sonoma or later + +### For Android Development + +* **Android Studio**: Ladybug (2024.2.1) or later +* **JDK**: 17 or later +* **Android SDK**: Minimum 24, Target 35 + +### For Web Development + +* **Node.js**: Version 18 or higher +* **npm**: Comes with Node.js + +## Repository Structure + +Clone the repository to get started: + +```bash +git clone https://github.com/couchbase-examples/couchbase-lite-retail-demo.git +cd couchbase-lite-retail-demo +``` + +The repository is organized as follows: + +``` +couchbase-lite-retail-demo/ +├── Android/ # Android app (Kotlin/Jetpack Compose) +├── iOS/ # iOS app (Swift/SwiftUI) +├── web/ # Web app (React/TypeScript) +├── common/ # Shared assets +│ └── assets/ # Images and diagrams +├── tutorials/ # Step-by-step tutorials +├── README.md # Main project documentation +└── CONTRIBUTING.md # Development guidelines +``` + +## Platform-Specific Setup + +For detailed setup instructions specific to each platform, see the platform-specific READMEs in the [couchbase-lite-retail-demo repository](https://github.com/couchbase-examples/couchbase-lite-retail-demo): + +* [Android README](https://github.com/couchbase-examples/couchbase-lite-retail-demo/blob/main/Android/README.md) +* [iOS README](https://github.com/couchbase-examples/couchbase-lite-retail-demo/blob/main/iOS/README.md) +* [Web README](https://github.com/couchbase-examples/couchbase-lite-retail-demo/blob/main/web/README.md) + +## Learn More + +### References + +* [Couchbase Lite Documentation](https://docs.couchbase.com/couchbase-lite/current/index.html) +* [Couchbase Capella App Services](https://docs.couchbase.com/cloud/app-services/index.html) +* [Couchbase Capella Free Trial](https://cloud.couchbase.com/) + +## What's Next? + +You now have a solid understanding of the Couchbase Lite Retail Demo architecture and your development environment is ready. In the next tutorial, you will set up the cloud backend by creating a Couchbase Capella cluster, configuring scopes and collections, and enabling App Services for synchronization. diff --git a/tutorial/markdown/mobile/retail-demo-app-services-sync/retail-demo-app-services-sync.md b/tutorial/markdown/mobile/retail-demo-app-services-sync/retail-demo-app-services-sync.md new file mode 100644 index 0000000..f394191 --- /dev/null +++ b/tutorial/markdown/mobile/retail-demo-app-services-sync/retail-demo-app-services-sync.md @@ -0,0 +1,335 @@ +--- +path: "/retail-demo-app-services-sync" +title: Real-Time Sync with Couchbase Capella App Services +short_title: App Services Sync +description: + - Learn how Couchbase Lite syncs data with Capella App Services + - Understand the replication architecture and configuration + - Configure and test bidirectional sync in the retail demo +content_type: tutorial +filter: mobile +technology: + - mobile + - capella + - app-services +tags: + - Android + - iOS + - App Services +sdk_language: + - kotlin + - swift +length: 30 Mins +exclude_tutorials: true +--- + +## Introduction + +In this tutorial, you will learn how the Couchbase Lite Retail Demo implements real-time data synchronization with Couchbase Capella App Services. This enables your inventory data to stay synchronized across all devices and the cloud backend. + +You will learn: + +* How Couchbase Lite replication works +* The sync flow for login, profile fetch, and continuous replication +* How to configure sync in the iOS, Android, and Web apps +* How to test and verify synchronization + +## Prerequisites + +Before starting this tutorial, ensure you have: + +* Completed the [Capella Setup tutorial](/retail-demo-capella-setup) +* Your App Services Public Connection URL +* User credentials created in App Services +* The retail demo app built and running on your platform + +## How Sync Works + +### Replication Architecture + +Couchbase Lite uses a **replicator** to synchronize data between the local database and a remote endpoint (App Services). The replicator supports: + +| Mode | Description | +|------|-------------| +| **Push** | Send local changes to the server | +| **Pull** | Receive server changes locally | +| **Push and Pull** | Bidirectional synchronization | + +### Sync Flow in the Retail Demo + +When a user logs in, the app follows this sync flow: + +``` +1. User Login + └── Authenticate with App Services endpoint + +2. Profile Fetch (One-Shot Pull) + └── Pull store profile document + └── Update UI with store information + +3. Continuous Replication (Push & Pull) + └── Sync inventory collection + └── Sync orders collection + └── Real-time updates across all devices +``` + +## Understanding the Code + +### iOS Implementation + +In the iOS app, sync is managed by `AppServicesSyncManager.swift`: + +```swift +// Configure the replicator +var config = ReplicatorConfiguration(target: URLEndpoint(url: syncURL)) +config.continuous = true +config.replicatorType = .pushAndPull + +// Add collections to sync +config.addCollections([inventoryCollection, ordersCollection, profileCollection]) + +// Set authentication +config.authenticator = BasicAuthenticator(username: username, password: password) + +// Create and start replicator +let replicator = Replicator(config: config) +replicator.start() +``` + +Key configuration options: + +| Property | Value | Description | +|----------|-------|-------------| +| `continuous` | `true` | Keeps replicating until stopped | +| `replicatorType` | `.pushAndPull` | Bidirectional sync | +| `authenticator` | `BasicAuthenticator` | Username/password auth | + +### Android Implementation + +In the Android app, sync is managed by `AppServicesSyncManager.kt`: + +```kotlin +// Create endpoint +val endpoint = URLEndpoint(URI(syncUrl)) + +// Configure replicator +val config = ReplicatorConfiguration(endpoint) + .addCollections(listOf(inventoryCollection, ordersCollection, profileCollection), null) + .setType(ReplicatorType.PUSH_AND_PULL) + .setContinuous(true) + .setAuthenticator(BasicAuthenticator(username, password.toCharArray())) + +// Create and start replicator +replicator = Replicator(config) +replicator.start() +``` + +### Web Implementation + +The web app uses `couchbase-lite-js` for sync: + +```typescript +// Configure replicator +const config = new ReplicatorConfiguration(database, new URLEndpoint(syncUrl)); +config.continuous = true; +config.replicatorType = ReplicatorType.PUSH_AND_PULL; +config.authenticator = new BasicAuthenticator(username, password); + +// Add collections +config.addCollections([inventoryCollection, ordersCollection, profileCollection]); + +// Start replication +const replicator = new Replicator(config); +await replicator.start(); +``` + +## Configuring Sync in the Apps + +### iOS Configuration + +1. Open `LiquorApp/Info.plist` or set environment variables: + +```bash +export CBL_BASE_URL="wss://your-endpoint.apps.cloud.couchbase.com:4984" +export CBL_AA_DB="supermarket-aa" +export CBL_NYC_DB="supermarket-nyc" +export CBL_AA_USER="aa-store-01@supermarket.com" +export CBL_NYC_USER="nyc-store-01@supermarket.com" +export CBL_PASSWORD="P@ssword1" +``` + +2. The app reads these values in `AppConfig.swift` and uses them to configure the replicator. + +### Android Configuration + +1. Set environment variables before launching Android Studio: + +```bash +export CBL_BASE_URL="wss://your-endpoint.apps.cloud.couchbase.com:4984" +export CBL_AA_DB="supermarket-aa" +export CBL_NYC_DB="supermarket-nyc" +export CBL_AA_USER="aa-store-01@supermarket.com" +export CBL_NYC_USER="nyc-store-01@supermarket.com" +export CBL_PASSWORD="P@ssword1" +``` + +2. Or add to `gradle.properties`: + +```properties +CBL_BASE_URL=wss://your-endpoint.apps.cloud.couchbase.com:4984 +CBL_AA_DB=supermarket-aa +CBL_NYC_DB=supermarket-nyc +``` + +### Web Configuration + +1. Copy the environment example and edit: + +```bash +cd web +cp .env.example .env +``` + +2. Set the sync URL in `.env`: + +```env +VITE_APP_SERVICES_URL=wss://your-endpoint.apps.cloud.couchbase.com:4984/supermarket-nyc +``` + +## Try It Out + +### Step 1: Start the App + +1. Launch the retail demo app on your platform +2. The login screen should appear + +### Step 2: Log In + +Log in with your App Services credentials: + +* **Email**: `nyc-store-01@supermarket.com` +* **Password**: `P@ssword1` + +The app will: +1. Authenticate with App Services +2. Pull the store profile +3. Start continuous replication + +### Step 3: View Inventory + +Navigate to the Inventory screen. You should see items synced from your Capella cluster. + +### Step 4: Make a Change + +1. Select an inventory item +2. Update the stock quantity +3. Save the change + +The change is: +1. Saved locally to Couchbase Lite +2. Pushed to App Services +3. Synced to Capella and other connected devices + +### Step 5: Verify in Capella + +1. Log into [Couchbase Capella](https://cloud.couchbase.com/) +2. Navigate to your cluster > Tools > Documents +3. Browse the `inventory` collection in the appropriate scope +4. Find your updated document and verify the change + +## Testing Multi-Device Sync + +To see real-time sync in action: + +1. **Run two instances** of the app (different emulators, devices, or platforms) +2. **Log in as the same store** on both (e.g., `nyc-store-01@supermarket.com`) +3. **Update inventory** on one device +4. **Observe the change** appear on the other device + +This demonstrates the continuous bidirectional sync capability. + +## Handling Sync Status + +The demo apps display sync status to help you understand what's happening: + +| Status | Meaning | +|--------|---------| +| **Connecting** | Establishing connection to App Services | +| **Busy** | Actively syncing data | +| **Idle** | Connected, waiting for changes | +| **Offline** | No network connection (changes queued locally) | +| **Stopped** | Replication manually stopped | + +### Monitoring Sync Events + +In the code, you can listen to replicator status changes: + +```swift +// iOS +replicator.addChangeListener { change in + print("Status: \(change.status.activity)") + print("Progress: \(change.status.progress.completed)/\(change.status.progress.total)") +} +``` + +```kotlin +// Android +replicator.addChangeListener { change -> + Log.d("Sync", "Status: ${change.status.activityLevel}") + Log.d("Sync", "Progress: ${change.status.progress.completed}/${change.status.progress.total}") +} +``` + +## Conflict Resolution + +When the same document is modified on multiple devices before syncing, a conflict occurs. Couchbase Lite provides automatic conflict resolution: + +* **Default**: Last-write-wins based on revision history +* **Custom**: You can implement custom conflict resolvers + +For the retail demo, the default conflict resolution is used. Learn more in the [conflict handling documentation](https://docs.couchbase.com/couchbase-lite/current/swift/conflict.html). + +## Troubleshooting + +### Sync Not Starting + +* Verify your `CBL_BASE_URL` includes `wss://` protocol +* Check that credentials match those in App Services +* Ensure App Services endpoint is running + +### Authentication Failures + +* Verify username format: `store-id@supermarket.com` +* Check password matches exactly (case-sensitive) +* Confirm user exists in the correct App Endpoint + +### Data Not Appearing + +* Verify collections are linked in your App Endpoint +* Check that data was imported into the correct scope +* Look for errors in app console/logs + +### Connection Timeouts + +* Check network connectivity +* Verify App Services URL is accessible +* Try pinging the endpoint from your development machine + +## Exercise: Create and Sync an Order + +1. Log into the app as `nyc-store-01@supermarket.com` +2. Navigate to an inventory item +3. Create a new order for that item +4. Open Capella and navigate to the `orders` collection +5. Verify the new order document appears +6. Change the order status in Capella to "Processing" +7. Return to the app and verify the status update synced + +## Learn More + +### References + +* [Couchbase Lite Replication](https://docs.couchbase.com/couchbase-lite/current/swift/replication.html) +* [App Services Documentation](https://docs.couchbase.com/cloud/app-services/index.html) +* [Conflict Resolution](https://docs.couchbase.com/couchbase-lite/current/swift/conflict.html) +* [Replicator Configuration](https://docs.couchbase.com/couchbase-lite/current/swift/replication.html#lbl-cfg-repl) diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/appendpoint.png b/tutorial/markdown/mobile/retail-demo-capella-setup/appendpoint.png new file mode 100644 index 0000000..2cef23b Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/appendpoint.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/appuser.png b/tutorial/markdown/mobile/retail-demo-capella-setup/appuser.png new file mode 100644 index 0000000..6de51a3 Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/appuser.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/connectapp.png b/tutorial/markdown/mobile/retail-demo-capella-setup/connectapp.png new file mode 100644 index 0000000..2f1b8c2 Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/connectapp.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/cors1.png b/tutorial/markdown/mobile/retail-demo-capella-setup/cors1.png new file mode 100644 index 0000000..6b330bd Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/cors1.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/cors2.png b/tutorial/markdown/mobile/retail-demo-capella-setup/cors2.png new file mode 100644 index 0000000..e1edb37 Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/cors2.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/data-model.png b/tutorial/markdown/mobile/retail-demo-capella-setup/data-model.png new file mode 100644 index 0000000..c1af92d Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/data-model.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/import-data.png b/tutorial/markdown/mobile/retail-demo-capella-setup/import-data.png new file mode 100644 index 0000000..1ad9ce1 Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-capella-setup/import-data.png differ diff --git a/tutorial/markdown/mobile/retail-demo-capella-setup/retail-demo-capella-setup.md b/tutorial/markdown/mobile/retail-demo-capella-setup/retail-demo-capella-setup.md new file mode 100644 index 0000000..86e8023 --- /dev/null +++ b/tutorial/markdown/mobile/retail-demo-capella-setup/retail-demo-capella-setup.md @@ -0,0 +1,240 @@ +--- +path: "/retail-demo-capella-setup" +title: Setting Up Couchbase Capella for the Retail Demo +short_title: Capella Setup +description: + - Create a Couchbase Capella cluster and bucket + - Configure scopes and collections for multi-store inventory + - Set up App Services for mobile and web sync + - Import sample data for testing +content_type: tutorial +filter: mobile +technology: + - mobile + - capella + - app-services +tags: + - App Services + - DBaaS +sdk_language: + - any +length: 30 Mins +exclude_tutorials: true +--- + +## Introduction + +In this tutorial, you will set up the cloud backend required for the Couchbase Lite Retail Demo. This includes creating a Couchbase Capella cluster, configuring the data model with scopes and collections, and setting up App Services for real-time synchronization. + +You will learn the fundamentals of: + +* Creating a Couchbase Capella cluster +* Configuring buckets, scopes, and collections +* Importing sample data +* Setting up Capella App Services +* Configuring user authentication + +> **NOTE**: Although instructions are specified for Capella App Services, equivalent instructions apply to self-managed Sync Gateway as well. + +## Prerequisites + +* A [Couchbase Capella account](https://cloud.couchbase.com/) (free trial available) +* Basic understanding of NoSQL concepts + +## Step 1: Create a Couchbase Capella Cluster + +1. Log in to [Couchbase Capella](https://cloud.couchbase.com/) + +2. Create a new cluster by following the [official instructions](https://docs.couchbase.com/cloud/get-started/create-account.html) + +3. Wait for the cluster to be provisioned (this may take a few minutes) + +## Step 2: Create the Supermarket Bucket + +1. Navigate to your cluster in the Capella dashboard + +2. Create a bucket named **"supermarket"** by following these [instructions](https://docs.couchbase.com/cloud/clusters/data-service/about-buckets-scopes-collections.html#buckets) + +3. Use the default bucket settings for this demo + +## Step 3: Create Scopes for Each Store + +Create two scopes to represent different store locations: + +1. Navigate to the **supermarket** bucket + +2. Create a scope named **"NYC-Store"** following these [instructions](https://docs.couchbase.com/cloud/clusters/data-service/about-buckets-scopes-collections.html#scopes) + +3. Create another scope named **"AA-Store"** + +## Step 4: Create Collections + +In **each** scope (NYC-Store and AA-Store), create three collections: + +| Collection | Purpose | +|------------|---------| +| `inventory` | Product inventory items with stock levels | +| `orders` | Customer orders with status tracking | +| `profile` | Store profile and contact information | + +Follow these [instructions](https://docs.couchbase.com/cloud/clusters/data-service/scopes-collections.html#create-collection) to create each collection. + +### Expected Data Model + +After completing these steps, your cluster configuration should look like this: + +![Data Model](data-model.png) + +``` +📦 supermarket (bucket) +├── 📁 AA-Store (scope) +│ ├── 📚 inventory +│ ├── 📚 orders +│ └── 📚 profile +├── 📁 NYC-Store (scope) +│ ├── 📚 inventory +│ ├── 📚 orders +│ └── 📚 profile +├── 📁 _default (system scope) +└── 📁 _system (system scope) +``` + +## Step 5: Import Sample Data + +1. Download and unzip the sample dataset: + * [demo-dataset.zip](https://cbm-retaildemo-dataset.s3.us-west-1.amazonaws.com/demo-dataset.zip) + +2. Follow the [import instructions](https://docs.couchbase.com/cloud/clusters/data-service/import-data-documents.html#how-to-import-data) to import data into each scope/collection using inline mode + +3. **Important**: When importing data, select the **Field** option to map the document ID + +![Import Data](import-data.png) + +4. Repeat for each collection in both scopes + +## Step 6: Create App Services + +Now set up Capella App Services to enable synchronization between mobile/web clients and your Capella cluster. + +### Create the App Service + +1. Create an App Service named **"supermarket-appservice"** linked to your supermarket cluster + +2. Follow these [instructions](https://docs.couchbase.com/cloud/get-started/create-account.html#app-services) + +### Create App Endpoints + +Create two App Endpoints, one for each store scope: + +| App Endpoint Name | Linked Scope | Description | +|-------------------|--------------|-------------| +| `supermarket-aa` | AA-Store | Endpoint for AA store employees | +| `supermarket-nyc` | NYC-Store | Endpoint for NYC store employees | + +Follow these [instructions](https://docs.couchbase.com/cloud/get-started/configuring-app-services.html#create-app-endpoint) for each endpoint. + +Your App Endpoint configuration should look like this: + +![App Endpoint Configuration](appendpoint.png) + +### Link Collections to App Endpoints + +For each App Endpoint, ensure the following collections are linked: + +* ✅ `inventory` +* ✅ `orders` +* ✅ `profile` + +## Step 7: Create App Users + +Create users for each store location. These credentials will be used by the mobile and web applications to authenticate. + +### User Configuration + +| Store | Username | Password | App Endpoint | +|-------|----------|----------|--------------| +| NYC | `nyc-store-01@supermarket.com` | `P@ssword1` | supermarket-nyc | +| AA | `aa-store-01@supermarket.com` | `P@ssword1` | supermarket-aa | + +Follow these [instructions](https://docs.couchbase.com/cloud/app-services/user-management/create-user.html) to create each user. + +> **TIP**: If you want the demo apps to work with pre-filled credentials, use exactly the usernames and passwords listed above. + +Your App User configuration should look like this: + +![App User Configuration](appuser.png) + +## Step 8: Record Your Connection URL + +1. In your App Endpoint, go to the **Connect** tab + +2. Copy the **Public Connection URL** - you'll need this when configuring your apps + +![Connection URL](connectapp.png) + +The URL format is: +``` +wss://your-endpoint.apps.cloud.couchbase.com:4984/database-name +``` + +## Step 9: Configure CORS (Web Only) + +If you're running the web application, you need to enable CORS on your App Endpoints. + +> **Skip this section** if you're only testing mobile apps. + +For **each** App Endpoint (supermarket-aa and supermarket-nyc): + +1. Enable CORS from the Settings page following these [instructions](https://docs.couchbase.com/cloud/app-services/deployment/cors-configuration-for-app-services.html#about-cors-configuration) + +2. Set **Origin** as `http://localhost:8080` + +![CORS Origin](cors1.png) + +3. Set **Login Origin** as `http://localhost:8080` + +4. Set **Allowed Headers** as `Authorization` + +![CORS Headers](cors2.png) + +> **NOTE**: If your web app runs on a different port, adjust the CORS settings accordingly. + +## Verify Your Setup + +Before proceeding, verify: + +- [ ] Supermarket bucket exists with NYC-Store and AA-Store scopes +- [ ] Each scope has inventory, orders, and profile collections +- [ ] Sample data is imported into each collection +- [ ] App Services are created with endpoints for each store +- [ ] Users are created for each App Endpoint +- [ ] You have the Public Connection URL saved +- [ ] CORS is configured (if using web app) + +## Troubleshooting + +### Data Not Appearing After Import + +* Verify you selected the correct scope and collection +* Check that the Field option was used for document ID mapping +* Ensure the import completed without errors + +### App Services Connection Issues + +* Verify the App Endpoint is in "Running" state +* Check that collections are properly linked +* Ensure user credentials match exactly + +### CORS Errors (Web) + +* Verify Origin matches your development server URL exactly +* Check that Authorization is in Allowed Headers +* Ensure you saved the CORS configuration + +## Learn More + +### References + +* [Couchbase Capella Documentation](https://docs.couchbase.com/cloud/index.html) +* [App Services Documentation](https://docs.couchbase.com/cloud/app-services/index.html) +* [Scopes and Collections](https://docs.couchbase.com/cloud/clusters/data-service/about-buckets-scopes-collections.html) diff --git a/tutorial/markdown/mobile/retail-demo-peer-to-peer-sync/P2P_demo_android-android-ios.mp4 b/tutorial/markdown/mobile/retail-demo-peer-to-peer-sync/P2P_demo_android-android-ios.mp4 new file mode 100644 index 0000000..11e2825 Binary files /dev/null and b/tutorial/markdown/mobile/retail-demo-peer-to-peer-sync/P2P_demo_android-android-ios.mp4 differ diff --git a/tutorial/markdown/mobile/retail-demo-peer-to-peer-sync/retail-demo-peer-to-peer-sync.md b/tutorial/markdown/mobile/retail-demo-peer-to-peer-sync/retail-demo-peer-to-peer-sync.md new file mode 100644 index 0000000..8bbb74b --- /dev/null +++ b/tutorial/markdown/mobile/retail-demo-peer-to-peer-sync/retail-demo-peer-to-peer-sync.md @@ -0,0 +1,354 @@ +--- +path: "/retail-demo-peer-to-peer-sync" +title: Peer-to-Peer Sync Between Mobile Devices +short_title: Peer-to-Peer Sync +description: + - Learn how Couchbase Lite enables direct device-to-device synchronization + - Understand P2P sync architecture without requiring cloud connectivity + - Configure and test peer-to-peer sync between iOS and Android devices +content_type: tutorial +filter: mobile +technology: + - mobile +tags: + - Android + - iOS + - P2P +sdk_language: + - kotlin + - swift +length: 30 Mins +exclude_tutorials: true +--- + +## Introduction + +Peer-to-peer (P2P) sync is a powerful feature of Couchbase Lite Enterprise Edition that enables direct synchronization between devices on the same local network, without requiring cloud connectivity. This is particularly useful for: + +* **Offline collaboration** - Employees can sync data even when internet is unavailable +* **Demo scenarios** - Showcase real-time sync between multiple devices +* **Reduced latency** - Direct device communication is faster than going through the cloud +* **Bandwidth savings** - Keep data local when cloud sync isn't needed + +In this tutorial, you will learn: + +* How P2P sync works in Couchbase Lite +* The listener and replicator architecture +* How to configure and test P2P sync between iOS and Android devices + +## Prerequisites + +* Couchbase Lite **Enterprise Edition** (P2P is not available in Community Edition) +* Two or more devices (iOS and/or Android) +* All devices connected to the **same Wi-Fi network** +* The retail demo app installed on each device + +> **NOTE**: P2P sync is only available on iOS and Android. The web app does not support P2P sync. + +## How P2P Sync Works + +### Architecture + +P2P sync uses a **listener/replicator** model: + +``` +Device A (Listener) Device B (Replicator) +┌─────────────────────┐ ┌─────────────────────┐ +│ Couchbase Lite │◄───────►│ Couchbase Lite │ +│ + URL Listener │ P2P │ + Replicator │ +└─────────────────────┘ Sync └─────────────────────┘ + ▲ │ + │ Same Wi-Fi Network │ + └───────────────────────────────┘ +``` + +1. **Listener**: One device acts as a "server", exposing an endpoint on the local network +2. **Replicator**: Other devices connect to the listener's endpoint and sync data +3. **Discovery**: Devices use Bonjour/mDNS to discover each other automatically + +### Peer Group ID + +All devices that want to sync together use the same **Peer Group ID**. This ensures: + +* Only devices in the same group discover each other +* Data isolation between different groups/stores + +In the retail demo, the peer group ID is configured in the app settings. + +## Understanding the Code + +### iOS Implementation + +The iOS app uses `GroceryMultipeerSyncManager.swift` for P2P sync: + +**Starting the Listener:** +```swift +// Create listener configuration +let config = URLEndpointListenerConfiguration(collections: collections) +config.port = 4985 +config.disableTLS = true // For demo purposes; use TLS in production + +// Create and start listener +listener = URLEndpointListener(config: config) +try listener.start() + +// Advertise service via Bonjour +let service = NetService(domain: "local.", type: "_cblp2p._tcp.", name: peerGroupId, port: 4985) +service.publish() +``` + +**Connecting as Replicator:** +```swift +// Create endpoint URL from discovered peer +let endpoint = URLEndpoint(url: URL(string: "ws://\(peer.hostname):\(peer.port)/")!) + +// Configure replicator +var config = ReplicatorConfiguration(target: endpoint) +config.addCollections(collections, config: nil) +config.continuous = true +config.replicatorType = .pushAndPull + +// Start replication +let replicator = Replicator(config: config) +replicator.start() +``` + +### Android Implementation + +The Android app uses `MultipeerSyncManager.kt`: + +**Starting the Listener:** +```kotlin +// Create listener configuration +val config = URLEndpointListenerConfiguration(collections) +config.port = 4985 +config.isTlsDisabled = true // For demo purposes + +// Create and start listener +listener = URLEndpointListener(config) +listener.start() + +// Advertise via Network Service Discovery +val serviceInfo = NsdServiceInfo().apply { + serviceName = peerGroupId + serviceType = "_cblp2p._tcp." + port = 4985 +} +nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener) +``` + +**Discovering and Connecting:** +```kotlin +// Discover peers via NSD +nsdManager.discoverServices("_cblp2p._tcp.", NsdManager.PROTOCOL_DNS_SD, discoveryListener) + +// When peer discovered, connect +val endpoint = URLEndpoint(URI("ws://${peer.host}:${peer.port}/")) +val config = ReplicatorConfiguration(endpoint) + .addCollections(collections, null) + .setType(ReplicatorType.PUSH_AND_PULL) + .setContinuous(true) + +replicator = Replicator(config) +replicator.start() +``` + +## Configuration + +### Enabling P2P Sync + +P2P sync is controlled by configuration flags in each app: + +**iOS** (`AppConfig.swift`): +```swift +static let enableP2PSync = true +static let p2pPeerGroupId = "retail-demo-group" +``` + +**Android** (`AppConfig.kt`): +```kotlin +const val ENABLE_P2P_SYNC = true +const val P2P_PEER_GROUP_ID = "retail-demo-group" +``` + +### Important Settings + +| Setting | Description | Value | +|---------|-------------|-------| +| `enableP2PSync` | Toggle P2P functionality | `true` / `false` | +| `p2pPeerGroupId` | Identifier for peer discovery | Must match across devices | +| `port` | Listener port number | Default: `4985` | + +> **IMPORTANT**: The `p2pPeerGroupId` must be identical on all devices that should sync together. + +## Try It Out + +### Demo Video + +Watch P2P sync in action between two Android devices and an iPhone: + +![P2P Demo](P2P_demo_android-android-ios.mp4) + +### Step-by-Step Testing + +#### Step 1: Prepare Your Devices + +1. Ensure all devices are connected to the **same Wi-Fi network** +2. Install the retail demo app on each device +3. Verify P2P sync is enabled in the app configuration + +#### Step 2: Start the First Device (Listener) + +1. Launch the app on Device A +2. Log in with store credentials +3. The app will automatically start the P2P listener +4. Note: The device is now advertising its presence on the network + +#### Step 3: Connect Additional Devices + +1. Launch the app on Device B (and C, etc.) +2. Log in with the same or compatible store credentials +3. The app will discover Device A automatically +4. Sync begins when the connection is established + +#### Step 4: Test Synchronization + +1. On **Device A**: Update an inventory item (e.g., change stock quantity) +2. On **Device B**: Observe the change appear within seconds +3. Reverse the test: Make a change on Device B and watch it sync to Device A + +### Expected Behavior + +When P2P sync is working correctly: + +| Action | Result | +|--------|--------| +| Device comes online | Automatically discovers other peers | +| Data changes locally | Syncs to all connected peers | +| Device goes offline | Changes queue and sync when reconnected | +| Network changes | Automatic reconnection and re-discovery | + +## Cross-Platform P2P + +One powerful feature of the retail demo is **cross-platform P2P sync**: + +* iOS devices can sync directly with Android devices +* All use the same Couchbase Lite protocol +* Data model is identical across platforms + +### Testing iOS ↔ Android Sync + +1. Start the retail demo on an **iOS device** +2. Start the retail demo on an **Android device** +3. Ensure both are on the same Wi-Fi network +4. Log in to both with the same store credentials +5. Make changes on one device and verify they appear on the other + +## P2P vs App Services Sync + +The retail demo supports both sync methods, which can be used independently or together: + +| Feature | P2P Sync | App Services Sync | +|---------|----------|-------------------| +| **Connectivity** | Local network only | Internet required | +| **Latency** | Very low | Depends on network | +| **Offline support** | Yes (within LAN) | Yes (changes queued) | +| **Cloud backup** | No | Yes | +| **Cross-location** | No (same LAN only) | Yes | +| **Web support** | No | Yes | + +### Combined Usage + +When both are enabled: + +1. P2P syncs data between nearby devices instantly +2. App Services syncs data to the cloud for backup and cross-location access +3. Changes flow through both channels + +## Troubleshooting + +### Devices Not Discovering Each Other + +**Check network:** +* Verify all devices are on the same Wi-Fi network +* Some networks block mDNS/Bonjour traffic (common in corporate networks) +* Try using a mobile hotspot for testing + +**Check configuration:** +* Verify `p2pPeerGroupId` is identical on all devices +* Ensure P2P sync is enabled in app configuration + +**Check permissions:** +* iOS: Allow local network access when prompted +* Android: Ensure location permission is granted (required for NSD) + +### P2P Sync Slow or Unreliable + +* Check Wi-Fi signal strength on all devices +* Move devices closer together +* Reduce interference from other wireless devices + +### Connection Drops Frequently + +* Disable battery optimization for the app +* Keep the app in the foreground during testing +* Check for Wi-Fi power-saving settings + +### Only One-Way Sync + +* Verify `replicatorType` is set to `.pushAndPull` +* Check that both devices have write access to the collections + +## Security Considerations + +The demo disables TLS for simplicity, but in production you should: + +1. **Enable TLS** on the listener +2. **Use authentication** for connections +3. **Restrict peer group IDs** to authorized groups + +```swift +// Production configuration with TLS +let config = URLEndpointListenerConfiguration(collections: collections) +config.disableTLS = false +config.tlsIdentity = myTLSIdentity +config.authenticator = ListenerPasswordAuthenticator { username, password in + // Validate credentials + return username == validUsername && password == validPassword +} +``` + +## Enterprise Edition Requirement + +P2P sync requires **Couchbase Lite Enterprise Edition**. If you're using Community Edition: + +* P2P sync features will not be available +* The `URLEndpointListener` class is not included +* App Services sync still works normally + +To use the Community Edition, you would need to: + +1. Remove or comment out P2P-related code +2. Update dependencies to use Community Edition packages +3. Set `ENABLE_P2P_SYNC = false` + +## Learn More + +### References + +* [Peer-to-Peer Sync Documentation](https://docs.couchbase.com/couchbase-lite/current/swift/p2psync.html) +* [URL Endpoint Listener](https://docs.couchbase.com/couchbase-lite/current/swift/p2psync-listener.html) +* [Network Service Discovery (Android)](https://developer.android.com/training/connect-devices-wirelessly/nsd) +* [Bonjour/mDNS (iOS)](https://developer.apple.com/bonjour/) + +## Congratulations! + +You have completed the **Couchbase Lite and Offline First Retail Applications** learning path! You now know how to: + +* Build an offline-first mobile app using Couchbase Lite as a local embedded database +* Set up Couchbase Capella with the correct bucket, scope, and collection structure for a multi-store retail application +* Configure Capella App Services for real-time bidirectional synchronization between mobile clients and the cloud +* Enable peer-to-peer sync between iOS and Android devices on a local network without cloud connectivity + +You can explore the full source code of the retail demo at the [couchbase-lite-retail-demo repository](https://github.com/couchbase-examples/couchbase-lite-retail-demo). +