Subscription Database Setup

Follow these steps to create the external subscription validation database

2Create AppSubscription Entity

In the new app: Dashboard → Data → New Entity → Name it "AppSubscription" → Paste this schema:

{
  "name": "AppSubscription",
  "type": "object",
  "properties": {
    "app_id": {
      "type": "string",
      "description": "Unique identifier for the subscribed app"
    },
    "app_name": {
      "type": "string",
      "description": "Name of the app (e.g., 'Shot Tracker Production')"
    },
    "user_email": {
      "type": "string",
      "description": "Email of the subscribed user"
    },
    "subscription_status": {
      "type": "string",
      "enum": ["active", "expired", "cancelled", "suspended"],
      "default": "active",
      "description": "Current status of the subscription"
    },
    "start_date": {
      "type": "string",
      "format": "date-time",
      "description": "When the subscription started"
    },
    "end_date": {
      "type": "string",
      "format": "date-time",
      "description": "When the subscription expires"
    },
    "subscription_key": {
      "type": "string",
      "description": "Unique subscription key (UUID) for this app instance"
    },
    "payment_reference": {
      "type": "string",
      "description": "Payment transaction reference"
    },
    "notes": {
      "type": "string",
      "description": "Admin notes"
    }
  },
  "required": ["app_id", "user_email", "subscription_status", "end_date"],
  "rls": {
    "create": {
      "user_condition": { "role": "admin" }
    },
    "read": {
      "user_condition": { "role": "admin" }
    },
    "update": {
      "user_condition": { "role": "admin" }
    },
    "delete": {
      "user_condition": { "role": "admin" }
    }
  }
}

3Create Backend Function

Dashboard → Code → Functions → New Function → Name it "validateAppSubscription" → Paste this code:

import { createClientFromRequest } from 'npm:@base44/sdk@0.8.6';

Deno.serve(async (req) => {
  try {
    // Parse request body
    const { app_id, user_email, user_role } = await req.json();

    // Verify API key
    const authHeader = req.headers.get('Authorization');
    const expectedKey = Deno.env.get('SUBSCRIPTION_API_KEY');
    
    if (!authHeader || authHeader !== `Bearer ${expectedKey}`) {
      return Response.json({ 
        valid: false, 
        message: 'Unauthorized' 
      }, { status: 401 });
    }

    // Admin users always have access
    if (user_role === 'admin') {
      return Response.json({
        valid: true,
        message: 'Admin access granted',
        subscription_status: 'admin',
        expires_at: null
      });
    }

    // Create service role client
    const base44 = createClientFromRequest(req);

    // Look up subscription
    const subscriptions = await base44.asServiceRole.entities.AppSubscription.filter({
      app_id: app_id,
      user_email: user_email
    });

    if (subscriptions.length === 0) {
      return Response.json({
        valid: false,
        message: 'No subscription found',
        subscription_status: 'not_found'
      });
    }

    // Get most recent subscription
    const subscription = subscriptions
      .sort((a, b) => new Date(b.created_date) - new Date(a.created_date))[0];

    const now = new Date();
    const endDate = new Date(subscription.end_date);
    const isExpired = now > endDate;
    const isActive = subscription.subscription_status === 'active';

    const valid = isActive && !isExpired;

    return Response.json({
      valid: valid,
      message: valid ? 'Subscription active' : 'Subscription expired or inactive',
      subscription_status: subscription.subscription_status,
      expires_at: subscription.end_date,
      days_remaining: valid ? Math.ceil((endDate - now) / (1000 * 60 * 60 * 24)) : 0
    });

  } catch (error) {
    console.error('Validation error:', error);
    return Response.json({ 
      valid: false, 
      message: 'Validation error: ' + error.message 
    }, { status: 500 });
  }
});

4Generate API Key

Open terminal and run this command to generate a secure API key:

openssl rand -base64 32

In the subscription database app: Dashboard → Settings → Secrets → Add SUBSCRIPTION_API_KEY with the generated key

5Get Function URL

In subscription database app: Dashboard → Code → Functions → validateAppSubscription → Copy the function URL

It will look like: https://your-app.base44.app/api/validateAppSubscription

6Configure Shot Tracker App

Come back to THIS app: Dashboard → Settings → Secrets → Add these two secrets:

SUBSCRIPTION_API_URL

The function URL from step 5

SUBSCRIPTION_API_KEY

The same API key you set in step 4

7Create Test Subscription

In subscription database app: Dashboard → Data → AppSubscription → Add Record

app_id: Get from THIS app's Dashboard → Settings → App ID

app_name: "Shot Tracker Test"

user_email: Your email

subscription_status: "active"

start_date: Today

end_date: 180 days from now

Testing

  1. Reload this Shot Tracker app - should work normally
  2. In subscription database, change subscription_status to "expired"
  3. Reload Shot Tracker - should show "Subscription Expired" modal
  4. Change back to "active" - access restored