feat: Complete platform enhancement with multi-tenant architecture

Major additions:
- Territory manager system with application workflow
- Custom pricing and page builder with Craft.js
- Enhanced Stripe Connect onboarding
- CodeReadr QR scanning integration
- Kiosk mode for venue sales
- Super admin dashboard and analytics
- MCP integration for AI-powered operations

Infrastructure improvements:
- Centralized API client and routing system
- Enhanced authentication with organization context
- Comprehensive theme management system
- Advanced event management with custom tabs
- Performance monitoring and accessibility features

Database schema updates:
- Territory management tables
- Custom pages and pricing structures
- Kiosk PIN system
- Enhanced organization profiles
- CodeReadr integration tables

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-12 18:21:40 -06:00
parent a02d64a86c
commit 26a87d0d00
232 changed files with 33175 additions and 5365 deletions

View File

@@ -0,0 +1,216 @@
export const prerender = false;
import type { APIRoute } from 'astro';
import { stripe } from '../../../lib/stripe';
import { supabase, supabaseAdmin } from '../../../lib/supabase';
import { verifyAuth } from '../../../lib/auth';
import { logUserActivity } from '../../../lib/logger';
export const GET: APIRoute = async ({ request }) => {
try {
// Verify authentication
const authContext = await verifyAuth(request);
if (!authContext) {
console.error('Account status check failed: Unauthorized request');
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
const { user } = authContext;
// Get user's organization ID first (using admin client to bypass RLS)
const { data: userData, error: userError } = await (supabaseAdmin || supabase)
.from('users')
.select('organization_id')
.eq('id', user.id)
.single();
if (userError || !userData?.organization_id) {
console.error('Account status check failed: Organization not found', {
userId: user.id,
userEmail: user.email,
error: userError
});
return new Response(JSON.stringify({
error: 'Organization not found',
debug: {
userId: user.id,
userEmail: user.email,
userData,
userError
}
}), {
status: 404,
headers: { 'Content-Type': 'application/json' }
});
}
// Now get the organization details
const { data: organization, error: orgError } = await (supabaseAdmin || supabase)
.from('organizations')
.select(`
id,
name,
stripe_account_id,
account_status,
stripe_onboarding_status,
stripe_details_submitted,
stripe_charges_enabled,
stripe_payouts_enabled,
onboarding_completed_at
`)
.eq('id', userData.organization_id)
.single();
if (orgError || !organization) {
console.error('Account status check failed: Organization details not found', {
userId: user.id,
organizationId: userData.organization_id,
error: orgError
});
return new Response(JSON.stringify({
error: 'Organization details not found',
debug: {
userId: user.id,
userEmail: user.email,
organizationId: userData.organization_id,
orgError
}
}), {
status: 404,
headers: { 'Content-Type': 'application/json' }
});
}
// If no Stripe account exists, return basic status
if (!organization.stripe_account_id) {
console.log('No Stripe account found for organization', {
userId: user.id,
organizationId: organization.id,
organizationName: organization.name,
accountStatus: organization.account_status
});
return new Response(JSON.stringify({
account_status: organization.account_status,
stripe_onboarding_status: 'not_started',
can_start_onboarding: organization.account_status === 'approved',
details_submitted: false,
charges_enabled: false,
payouts_enabled: false,
requirements: {
currently_due: [],
eventually_due: [],
past_due: []
}
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
// Get detailed status from Stripe
console.log('Retrieving Stripe account status', {
userId: user.id,
organizationId: organization.id,
stripeAccountId: organization.stripe_account_id
});
const account = await stripe.accounts.retrieve(organization.stripe_account_id);
// Determine overall onboarding status
let onboarding_status = 'in_progress';
if (account.details_submitted && account.charges_enabled) {
onboarding_status = 'completed';
} else if (account.details_submitted) {
onboarding_status = 'pending_review';
}
console.log('Stripe account status retrieved', {
stripeAccountId: organization.stripe_account_id,
detailsSubmitted: account.details_submitted,
chargesEnabled: account.charges_enabled,
payoutsEnabled: account.payouts_enabled,
onboardingStatus: onboarding_status,
requirementsCount: {
currentlyDue: account.requirements?.currently_due?.length || 0,
eventuallyDue: account.requirements?.eventually_due?.length || 0,
pastDue: account.requirements?.past_due?.length || 0
}
});
// Update organization with latest Stripe status
const { error: updateError } = await (supabaseAdmin || supabase)
.from('organizations')
.update({
stripe_onboarding_status: onboarding_status,
stripe_details_submitted: account.details_submitted,
stripe_charges_enabled: account.charges_enabled,
stripe_payouts_enabled: account.payouts_enabled,
...(onboarding_status === 'completed' && !organization.onboarding_completed_at && {
onboarding_completed_at: new Date().toISOString(),
account_status: 'active'
})
})
.eq('id', organization.id);
if (updateError) {
console.error('Failed to update organization with latest Stripe status', {
organizationId: organization.id,
error: updateError
});
}
// Log status check if onboarding was completed
if (onboarding_status === 'completed' && organization.stripe_onboarding_status !== 'completed') {
await logUserActivity({
userId: user.id,
action: 'stripe_onboarding_completed',
resourceType: 'organization',
resourceId: organization.id,
details: {
stripe_account_id: organization.stripe_account_id,
charges_enabled: account.charges_enabled,
payouts_enabled: account.payouts_enabled
}
});
}
return new Response(JSON.stringify({
account_status: onboarding_status === 'completed' ? 'active' : organization.account_status,
stripe_onboarding_status: onboarding_status,
can_start_onboarding: organization.account_status === 'approved',
details_submitted: account.details_submitted,
charges_enabled: account.charges_enabled,
payouts_enabled: account.payouts_enabled,
requirements: {
currently_due: account.requirements?.currently_due || [],
eventually_due: account.requirements?.eventually_due || [],
past_due: account.requirements?.past_due || []
},
stripe_account_id: organization.stripe_account_id,
business_type: account.business_type,
country: account.country,
default_currency: account.default_currency,
created: account.created
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
console.error('Account status check failed with unexpected error', {
error: error instanceof Error ? error.message : error,
stack: error instanceof Error ? error.stack : undefined
});
return new Response(JSON.stringify({
error: 'Failed to check account status',
details: error instanceof Error ? error.message : 'Unknown error'
}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
};