Просмотр исходного кода

docs: add ShopRenter app development getting started guide #72

Claude 5 месяцев назад
Родитель
Сommit
9a7db069f3
1 измененных файлов с 602 добавлено и 0 удалено
  1. 602 0
      docs/shoprenter_app_development.md

+ 602 - 0
docs/shoprenter_app_development.md

@@ -0,0 +1,602 @@
+# ShopRenter App Development: Getting Started
+
+## Overview
+
+This document provides comprehensive guidance for developing applications that integrate with the ShopRenter e-commerce platform. ShopRenter apps can be either Embedded (loaded within the ShopRenter admin interface) or Redirected (external applications).
+
+**Reference**: This documentation is based on the official ShopRenter developer documentation at [doc.shoprenter.hu/development/app-development](https://doc.shoprenter.hu/development/app-development/01_getting_started.html).
+
+## Application Registration
+
+### Required Information
+
+Before developing a ShopRenter app, you must register your application by contacting ShopRenter Partner Support at **partnersupport@shoprenter.hu** with the following details:
+
+#### 1. Basic Information
+- **Application Name** - The name that will appear in the ShopRenter installable apps list
+- **Logo** - Image file with dimensions **250x150 pixels**
+- **Description** - Brief description of your app (maximum **70 characters**)
+- **Details Link** - URL to your application's sales/information page
+
+#### 2. Technical Configuration
+- **EntryPoint** - The HTTPS URL where your app is hosted
+  - Must use HTTPS protocol
+  - This is where ShopRenter will load your application
+
+- **RedirectUri** - The HTTPS authentication endpoint
+  - Receives authentication data during the OAuth flow
+  - Must use HTTPS protocol
+  - **Important**: Hash-based URL routes in SPAs (Single Page Applications) are technically incompatible
+
+- **UninstallUri** - The HTTPS endpoint called when app is uninstalled
+  - Receives GET request with query parameters: `shopname`, `code`, `timestamp`, `hmac`
+  - Must use HTTPS protocol
+  - Use this to clean up data and revoke access tokens
+
+#### 3. Application Type
+Choose one of two application types:
+
+**Embedded Application**
+- Loaded in an iframe within the ShopRenter admin interface
+- Accessible at: `[shopname].myshoprenter.hu/admin/app/[id]`
+- Provides seamless integration with the admin UI
+- Best for tools that complement the admin interface
+
+**Redirected Application**
+- External application that users are directed to
+- Directs users to the EntryPoint URL
+- Best for standalone tools or services
+
+#### 4. API Access
+- **Required Scopes** - List of API permissions your app needs
+  - Review available scopes in the ShopRenter API documentation
+  - Request only the permissions necessary for your app's functionality
+  - Users will see and approve these permissions during installation
+
+#### 5. Testing Environment
+- **Test Store Name** - Request a test store via [shoprenter.hu](https://shoprenter.hu)
+  - Format: `[shopName].myshoprenter.hu`
+  - Use this for development and testing before production release
+
+### Credentials You'll Receive
+
+After registration, ShopRenter Partner Support will provide:
+
+- **AppId** - Unique application identifier
+- **ClientId** - OAuth client identifier
+- **ClientSecret** - Secret key for HMAC validation and authentication
+- **App URL** - The registered application URL
+
+**⚠️ Security**: Keep your ClientSecret secure and never expose it in client-side code!
+
+## Installation Flow
+
+Understanding the installation process is critical for implementing your app correctly.
+
+### Step-by-Step Installation Process
+
+#### 1. User Initiates Installation
+- Shop owner browses the ShopRenter app marketplace
+- Clicks to install your application
+
+#### 2. ShopRenter Calls RedirectUri
+ShopRenter makes a GET request to your RedirectUri with these query parameters:
+
+- `shopname` - The shop's name (e.g., "example-shop")
+- `code` - Authorization code for token exchange
+- `timestamp` - Unix timestamp of the request
+- `hmac` - HMAC-SHA256 signature for validation
+- `app_url` - The URL where your app should redirect after validation
+
+**Example Request**:
+```
+https://your-app.com/auth/callback?shopname=example-shop&code=abc123&timestamp=1234567890&hmac=xyz789&app_url=https://example-shop.myshoprenter.hu/admin/app/123
+```
+
+#### 3. HMAC Validation (Critical Security Step)
+Your application MUST validate the HMAC signature to ensure the request is legitimate:
+
+**HMAC Validation Process**:
+1. Extract all query parameters except `hmac`
+2. Sort parameters alphabetically by key
+3. Create a query string: `key1=value1&key2=value2`
+4. Compute HMAC-SHA256 hash using your ClientSecret
+5. Compare computed hash with received `hmac` parameter
+6. If they match, the request is authentic
+
+**Example Validation (Pseudocode)**:
+```javascript
+function validateHmac(params, clientSecret) {
+  const { hmac, ...dataToValidate } = params;
+
+  // Sort parameters alphabetically
+  const sortedParams = Object.keys(dataToValidate)
+    .sort()
+    .map(key => `${key}=${dataToValidate[key]}`)
+    .join('&');
+
+  // Compute HMAC-SHA256
+  const computedHmac = crypto
+    .createHmac('sha256', clientSecret)
+    .update(sortedParams)
+    .digest('hex');
+
+  // Compare hashes
+  return computedHmac === hmac;
+}
+```
+
+**⚠️ Security Warning**: Never skip HMAC validation! This protects against unauthorized access attempts.
+
+#### 4. Token Exchange
+After validating the HMAC, exchange the authorization code for access tokens:
+
+- Use the `code` parameter from the callback
+- Make a POST request to ShopRenter's token endpoint
+- Receive `access_token` and `refresh_token`
+- Store tokens securely in your database
+
+**Note**: Basic Authentication is **deprecated**. Attempting to use Basic Auth will return **403 Forbidden** errors.
+
+#### 5. Redirect to App URL
+After successful token exchange:
+- Redirect the user to the `app_url` received in step 2
+- ShopRenter will then load your EntryPoint with authentication parameters
+
+#### 6. Application Loads
+- ShopRenter loads your EntryPoint (in iframe for Embedded apps)
+- Your app can now access the ShopRenter API using the obtained tokens
+
+### Installation Flow Diagram
+
+```
+┌──────────────┐
+│ Shop Owner   │
+│ Clicks       │
+│ "Install"    │
+└──────┬───────┘
+       │
+       ▼
+┌──────────────┐
+│ ShopRenter   │
+│ Calls        │
+│ RedirectUri  │
+└──────┬───────┘
+       │ (shopname, code, timestamp, hmac, app_url)
+       ▼
+┌──────────────────┐
+│ Your App         │
+│ Validates HMAC   │
+└──────┬───────────┘
+       │ ✓ Valid
+       ▼
+┌──────────────────┐
+│ Your App         │
+│ Exchanges Code   │
+│ for Tokens       │
+└──────┬───────────┘
+       │ (access_token, refresh_token)
+       ▼
+┌──────────────────┐
+│ Store Tokens     │
+│ in Database      │
+└──────┬───────────┘
+       │
+       ▼
+┌──────────────────┐
+│ Redirect to      │
+│ app_url          │
+└──────┬───────────┘
+       │
+       ▼
+┌──────────────────┐
+│ ShopRenter Loads │
+│ Your EntryPoint  │
+└──────────────────┘
+```
+
+## OAuth 2.0 Authentication
+
+ShopRenter uses OAuth 2.0 for secure API authentication.
+
+### Token Types
+
+#### Access Token
+- Used to authenticate API requests
+- Includes: `Authorization: Bearer {access_token}` header
+- Has a limited lifetime (expires after a period)
+- Must be refreshed when expired
+
+#### Refresh Token
+- Used to obtain new access tokens
+- Longer lifetime than access tokens
+- Store securely in your database
+
+### Token Management
+
+#### Storing Tokens
+Store tokens securely in your database with:
+- `store_id` - Unique identifier for the shop
+- `access_token` - Current access token
+- `refresh_token` - Refresh token for token renewal
+- `token_expires_at` - Timestamp when access token expires
+- `shopname` - Shop identifier
+
+**Database Example**:
+```sql
+CREATE TABLE shoprenter_tokens (
+  id UUID PRIMARY KEY,
+  store_id UUID REFERENCES stores(id),
+  access_token TEXT NOT NULL,
+  refresh_token TEXT,
+  expires_at TIMESTAMPTZ,
+  shopname VARCHAR NOT NULL,
+  scopes TEXT[],
+  created_at TIMESTAMPTZ DEFAULT NOW(),
+  updated_at TIMESTAMPTZ DEFAULT NOW()
+);
+```
+
+#### Token Refresh
+When an access token expires:
+1. Detect 401 Unauthorized response from API
+2. Use refresh token to request new access token
+3. Update stored access token and expiration time
+4. Retry the original API request
+
+**Token Refresh Flow**:
+```javascript
+async function refreshAccessToken(storeId) {
+  const store = await getStoreTokens(storeId);
+
+  const response = await fetch('https://oauth.shoprenter.hu/token', {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({
+      grant_type: 'refresh_token',
+      refresh_token: store.refresh_token,
+      client_id: CLIENT_ID,
+      client_secret: CLIENT_SECRET
+    })
+  });
+
+  const { access_token, expires_in } = await response.json();
+
+  await updateStoreToken(storeId, {
+    access_token,
+    token_expires_at: new Date(Date.now() + expires_in * 1000)
+  });
+
+  return access_token;
+}
+```
+
+### API Authentication
+
+All API requests must include the access token in the Authorization header:
+
+```http
+GET /products HTTP/1.1
+Host: example-shop.api.shoprenter.hu
+Authorization: Bearer {access_token}
+```
+
+## Scope Management
+
+Scopes define the permissions your app has to access ShopRenter resources.
+
+### Requesting Scopes
+
+When registering your app, request only the scopes necessary for your app's functionality. Common scopes include:
+
+- `read_products` - Read product catalog
+- `read_orders` - Access order information
+- `read_customers` - View customer data
+- `read_inventory` - Check inventory levels
+- And more (see ShopRenter API documentation for complete list)
+
+### Adding New Scopes
+
+If you need to add features requiring additional permissions:
+
+1. **Contact Partner Support** - Request the new scopes
+2. **Update App Registration** - ShopRenter updates your app's scope list
+3. **Request User Consent** - Existing installations need shop owner approval
+
+### Scope Approval for Existing Installations
+
+After new scopes are added, shop owners must approve them by visiting:
+
+```
+https://{shopName}.myshoprenter.hu/admin/app/{clientId}/approveScopes
+```
+
+**Implementation Steps**:
+1. Detect missing permissions (API returns permission errors)
+2. Notify shop owner about new features requiring permissions
+3. Provide a link to the approval URL
+4. After approval, your app has access to the new scopes
+
+**Example User Flow**:
+```javascript
+function requestScopeApproval(shopName, clientId) {
+  const approvalUrl = `https://${shopName}.myshoprenter.hu/admin/app/${clientId}/approveScopes`;
+
+  // Show notification to shop owner
+  showNotification({
+    message: 'New features available! Please approve additional permissions.',
+    action: {
+      text: 'Approve Permissions',
+      url: approvalUrl
+    }
+  });
+}
+```
+
+## Uninstallation Flow
+
+When a shop owner uninstalls your app, ShopRenter sends a GET request to your UninstallUri.
+
+### Uninstall Request Parameters
+
+The request includes these query parameters:
+- `shopname` - The shop's name
+- `code` - Uninstall verification code
+- `timestamp` - Unix timestamp
+- `hmac` - HMAC-SHA256 signature for validation
+
+**Example Request**:
+```
+https://your-app.com/uninstall?shopname=example-shop&code=xyz789&timestamp=1234567890&hmac=abc123
+```
+
+### Handling Uninstallation
+
+Your UninstallUri endpoint should:
+
+1. **Validate HMAC** - Ensure the request is legitimate (same process as installation)
+2. **Clean Up Data** - Remove or anonymize shop-specific data
+3. **Revoke Tokens** - Delete stored access and refresh tokens
+4. **Log Event** - Record the uninstallation for analytics
+5. **Return Success** - Respond with 200 OK status
+
+**Example Handler**:
+```javascript
+async function handleUninstall(req) {
+  const { shopname, code, timestamp, hmac } = req.query;
+
+  // 1. Validate HMAC
+  if (!validateHmac(req.query, CLIENT_SECRET)) {
+    return res.status(401).json({ error: 'Invalid HMAC' });
+  }
+
+  // 2. Find store
+  const store = await findStoreByShopname(shopname);
+
+  // 3. Clean up data
+  await deleteStoreData(store.id);
+
+  // 4. Revoke tokens
+  await deleteStoreTokens(store.id);
+
+  // 5. Mark as inactive
+  await markStoreInactive(store.id);
+
+  // 6. Log event
+  await logUninstallEvent(store.id, timestamp);
+
+  return res.status(200).json({ success: true });
+}
+```
+
+## Development Best Practices
+
+### Security
+
+1. **Always Validate HMAC** - On both installation and uninstallation requests
+2. **Use HTTPS** - All endpoints must use secure HTTPS connections
+3. **Secure Token Storage** - Encrypt tokens at rest in your database
+4. **Rotate Secrets** - Periodically rotate your ClientSecret (coordinate with Partner Support)
+5. **Rate Limiting** - Implement rate limiting for API calls to avoid throttling
+6. **Error Handling** - Handle API errors gracefully and provide helpful feedback
+
+### OAuth Implementation
+
+1. **Token Refresh** - Implement automatic token refresh before expiration
+2. **Retry Logic** - Retry failed API calls with exponential backoff
+3. **Scope Validation** - Check that you have required scopes before making requests
+4. **State Management** - Use state parameter in OAuth flow to prevent CSRF attacks
+
+### User Experience
+
+1. **Loading States** - Show loading indicators during API operations
+2. **Error Messages** - Provide clear, actionable error messages
+3. **Onboarding** - Guide new users through setup and configuration
+4. **Documentation** - Provide comprehensive user documentation
+5. **Support** - Offer responsive customer support
+
+### Testing
+
+1. **Test Store** - Use your test store for development and testing
+2. **Edge Cases** - Test token expiration, network failures, and permission errors
+3. **HMAC Validation** - Verify HMAC validation works correctly
+4. **Uninstall Flow** - Test the complete uninstall process
+5. **Multi-Shop** - Test with multiple shops if supporting multi-shop scenarios
+
+## API Usage
+
+### Base URL
+
+All API requests go to:
+```
+https://{shopname}.api.shoprenter.hu
+```
+
+Replace `{shopname}` with the shop's actual name.
+
+### Making API Requests
+
+**Example: Fetching Products**
+```javascript
+async function fetchProducts(shopname, accessToken) {
+  const response = await fetch(
+    `https://${shopname}.api.shoprenter.hu/products`,
+    {
+      headers: {
+        'Authorization': `Bearer ${accessToken}`,
+        'Content-Type': 'application/json'
+      }
+    }
+  );
+
+  if (!response.ok) {
+    if (response.status === 401) {
+      // Token expired, refresh and retry
+      const newToken = await refreshAccessToken(storeId);
+      return fetchProducts(shopname, newToken);
+    }
+    throw new Error(`API Error: ${response.status}`);
+  }
+
+  return response.json();
+}
+```
+
+### Pagination
+
+ShopRenter API supports pagination for large datasets:
+
+```javascript
+async function fetchAllProducts(shopname, accessToken) {
+  let allProducts = [];
+  let page = 1;
+  let hasMore = true;
+
+  while (hasMore) {
+    const response = await fetch(
+      `https://${shopname}.api.shoprenter.hu/products?page=${page}&limit=100`,
+      {
+        headers: {
+          'Authorization': `Bearer ${accessToken}`,
+          'Content-Type': 'application/json'
+        }
+      }
+    );
+
+    const data = await response.json();
+    allProducts = allProducts.concat(data.items);
+
+    hasMore = data.items.length === 100;
+    page++;
+  }
+
+  return allProducts;
+}
+```
+
+### Rate Limiting
+
+Implement rate limiting to respect API quotas:
+
+```javascript
+class RateLimiter {
+  constructor(maxRequests = 5, perSecond = 1) {
+    this.maxRequests = maxRequests;
+    this.perSecond = perSecond;
+    this.queue = [];
+    this.processing = false;
+  }
+
+  async request(fn) {
+    return new Promise((resolve, reject) => {
+      this.queue.push({ fn, resolve, reject });
+      this.processQueue();
+    });
+  }
+
+  async processQueue() {
+    if (this.processing || this.queue.length === 0) return;
+
+    this.processing = true;
+    const { fn, resolve, reject } = this.queue.shift();
+
+    try {
+      const result = await fn();
+      resolve(result);
+    } catch (error) {
+      reject(error);
+    }
+
+    setTimeout(() => {
+      this.processing = false;
+      this.processQueue();
+    }, (1000 / this.maxRequests) * this.perSecond);
+  }
+}
+
+const limiter = new RateLimiter(5, 1); // 5 requests per second
+
+// Usage
+await limiter.request(() => fetchProducts(shopname, token));
+```
+
+## Reference Resources
+
+ShopRenter provides example implementations to help you get started:
+
+### Example Applications
+
+1. **SR Demo App (PHP)** - Basic PHP implementation
+2. **PHP Slim Framework** - REST API implementation using Slim
+3. **Node.js** - JavaScript/Node.js implementation
+
+These examples are available on GitHub (referenced in ShopRenter documentation).
+
+### Documentation Links
+
+- **App Development Guide**: [doc.shoprenter.hu/development/app-development](https://doc.shoprenter.hu/development/app-development/01_getting_started.html)
+- **API Documentation**: [doc.shoprenter.hu/api](https://doc.shoprenter.hu/api/)
+- **Payment API**: [doc.shoprenter.hu/paymentapi](https://doc.shoprenter.hu/paymentapi/)
+
+## ShopCall.ai Integration
+
+This project (ShopCall.ai) implements ShopRenter integration with the following components:
+
+### Edge Functions
+- `oauth-shoprenter-init` - Initiates OAuth flow
+- `oauth-shoprenter-callback` - Handles OAuth callback
+- `webhook-shoprenter-uninstall` - Handles app uninstallation
+- `shoprenter-sync` - Manual data synchronization
+- `shoprenter-scheduled-sync` - Automated background sync (hourly via pg_cron)
+
+### API Client
+- `_shared/shoprenter-client.ts` - ShopRenter API client with token refresh
+
+### Data Sync
+- Products, orders, and customers cached in Supabase tables
+- Automatic token refresh when expired
+- Rate limiting (5 requests/second)
+- Retry logic with exponential backoff
+
+### Database Tables
+- `shoprenter_tokens` - Token management
+- `shoprenter_products_cache` - Cached product data
+- `pending_shoprenter_installs` - Temporary OAuth state
+- `oauth_states` - OAuth flow state management
+- `sync_logs` - Sync execution tracking
+- `store_sync_config` - Per-store sync configuration
+
+See `CLAUDE.md` for complete implementation details.
+
+## Getting Help
+
+For questions or issues:
+
+1. **ShopRenter Partner Support**: partnersupport@shoprenter.hu
+2. **Developer Documentation**: [doc.shoprenter.hu](https://doc.shoprenter.hu)
+3. **API Documentation**: [doc.shoprenter.hu/api](https://doc.shoprenter.hu/api/)
+
+---
+
+*Last Updated: 2025-01-30*
+*Based on: ShopRenter Developer Documentation - App Development - Getting Started*