mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 10:19:43 +00:00
Update
This commit is contained in:
1 parent
f46f0d59df
commit
3ca3da4501
5 files changed
+40
-2
No files matched your search
@@ -95,6 +95,7 @@ Edge functions in `apps/supabase/functions/` handle complex operations:
|
|||||||
- `send-notification` - Push notifications for matches
|
- `send-notification` - Push notifications for matches
|
||||||
- `revenuecat-webhook` - Subscription webhook handler
|
- `revenuecat-webhook` - Subscription webhook handler
|
||||||
- `sync-subscription` - Syncs RevenueCat subscription status
|
- `sync-subscription` - Syncs RevenueCat subscription status
|
||||||
|
- `redeem-code` - Redeems promotional codes for premium access (website only)
|
||||||
|
|
||||||
#### Edge Function Deployment Guidelines
|
#### Edge Function Deployment Guidelines
|
||||||
When deploying edge functions via MCP tools (`mcp__sauci-*__deploy_edge_function`):
|
When deploying edge functions via MCP tools (`mcp__sauci-*__deploy_edge_function`):
|
||||||
@@ -118,6 +119,7 @@ This approach:
|
|||||||
| `submit-response` | false | Manual via getUser() |
|
| `submit-response` | false | Manual via getUser() |
|
||||||
| `sync-subscription` | false | Manual via getUser() |
|
| `sync-subscription` | false | Manual via getUser() |
|
||||||
| `delete-relationship` | false | Manual via getUser() |
|
| `delete-relationship` | false | Manual via getUser() |
|
||||||
|
| `redeem-code` | false | Manual via getUser() |
|
||||||
| `revenuecat-webhook` | false | Webhook signature validation |
|
| `revenuecat-webhook` | false | Webhook signature validation |
|
||||||
| `send-notification` | false | Internal trigger (no auth) |
|
| `send-notification` | false | Internal trigger (no auth) |
|
||||||
| `send-message-notification` | false | Internal trigger (no auth) |
|
| `send-message-notification` | false | Internal trigger (no auth) |
|
||||||
@@ -134,6 +136,26 @@ This approach:
|
|||||||
- RevenueCat handles in-app purchases and subscription management
|
- RevenueCat handles in-app purchases and subscription management
|
||||||
- RLS policies enforce couple-level data isolation
|
- RLS policies enforce couple-level data isolation
|
||||||
|
|
||||||
|
### Redemption Code System
|
||||||
|
Promotional codes that grant users premium access. **Codes can only be redeemed on the website, NOT in the mobile app.**
|
||||||
|
|
||||||
|
**Database Tables:**
|
||||||
|
- `redemption_codes` - Stores codes with max_uses, current_uses, expiration, active status
|
||||||
|
- `code_redemptions` - Tracks which users redeemed which codes
|
||||||
|
|
||||||
|
**Components:**
|
||||||
|
- **Admin UI** (`apps/admin/src/pages/RedemptionCodesPage.tsx`) - Super admins can generate, manage, and view redemption codes
|
||||||
|
- **Edge Function** (`apps/supabase/functions/redeem-code/`) - Validates and processes code redemption
|
||||||
|
- **Database Function** (`redeem_code(p_code)`) - Atomic redemption with validation (active, not expired, has uses remaining, user hasn't redeemed)
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. Admin generates code in admin dashboard
|
||||||
|
2. User enters code on website (NOT mobile app)
|
||||||
|
3. `redeem-code` edge function calls `redeem_code()` database function
|
||||||
|
4. On success, user's `profiles.is_premium` is set to `true`
|
||||||
|
|
||||||
|
**Important:** Do NOT add redemption code UI to the mobile app. Apple requires in-app purchases for premium features purchased within iOS apps.
|
||||||
|
|
||||||
## Mobile UI - DO NOT CHANGE
|
## Mobile UI - DO NOT CHANGE
|
||||||
|
|
||||||
### Tab Bar Background
|
### Tab Bar Background
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { UserDetailPage } from '@/pages/users/UserDetailPage';
|
|||||||
import { MatchChatPage } from '@/pages/users/MatchChatPage';
|
import { MatchChatPage } from '@/pages/users/MatchChatPage';
|
||||||
import { AuditLogsPage } from '@/pages/AuditLogsPage';
|
import { AuditLogsPage } from '@/pages/AuditLogsPage';
|
||||||
import { AdminsPage } from '@/pages/admins/AdminsPage';
|
import { AdminsPage } from '@/pages/admins/AdminsPage';
|
||||||
|
import { RedemptionCodesPage } from '@/pages/RedemptionCodesPage';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
@@ -72,6 +73,14 @@ function App() {
|
|||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/redemption-codes"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute requireSuperAdmin>
|
||||||
|
<RedemptionCodesPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/audit-logs"
|
path="/audit-logs"
|
||||||
element={
|
element={
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
LogOut,
|
LogOut,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
Shield,
|
Shield,
|
||||||
|
Ticket,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
@@ -47,6 +48,12 @@ const systemNav: NavItem[] = [
|
|||||||
icon: <Shield className="h-5 w-5" />,
|
icon: <Shield className="h-5 w-5" />,
|
||||||
requireSuperAdmin: true,
|
requireSuperAdmin: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Redemption Codes',
|
||||||
|
href: '/redemption-codes',
|
||||||
|
icon: <Ticket className="h-5 w-5" />,
|
||||||
|
requireSuperAdmin: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Audit Logs',
|
label: 'Audit Logs',
|
||||||
href: '/audit-logs',
|
href: '/audit-logs',
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const AUDITED_TABLES = [
|
|||||||
'subscriptions',
|
'subscriptions',
|
||||||
'feedback',
|
'feedback',
|
||||||
'admin_users',
|
'admin_users',
|
||||||
|
'redemption_codes',
|
||||||
|
'code_redemptions',
|
||||||
];
|
];
|
||||||
|
|
||||||
type AuditAction = 'INSERT' | 'UPDATE' | 'DELETE';
|
type AuditAction = 'INSERT' | 'UPDATE' | 'DELETE';
|
||||||
|
|||||||
@@ -109,8 +109,6 @@ android {
|
|||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
// Caution! In production, you need to generate your own keystore file.
|
|
||||||
// see https://reactnative.dev/docs/signed-apk-android.
|
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
||||||
minifyEnabled enableProguardInReleaseBuilds
|
minifyEnabled enableProguardInReleaseBuilds
|
||||||
|
|||||||
Reference in new issue
Block a user