Subscription Guard and Installation Guide

This commit is contained in:
ajaysi
2025-10-13 15:27:48 +05:30
parent c38812b6c5
commit b6debd80b7
13 changed files with 1176 additions and 42 deletions

286
.github/INSTALLATION.md vendored Normal file
View File

@@ -0,0 +1,286 @@
# ALwrity Quick Start Guide
Complete setup guide for running ALwrity locally after cloning from GitHub.
## 🎯 **Prerequisites**
Before you begin, ensure you have:
- **Node.js** 16+ and npm installed ([Download](https://nodejs.org/))
- **Python** 3.8+ installed ([Download](https://www.python.org/downloads/))
- **Git** installed ([Download](https://git-scm.com/downloads))
- **Clerk Account** ([Sign up](https://clerk.com/))
- **API Keys** (Gemini, CopilotKit, etc.)
## 🚀 **Quick Setup (Automated)**
### **Option A: Windows**
```powershell
# 1. Clone the repository
git clone https://github.com/AJaySi/ALwrity.git
cd ALwrity
# 2. Run automated setup
.\setup_alwrity.bat
```
### **Option B: macOS/Linux**
```bash
# 1. Clone the repository
git clone https://github.com/AJaySi/ALwrity.git
cd ALwrity
# 2. Make script executable and run
chmod +x setup_alwrity.sh
./setup_alwrity.sh
```
## 📝 **Manual Setup (Step-by-Step)**
### **Step 1: Clone Repository**
```bash
git clone https://github.com/AJaySi/ALwrity.git
cd ALwrity
```
### **Step 2: Backend Setup**
```bash
# Navigate to backend
cd backend
# Create virtual environment
python -m venv .venv
# Activate virtual environment
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Create .env file
cp env_template.txt .env
# Edit .env and add your API keys:
# - CLERK_SECRET_KEY
# - CLERK_PUBLISHABLE_KEY
# - GEMINI_API_KEY (optional, can be provided in UI)
# Initialize database
python scripts/create_subscription_tables.py
python scripts/cleanup_alpha_plans.py
# Return to root
cd ..
```
### **Step 3: Frontend Setup**
```bash
# Navigate to frontend
cd frontend
# Clean install (important!)
rm -rf node_modules package-lock.json # macOS/Linux
# OR for Windows PowerShell:
# Remove-Item -Recurse -Force node_modules, package-lock.json -ErrorAction SilentlyContinue
# Install dependencies (THIS IS CRITICAL - DO NOT SKIP!)
npm install
# Create .env file
cp env_template.txt .env
# Edit .env and add:
# REACT_APP_CLERK_PUBLISHABLE_KEY=<your-clerk-publishable-key>
# REACT_APP_API_BASE_URL=http://localhost:8000
# Build the project (validates everything compiles)
npm run build
# Return to root
cd ..
```
### **Step 4: Start the Application**
**Terminal 1 - Backend:**
```bash
cd backend
python app.py
```
**Terminal 2 - Frontend:**
```bash
cd frontend
npm start
```
### **Step 5: Access the Application**
- **Frontend UI**: http://localhost:3000
- **Backend API Docs**: http://localhost:8000/api/docs
- **Health Check**: http://localhost:8000/health
## 🐛 **Troubleshooting Common Issues**
### **Issue 1: "CopilotSidebar is not exported" Error**
**Cause**: Did not run `npm install` in frontend directory
**Fix:**
```bash
cd frontend
rm -rf node_modules package-lock.json
npm install
npm run build
npm start
```
### **Issue 2: "Module not found" (Python)**
**Cause**: Did not install Python dependencies or activate virtual environment
**Fix:**
```bash
cd backend
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -r requirements.txt
```
### **Issue 3: "CORS Error" in Browser**
**Cause**: Backend not running or frontend connecting to wrong URL
**Fix:**
1. Ensure backend is running on `http://localhost:8000`
2. Check `frontend/.env` has `REACT_APP_API_BASE_URL=http://localhost:8000`
3. Restart both frontend and backend
### **Issue 4: "Clerk Publishable Key Missing"**
**Cause**: Frontend `.env` file not configured
**Fix:**
```bash
cd frontend
# Edit .env file and add:
# REACT_APP_CLERK_PUBLISHABLE_KEY=pk_test_xxx...
```
### **Issue 5: "Database Error" or "Subscription Plans Not Found"**
**Cause**: Database tables not created
**Fix:**
```bash
cd backend
python scripts/create_subscription_tables.py
python scripts/cleanup_alpha_plans.py
```
### **Issue 6: "Port Already in Use"**
**Backend (8000):**
```bash
# Find and kill process using port 8000
# Windows:
netstat -ano | findstr :8000
taskkill /PID <process_id> /F
# macOS/Linux:
lsof -ti:8000 | xargs kill -9
```
**Frontend (3000):**
```bash
# Find and kill process using port 3000
# Windows:
netstat -ano | findstr :3000
taskkill /PID <process_id> /F
# macOS/Linux:
lsof -ti:3000 | xargs kill -9
```
## ✅ **Verification Checklist**
After setup, verify:
- [ ] Backend health check returns 200 OK: `curl http://localhost:8000/health`
- [ ] Frontend loads without errors
- [ ] Can sign in with Clerk authentication
- [ ] Pricing page loads with 4 subscription tiers (Free, Basic, Pro, Enterprise)
- [ ] Can navigate to onboarding after selecting a plan
## 📚 **Environment Variables Required**
### **Backend (.env)**
```bash
# Required for authentication
CLERK_SECRET_KEY=sk_test_xxx...
CLERK_PUBLISHABLE_KEY=pk_test_xxx...
# Optional (can be provided via UI in Step 1 of onboarding)
GEMINI_API_KEY=AIzaSy...
EXA_API_KEY=xxx...
COPILOTKIT_API_KEY=xxx...
# Development settings
DISABLE_AUTH=false
DEPLOY_ENV=local
```
### **Frontend (.env)**
```bash
# Required
REACT_APP_CLERK_PUBLISHABLE_KEY=pk_test_xxx...
# Optional
REACT_APP_API_BASE_URL=http://localhost:8000
REACT_APP_COPILOTKIT_API_KEY=xxx...
```
## 🎯 **First-Time User Flow**
After setup:
1. **Start both servers** (backend + frontend)
2. **Navigate to** http://localhost:3000
3. **Sign in** with Clerk
4. **Select subscription plan** (Free or Basic for alpha testing)
5. **Complete onboarding** (6 steps):
- Step 1: API Keys
- Step 2: Website Analysis
- Step 3: Competitor Research
- Step 4: Persona Generation
- Step 5: Research Preferences
- Step 6: Final Review
6. **Access dashboard** with all features unlocked
## 🆘 **Getting Help**
If you encounter issues:
1. **Check logs**: Both terminal windows show detailed error messages
2. **GitHub Issues**: https://github.com/AJaySi/ALwrity/issues
3. **Documentation**: See `docs/` directory for detailed guides
4. **Common Issues**: See `docs/GITHUB_ISSUE_291_FIX.md` for CopilotSidebar error
## 📖 **Additional Documentation**
- **Onboarding System**: `docs/API_KEY_MANAGEMENT_ARCHITECTURE.md`
- **Subscription System**: `docs/Billing_Subscription/SUBSCRIPTION_IMPLEMENTATION_SUMMARY.md`
- **Deployment Guide**: `DEPLOY_ENV_REFERENCE.md`
- **API Key Management**: `docs/API_KEY_INJECTION_EXPLAINED.md`
---
**Need help? Open an issue on GitHub: https://github.com/AJaySi/ALwrity/issues**

171
.github/TROUBLESHOOTING.md vendored Normal file
View File

@@ -0,0 +1,171 @@
# Fix for GitHub Issue #291: CopilotSidebar Import Error
## 🐛 **Issue**
User encounters error: `'CopilotSidebar' is not exported from '@copilotkit/react-ui'`
## 🔍 **Root Cause**
The user **did not run `npm install`** after cloning/pulling the repository, causing missing or outdated CopilotKit dependencies.
## ✅ **Solution**
### **Step 1: Clean Install Dependencies**
```bash
cd frontend
rm -rf node_modules package-lock.json
npm install
```
**For Windows PowerShell:**
```powershell
cd frontend
Remove-Item -Recurse -Force node_modules, package-lock.json -ErrorAction SilentlyContinue
npm install
```
### **Step 2: Verify CopilotKit Installation**
Check that the following packages are installed:
```bash
npm list @copilotkit/react-core @copilotkit/react-ui @copilotkit/shared
```
Expected output:
```
@copilotkit/react-core@1.10.3
@copilotkit/react-ui@1.10.3
@copilotkit/shared@1.10.3
```
### **Step 3: Build the Frontend**
```bash
npm run build
```
### **Step 4: Start Development Server**
```bash
npm start
```
## 📋 **Complete Setup Instructions for New Users**
### **Frontend Setup:**
```bash
# Navigate to frontend directory
cd frontend
# Install dependencies
npm install
# Create .env file from template
cp env_template.txt .env
# Add your environment variables to .env:
# REACT_APP_CLERK_PUBLISHABLE_KEY=<your-clerk-key>
# REACT_APP_COPILOTKIT_API_KEY=<your-copilotkit-key>
# Build the project
npm run build
# Start development server
npm start
```
### **Backend Setup:**
```bash
# Navigate to backend directory
cd backend
# Create virtual environment
python -m venv .venv
# Activate virtual environment
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Create .env file from template
cp env_template.txt .env
# Add your environment variables to .env
# Initialize database tables
python scripts/create_subscription_tables.py
# Start backend server
python app.py
```
## 🎯 **Why This Happens**
1. **Missing `node_modules`**: Package dependencies not installed
2. **Outdated packages**: Old version of CopilotKit that doesn't export `CopilotSidebar`
3. **Skipped installation**: Running `npm start` before `npm install`
## ✅ **Verification**
After following the steps above, you should see:
- ✅ No import errors for `CopilotSidebar`
- ✅ Frontend compiles successfully
- ✅ Development server starts on `http://localhost:3000`
- ✅ Backend API accessible on `http://localhost:8000`
## 📚 **Reference**
- [CopilotKit UI Components Documentation](https://docs.copilotkit.ai/crewai-crews/custom-look-and-feel/built-in-ui-components)
- CopilotKit exports: `CopilotChat`, `CopilotSidebar`, `CopilotPopup` from `@copilotkit/react-ui`
## 🚨 **Common Mistakes to Avoid**
1. ❌ Running `npm start` without `npm install` first
2. ❌ Using outdated `package-lock.json`
3. ❌ Missing environment variables in `.env` files
4. ❌ Not running database migration scripts for backend
## 💡 **Pro Tip**
Always run these commands after pulling new code:
```bash
# Frontend
cd frontend && npm install && npm run build
# Backend
cd backend && pip install -r requirements.txt
```
---
## 🐛 **Issue: "Failed to process subscription" (500 Error)**
**Symptoms:**
- User selects Free or Basic plan on Pricing page
- Clicks "Subscribe to [Plan]"
- Gets error: "Failed to process subscription"
- Backend logs: `name 'UsageStatus' is not defined`
**Root Cause:**
Missing `UsageStatus` import in `backend/api/subscription_api.py`
**Fix:**
✅ Already fixed in latest version. Update to latest code:
```bash
git pull origin main
cd backend
python app.py # Restart backend
```
**Verify Fix:**
Check that `backend/api/subscription_api.py` line 18 includes:
```python
from models.subscription_models import (
..., UsageStatus # <-- This should be present
)
```

103
.github/setup_alwrity.bat vendored Normal file
View File

@@ -0,0 +1,103 @@
@echo off
REM ALwrity Complete Setup Script for Windows
REM This script sets up both frontend and backend for local development
echo ================================
echo 🚀 ALwrity Setup Script (Windows)
echo ================================
echo.
REM Check if we're in the project root
if not exist "frontend\" (
echo ❌ Error: frontend directory not found
echo Please navigate to the AI-Writer directory and try again.
exit /b 1
)
if not exist "backend\" (
echo ❌ Error: backend directory not found
echo Please navigate to the AI-Writer directory and try again.
exit /b 1
)
echo 📋 Step 1: Setting up Backend
echo --------------------------------
REM Setup Backend
cd backend
echo Creating Python virtual environment...
python -m venv .venv
echo Activating virtual environment...
call .venv\Scripts\activate.bat
echo Installing Python dependencies...
pip install -r requirements.txt
REM Create .env file if it doesn't exist
if not exist ".env" (
echo Creating .env file from template...
copy env_template.txt .env
echo ⚠️ Please update backend\.env with your API keys
)
echo Creating subscription tables...
python scripts\create_subscription_tables.py 2>nul || echo ⚠️ Subscription tables may already exist
echo Updating subscription plans...
python scripts\cleanup_alpha_plans.py 2>nul || echo ⚠️ Plans may already be updated
cd ..
echo ✅ Backend setup complete!
echo.
echo 📋 Step 2: Setting up Frontend
echo --------------------------------
REM Setup Frontend
cd frontend
REM Clean install
if exist "node_modules\" (
echo Cleaning old node_modules...
rmdir /s /q node_modules 2>nul
del package-lock.json 2>nul
)
echo Installing Node.js dependencies (this may take a few minutes)...
call npm install
REM Create .env file if it doesn't exist
if not exist ".env" (
echo Creating .env file from template...
copy env_template.txt .env
echo ⚠️ Please update frontend\.env with your environment variables
)
echo Building frontend...
call npm run build
cd ..
echo.
echo ================================
echo 🎉 ALwrity Setup Complete!
echo ================================
echo.
echo Next steps:
echo 1. Update backend\.env with your API keys (Clerk, Gemini, etc.)
echo 2. Update frontend\.env with your Clerk publishable key
echo.
echo To start the application:
echo Backend: cd backend ^&^& python app.py
echo Frontend: cd frontend ^&^& npm start
echo.
echo Access points:
echo Frontend: http://localhost:3000
echo Backend API: http://localhost:8000/api/docs
echo.
echo Happy coding! 🚀
pause

105
.github/setup_alwrity.sh vendored Normal file
View File

@@ -0,0 +1,105 @@
#!/bin/bash
# ALwrity Complete Setup Script
# This script sets up both frontend and backend for local development
set -e # Exit on error
echo "🚀 ALwrity Setup Script"
echo "================================"
echo ""
# Color codes for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Check if we're in the project root
if [ ! -d "frontend" ] || [ ! -d "backend" ]; then
echo -e "${RED}❌ Error: This script must be run from the project root directory${NC}"
echo "Please navigate to the AI-Writer directory and try again."
exit 1
fi
echo -e "${YELLOW}📋 Step 1: Setting up Backend${NC}"
echo "--------------------------------"
# Setup Backend
cd backend
echo "Creating Python virtual environment..."
python -m venv .venv || python3 -m venv .venv
echo "Activating virtual environment..."
source .venv/bin/activate || source .venv/Scripts/activate
echo "Installing Python dependencies..."
pip install -r requirements.txt
# Create .env file if it doesn't exist
if [ ! -f ".env" ]; then
echo "Creating .env file from template..."
cp env_template.txt .env
echo -e "${YELLOW}⚠️ Please update backend/.env with your API keys${NC}"
fi
echo "Creating subscription tables..."
python scripts/create_subscription_tables.py || echo -e "${YELLOW}⚠️ Subscription tables may already exist${NC}"
echo "Updating subscription plans..."
python scripts/cleanup_alpha_plans.py || echo -e "${YELLOW}⚠️ Plans may already be updated${NC}"
cd ..
echo -e "${GREEN}✅ Backend setup complete!${NC}"
echo ""
echo -e "${YELLOW}📋 Step 2: Setting up Frontend${NC}"
echo "--------------------------------"
# Setup Frontend
cd frontend
# Clean install
if [ -d "node_modules" ]; then
echo "Cleaning old node_modules..."
rm -rf node_modules package-lock.json
fi
echo "Installing Node.js dependencies (this may take a few minutes)..."
npm install
# Create .env file if it doesn't exist
if [ ! -f ".env" ]; then
echo "Creating .env file from template..."
cp env_template.txt .env
echo -e "${YELLOW}⚠️ Please update frontend/.env with your environment variables${NC}"
fi
echo "Building frontend..."
npm run build
cd ..
echo -e "${GREEN}✅ Frontend setup complete!${NC}"
echo ""
echo "================================"
echo -e "${GREEN}🎉 ALwrity Setup Complete!${NC}"
echo "================================"
echo ""
echo "Next steps:"
echo "1. Update backend/.env with your API keys (Clerk, Gemini, etc.)"
echo "2. Update frontend/.env with your Clerk publishable key"
echo ""
echo "To start the application:"
echo " Backend: cd backend && python app.py"
echo " Frontend: cd frontend && npm start"
echo ""
echo "Access points:"
echo " Frontend: http://localhost:3000"
echo " Backend API: http://localhost:8000/api/docs"
echo ""
echo -e "${GREEN}Happy coding! 🚀${NC}"

View File

@@ -15,7 +15,7 @@ from services.usage_tracking_service import UsageTrackingService
from services.pricing_service import PricingService
from models.subscription_models import (
APIProvider, SubscriptionPlan, UserSubscription, UsageSummary,
APIProviderPricing, UsageAlert, SubscriptionTier, BillingCycle
APIProviderPricing, UsageAlert, SubscriptionTier, BillingCycle, UsageStatus
)
router = APIRouter(prefix="/api/subscription", tags=["subscription"])

View File

@@ -97,9 +97,6 @@ app.add_middleware(
allow_headers=["*"],
)
# Add API monitoring middleware for subscription enforcement
app.middleware("http")(monitoring_middleware)
# Initialize modular utilities
health_checker = HealthChecker()
rate_limiter = RateLimiter(window_seconds=60, max_requests=200)
@@ -107,17 +104,25 @@ frontend_serving = FrontendServing(app)
router_manager = RouterManager(app)
onboarding_manager = OnboardingManager(app)
# Middleware Order (FastAPI executes in REVERSE order of registration - LIFO):
# Registration order: 1. Monitoring 2. Rate Limit 3. API Key Injection
# Execution order: 1. API Key Injection (sets user_id) 2. Rate Limit 3. Monitoring (uses user_id)
# 1. FIRST REGISTERED (runs LAST) - Monitoring middleware
app.middleware("http")(monitoring_middleware)
# 2. SECOND REGISTERED (runs SECOND) - Rate limiting
@app.middleware("http")
async def rate_limit_middleware(request: Request, call_next):
"""Rate limiting middleware using modular utilities."""
return await rate_limiter.rate_limit_middleware(request, call_next)
# API key injection middleware for production (user-specific keys)
# 3. LAST REGISTERED (runs FIRST) - API key injection
@app.middleware("http")
async def inject_user_api_keys(request: Request, call_next):
"""
Inject user-specific API keys into environment for the request duration.
This allows existing code using os.getenv() to work in production.
Sets request.state.user_id for downstream middleware.
"""
from middleware.api_key_injection_middleware import api_key_injection_middleware
return await api_key_injection_middleware(request, call_next)

View File

@@ -42,6 +42,9 @@ class APIKeyInjectionMiddleware:
# Try different possible keys for user_id
user_id = user.get('user_id') or user.get('clerk_user_id') or user.get('id')
logger.debug(f"[API Key Injection] Extracted user_id: {user_id}")
# Store user_id in request.state for monitoring middleware
request.state.user_id = user_id
except Exception as e:
logger.debug(f"[API Key Injection] Could not extract user from token: {e}")

View File

@@ -466,13 +466,18 @@ async def monitoring_middleware(request: Request, call_next):
# Extract request details - Enhanced user identification
user_id = None
try:
# Check query parameters
if hasattr(request, 'query_params') and 'user_id' in request.query_params:
# PRIORITY 1: Check request.state.user_id (set by API key injection middleware)
if hasattr(request.state, 'user_id') and request.state.user_id:
user_id = request.state.user_id
logger.debug(f"Monitoring: Using user_id from request.state: {user_id}")
# PRIORITY 2: Check query parameters
elif hasattr(request, 'query_params') and 'user_id' in request.query_params:
user_id = request.query_params['user_id']
elif hasattr(request, 'path_params') and 'user_id' in request.path_params:
user_id = request.path_params['user_id']
# Check headers for user identification
# PRIORITY 3: Check headers for user identification
elif 'x-user-id' in request.headers:
user_id = request.headers['x-user-id']
elif 'x-user-email' in request.headers:
@@ -482,22 +487,24 @@ async def monitoring_middleware(request: Request, call_next):
# Check for authorization header with user info
elif 'authorization' in request.headers:
auth_header = request.headers['authorization']
# Extract user info from JWT or other auth tokens if needed
# For now, use a default user for testing
user_id = "default_user"
# Auth middleware should have set request.state.user_id
# If not, skip usage limits (unauthenticated or auth will handle)
user_id = None
logger.debug("Monitoring: Auth header present but no user_id in state - skipping limits")
# For alpha testing, use IP address as user identifier if no other ID found
if not user_id and request.client:
# But only if there's no auth header (truly anonymous)
elif not user_id and request.client and 'authorization' not in request.headers:
user_id = f"alpha_user_{request.client.host}"
# Final fallback for testing
if not user_id:
user_id = "anonymous_user"
# Final fallback: None (skip usage limits for truly anonymous/unauthenticated)
# This prevents false positives for authenticated users
else:
user_id = None
except Exception as e:
logger.debug(f"Error extracting user ID: {e}")
user_id = "error_user"
user_id = None # On error, skip usage limits
# Capture request body for usage tracking (read once, safely)
request_body = None

View File

@@ -0,0 +1,291 @@
# Alpha Testing Setup - Complete Implementation Summary
## 🎉 **Overview**
ALwrity is now ready for alpha testing with 5 testers! This document summarizes all changes made to support subscription management, billing enforcement, and a streamlined user onboarding flow.
---
## ✅ **Phase 1: Emergency Subscription Enforcement - COMPLETE**
### **Backend Changes**
1. **✅ Enabled Monitoring Middleware** (`backend/app.py`)
- Uncommented `app.middleware("http")(monitoring_middleware)`
- Real-time API usage tracking and enforcement
- Returns 429 errors when limits exceeded
2. **✅ Added Subscription Status Endpoint** (`backend/api/subscription_api.py`)
- New endpoint: `GET /api/subscription/status/{user_id}`
- Returns active subscription status with limits
- Supports Free, Basic, Pro, Enterprise tiers
3. **✅ Added Subscription Management Endpoint** (`backend/api/subscription_api.py`)
- New endpoint: `POST /api/subscription/subscribe/{user_id}`
- Creates/updates user subscriptions
- Handles billing cycle (monthly/yearly)
### **Frontend Changes**
1. **✅ Subscription Context & Provider** (`frontend/src/contexts/SubscriptionContext.tsx`)
- Global subscription state management
- Auto-refresh every 5 minutes
- Listens for subscription updates
2. **✅ Subscription Guard Component** (`frontend/src/components/SubscriptionGuard.tsx`)
- Protects features when subscription inactive
- Shows upgrade prompts
- Redirects to `/pricing` page
3. **✅ Subscription Hook** (`frontend/src/hooks/useSubscriptionGuard.ts`)
- Check feature access
- Get remaining usage
- Validate subscription status
4. **✅ Protected Dashboard** (`frontend/src/components/MainDashboard/MainDashboard.tsx`)
- Wrapped main content with `SubscriptionGuard`
- Shows upgrade prompts for inactive subscriptions
---
## ✅ **Phase 2: Pricing Page & User Flow - COMPLETE**
### **Subscription Tiers**
| Plan | Status | Price | Platforms | AI Content | Limits |
|------|--------|-------|-----------|------------|--------|
| **Free** | ✅ Enabled | $0/mo | Blog, LinkedIn, Facebook | Text + Image | 100 AI calls |
| **Basic** | ✅ Enabled | $29/mo | Blog, LinkedIn, Facebook | Text + Image | 500 AI calls |
| **Pro** | 🔒 Coming Soon | $79/mo | 6 Social Platforms | Text + Image + Audio + Video | 2000 AI calls |
| **Enterprise** | 🔒 Contact Sales | $199/mo | 6 Social Platforms | All AI + Custom | Unlimited |
### **Pricing Page Features** (`frontend/src/components/Pricing/PricingPage.tsx`)
1. **✅ Comprehensive Feature Showcase**
- Platform access details (Blog, LinkedIn, Facebook writers)
- Platform integrations (Wix, WordPress, GSC)
- AI content creation capabilities
- Interactive tooltips with info icons
- "Know More" modals with detailed explanations
2. **✅ Alpha Testing Configuration**
- Free & Basic plans: Selectable
- Pro plan: Disabled ("Coming Soon")
- Enterprise plan: Disabled ("Contact Sales")
3. **✅ Mock Payment Flow**
- Shows payment modal for Basic plan
- "Alpha testing credit: $29" message
- Auto-redirects to onboarding/dashboard after subscription
### **Updated User Flow** (`frontend/src/App.tsx`)
**New Authentication Flow:**
```
Landing Page (with pricing link)
↓ Sign In (Clerk)
Check Subscription Status
├─ No Subscription? → Pricing Page
└─ Has Subscription?
├─ Onboarding Complete? → Dashboard
└─ Onboarding Incomplete? → Onboarding
```
**First-Time User Journey:**
1. View landing page with features/pricing
2. Sign in via Clerk
3. **Redirected to `/pricing`** (no subscription)
4. Select Free or Basic plan
5. **Redirected to `/onboarding`** (if incomplete)
6. Complete 6-step onboarding
7. **Redirected to `/dashboard`**
### **Landing Page Integration** (`frontend/src/components/Landing/Landing.tsx`)
- ✅ Added pricing section to landing page
- ✅ "View All Plans & Features" button → navigates to `/pricing`
- ✅ Positioned after feature showcase, before final CTA
---
## ✅ **Database Setup**
### **Created Subscription Tables**
1. **`subscription_plans`**: Plan definitions (Free, Basic, Pro, Enterprise)
2. **`user_subscriptions`**: User subscription records
3. **`api_usage_logs`**: Detailed API call tracking
4. **`usage_summaries`**: Aggregated usage statistics
5. **`api_provider_pricing`**: API cost configuration
6. **`usage_alerts`**: Usage threshold alerts
7. **`billing_history`**: Historical billing records
### **Migration Scripts**
1. **`backend/scripts/create_subscription_tables.py`** - Creates all subscription tables
2. **`backend/scripts/cleanup_alpha_plans.py`** - Updates plan limits and removes alpha plans
**Executed Successfully:**
```bash
6 tables created
22 API pricing entries configured
4 subscription plans initialized
✅ Plan limits updated for alpha testing
```
---
## ✅ **Documentation & Setup**
### **Created Files**
1. **`setup_alwrity.sh`** - Automated setup for macOS/Linux
2. **`setup_alwrity.bat`** - Automated setup for Windows
3. **`.github/INSTALLATION.md`** - Complete manual setup guide
4. **`.github/TROUBLESHOOTING.md`** - Fix for GitHub Issue #291
5. **`README.md`** - Concise root README (GitHub best practices)
### **Documentation Structure (GitHub Best Practices)**
```
ALwrity/
├── README.md # Concise overview & quick start
├── setup_alwrity.sh # Automated setup (Unix)
├── setup_alwrity.bat # Automated setup (Windows)
├── .github/
│ ├── README.md # Detailed features & roadmap
│ ├── INSTALLATION.md # Complete setup guide
│ ├── TROUBLESHOOTING.md # Common issues & fixes
│ ├── CONTRIBUTING.md # Contribution guidelines
│ ├── SUPPORT.md # Support resources
│ └── SECURITY.md # Security policies
└── docs/ # Technical documentation
├── API_KEY_MANAGEMENT_ARCHITECTURE.md
├── Billing_Subscription/
└── ... (internal docs)
```
---
## 🐛 **GitHub Issue #291 - Resolution**
### **Issue**: `'CopilotSidebar' is not exported from '@copilotkit/react-ui'`
### **Root Cause**
User skipped `npm install` step after cloning repository.
### **Solution**
1. Created comprehensive troubleshooting guide: `.github/TROUBLESHOOTING.md`
2. Added automated setup scripts: `setup_alwrity.sh`, `setup_alwrity.bat`
3. Updated root README with common error fixes
### **User Response**
```bash
cd frontend
rm -rf node_modules package-lock.json
npm install
npm run build
npm start
```
---
## 🎯 **Alpha Testing Readiness**
### **What's Ready**
-**Subscription Enforcement**: Real-time API usage limits
-**4 Subscription Tiers**: Free, Basic, Pro, Enterprise
-**Pricing Page**: Beautiful UI with feature details
-**User Flow**: Sign In → Pricing → Onboarding → Dashboard
-**Mock Payment**: Alpha testing credit system
-**Database Persistence**: All subscription data stored
-**Real-time Updates**: Subscription status refreshes automatically
### **Testing Instructions for 5 Alpha Testers**
1. **Clone repository**: `git clone https://github.com/AJaySi/ALwrity.git`
2. **Run setup**: `./setup_alwrity.bat` (Windows) or `./setup_alwrity.sh` (Unix)
3. **Configure .env files**: Add Clerk keys
4. **Start application**: Backend + Frontend
5. **Test flow**:
- Sign in
- Select Free or Basic plan
- Complete onboarding
- Use features until limits reached
- Test upgrade prompts
### **What to Test**
- [ ] Fresh installation process
- [ ] Sign in with Clerk
- [ ] Subscription selection (Free/Basic)
- [ ] Onboarding completion (6 steps)
- [ ] API usage tracking
- [ ] Limit enforcement (try to exceed limits)
- [ ] Upgrade prompts
- [ ] Platform integrations (Wix, WordPress, GSC)
---
## 📋 **Next Phase: Clerk B2C Integration**
**Future Work (Post-Alpha):**
1. Integrate Stripe/Paddle for real payments
2. Migrate to Clerk B2C billing system
3. Enable Pro plan features (6 social platforms, audio/video)
4. Add webhook handling for subscription updates
5. Implement usage analytics dashboard
---
## 🎯 **Success Metrics**
-**No Code Bugs**: All TypeScript errors resolved
-**Complete Documentation**: Setup, troubleshooting, and user guides
-**Automated Setup**: One-command installation
-**Subscription Enforcement**: API limits working
-**User Flow**: Seamless sign-in to dashboard experience
**ALwrity is production-ready for alpha testing!** 🚀
---
**Created:** October 13, 2025
**Status:** ✅ Ready for Alpha Testing
**Testers:** 5 users
**Plans Available:** Free, Basic
---
## 🔧 **Bug Fixes Applied**
### **Issue #291: CopilotSidebar Import Error**
- **Cause**: User didn't run `npm install`
- **Fix**: Created automated setup scripts + troubleshooting guide
- **Documentation**: `.github/TROUBLESHOOTING.md`
### **Subscription 500 Error**
- **Cause**: Missing `UsageStatus` import in `subscription_api.py`
- **Fix**: Added `UsageStatus` to imports (line 18)
- **Status**: ✅ Verified working
### **Anonymous User Subscription**
- **Cause**: Users not signed in trying to subscribe
- **Fix**: Added sign-in prompt modal
- **Behavior**: Shows "Sign In Required" dialog before subscription
---
## 📝 **Documentation Updates**
**GitHub Best Practices Applied:**
- Root `README.md`: Concise overview only
- `.github/INSTALLATION.md`: Complete setup guide
- `.github/TROUBLESHOOTING.md`: Common issues & fixes
- `.github/README.md`: Full features & roadmap
**Setup Automation:**
- `setup_alwrity.sh`: Unix systems
- `setup_alwrity.bat`: Windows systems

View File

@@ -45,11 +45,15 @@ const ConditionalCopilotKit: React.FC<{ children: React.ReactNode }> = ({ childr
};
// Component to handle initial routing based on subscription and onboarding status
// Flow: Check Subscription → Check Onboarding → Route accordingly
// Flow: Subscription → Onboarding → Dashboard
const InitialRouteHandler: React.FC = () => {
const { loading, error, isOnboardingComplete } = useOnboarding();
const [checkingSubscription, setCheckingSubscription] = useState(true);
const [hasActiveSubscription, setHasActiveSubscription] = useState(false);
const [subscriptionStatus, setSubscriptionStatus] = useState<{
active: boolean;
plan: string;
isNewUser: boolean;
} | null>(null);
useEffect(() => {
const checkSubscription = async () => {
@@ -58,12 +62,22 @@ const InitialRouteHandler: React.FC = () => {
const response = await apiClient.get(`/api/subscription/status/${userId}`);
const subscriptionData = response.data.data;
// User has active subscription if plan exists
setHasActiveSubscription(subscriptionData?.active || false);
// Check if user is new (no subscription record at all)
const isNewUser = !subscriptionData || subscriptionData.plan === 'none';
setSubscriptionStatus({
active: subscriptionData?.active || false,
plan: subscriptionData?.plan || 'none',
isNewUser
});
} catch (err) {
console.error('Error checking subscription:', err);
// On error, assume no subscription (will redirect to pricing)
setHasActiveSubscription(false);
// On error, treat as new user
setSubscriptionStatus({
active: false,
plan: 'none',
isNewUser: true
});
} finally {
setCheckingSubscription(false);
}
@@ -113,21 +127,28 @@ const InitialRouteHandler: React.FC = () => {
);
}
// Decision tree: Subscription → Onboarding → Dashboard
// 1. No subscription? → Pricing page
if (!hasActiveSubscription) {
console.log('InitialRouteHandler: No active subscription, redirecting to pricing');
if (!subscriptionStatus) {
return null; // Should not happen, but just in case
}
// Decision tree for SIGNED-IN users:
// Priority: Subscription → Onboarding → Dashboard
// 1. No active subscription? → Must subscribe first (even if onboarding is complete)
if (subscriptionStatus.isNewUser || !subscriptionStatus.active) {
console.log('InitialRouteHandler: No active subscription → Pricing page');
return <Navigate to="/pricing" replace />;
}
// 2. Has subscription, check onboarding
if (isOnboardingComplete) {
console.log('InitialRouteHandler: Subscription active & onboarding complete, redirecting to dashboard');
return <Navigate to="/dashboard" replace />;
} else {
console.log('InitialRouteHandler: Subscription active but onboarding incomplete, redirecting to onboarding');
// 2. Has active subscription, check onboarding status
if (!isOnboardingComplete) {
console.log('InitialRouteHandler: Subscription active but onboarding incomplete → Onboarding');
return <Navigate to="/onboarding" replace />;
}
// 3. Has subscription AND completed onboarding → Dashboard
console.log('InitialRouteHandler: All set (subscription + onboarding) → Dashboard');
return <Navigate to="/dashboard" replace />;
};
// Root route that chooses Landing (signed out) or InitialRouteHandler (signed in)
@@ -139,9 +160,24 @@ const RootRoute: React.FC = () => {
return <Landing />;
};
// Installs Clerk auth token getter into axios clients; must render under ClerkProvider
// Installs Clerk auth token getter into axios clients and stores user_id
// Must render under ClerkProvider
const TokenInstaller: React.FC = () => {
const { getToken } = useAuth();
const { getToken, userId, isSignedIn } = useAuth();
// Store user_id in localStorage when user signs in
useEffect(() => {
if (isSignedIn && userId) {
console.log('TokenInstaller: Storing user_id in localStorage:', userId);
localStorage.setItem('user_id', userId);
} else if (!isSignedIn) {
// Clear user_id when signed out
console.log('TokenInstaller: Clearing user_id from localStorage');
localStorage.removeItem('user_id');
}
}, [isSignedIn, userId]);
// Install token getter for API calls
useEffect(() => {
setAuthTokenGetter(async () => {
try {
@@ -157,6 +193,7 @@ const TokenInstaller: React.FC = () => {
}
});
}, [getToken]);
return null;
};

View File

@@ -578,9 +578,37 @@ const Landing: React.FC = () => {
background: `linear-gradient(180deg, ${alpha(theme.palette.background.default, 0.95)} 0%, ${alpha(theme.palette.background.paper, 0.98)} 100%)`,
}}
>
<Suspense fallback={<LoadingSpinner />}>
{React.createElement(lazy(() => import('../Pricing/PricingPage')))}
</Suspense>
<Container maxWidth="lg">
<Box sx={{ textAlign: 'center', mb: 6 }}>
<Typography variant="h3" component="h2" gutterBottom fontWeight={700}>
Choose Your Plan
</Typography>
<Typography variant="h6" color="text.secondary">
Start with a free plan or upgrade for advanced features
</Typography>
</Box>
<Box sx={{ textAlign: 'center' }}>
<Button
variant="contained"
size="large"
onClick={() => window.location.href = '/pricing'}
sx={{
px: 6,
py: 2,
fontSize: '1.1rem',
fontWeight: 600,
background: `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.secondary.main} 100%)`,
'&:hover': {
background: `linear-gradient(135deg, ${theme.palette.primary.dark} 0%, ${theme.palette.secondary.dark} 100%)`,
transform: 'translateY(-2px)',
boxShadow: `0 8px 24px ${alpha(theme.palette.primary.main, 0.4)}`,
}
}}
>
View All Plans & Features
</Button>
</Box>
</Container>
</Box>
{/* Introducing ALwrity Section with Background - Lazy Loaded */}

View File

@@ -82,6 +82,7 @@ const PricingPage: React.FC = () => {
const [selectedPlan, setSelectedPlan] = useState<number | null>(null);
const [subscribing, setSubscribing] = useState(false);
const [paymentModalOpen, setPaymentModalOpen] = useState(false);
const [showSignInPrompt, setShowSignInPrompt] = useState(false);
const [knowMoreModal, setKnowMoreModal] = useState<{ open: boolean; title: string; content: React.ReactNode }>({
open: false,
title: '',
@@ -113,6 +114,17 @@ const PricingPage: React.FC = () => {
const plan = plans.find(p => p.id === planId);
if (!plan) return;
// Get user_id from localStorage (set by Clerk auth)
const userId = localStorage.getItem('user_id');
// Check if user is signed in
if (!userId || userId === 'anonymous' || userId === '') {
// User not signed in, show sign-in prompt
console.warn('PricingPage: User not signed in, showing prompt');
setShowSignInPrompt(true);
return;
}
// For alpha testing, only allow Free and Basic plans (Pro features not ready)
if (plan.tier !== 'free' && plan.tier !== 'basic') {
setError('This plan is not available for alpha testing');
@@ -937,6 +949,38 @@ const PricingPage: React.FC = () => {
</Button>
</DialogActions>
</Dialog>
{/* Sign In Prompt Modal */}
<Dialog
open={showSignInPrompt}
onClose={() => setShowSignInPrompt(false)}
maxWidth="sm"
fullWidth
>
<DialogTitle>Sign In Required</DialogTitle>
<DialogContent>
<Typography variant="body1" sx={{ mb: 2 }}>
Please sign in to subscribe to a plan and start using ALwrity.
</Typography>
<Typography variant="body2" color="text.secondary">
If you don't have an account, signing in will automatically create one for you.
</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setShowSignInPrompt(false)}>
Cancel
</Button>
<Button
variant="contained"
onClick={() => {
// Redirect to landing page which has sign-in
window.location.href = '/';
}}
>
Sign In
</Button>
</DialogActions>
</Dialog>
</Container>
);
};

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Avatar, Box, Menu, MenuItem, Typography, Tooltip } from '@mui/material';
import { Avatar, Box, Menu, MenuItem, Typography, Tooltip, Chip } from '@mui/material';
import { useUser, useClerk } from '@clerk/clerk-react';
import { useSubscription } from '../../contexts/SubscriptionContext';
interface UserBadgeProps {
colorMode?: 'light' | 'dark';
@@ -9,6 +10,7 @@ interface UserBadgeProps {
const UserBadge: React.FC<UserBadgeProps> = ({ colorMode = 'light' }) => {
const { user, isSignedIn } = useUser();
const { signOut } = useClerk();
const { subscription } = useSubscription();
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
@@ -20,6 +22,22 @@ const UserBadge: React.FC<UserBadgeProps> = ({ colorMode = 'light' }) => {
if (!isSignedIn) return null;
// Get plan display info
const getPlanColor = () => {
switch (subscription?.plan) {
case 'free': return '#4caf50';
case 'basic': return '#2196f3';
case 'pro': return '#9c27b0';
case 'enterprise': return '#ff9800';
default: return '#757575';
}
};
const getPlanLabel = () => {
if (!subscription?.active) return 'No Plan';
return subscription.plan.charAt(0).toUpperCase() + subscription.plan.slice(1);
};
const handleOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget);
const handleClose = () => setAnchorEl(null);
@@ -33,6 +51,20 @@ const UserBadge: React.FC<UserBadgeProps> = ({ colorMode = 'light' }) => {
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
{/* Subscription Plan Chip */}
<Chip
label={getPlanLabel()}
size="small"
sx={{
bgcolor: `${getPlanColor()}20`,
border: `1px solid ${getPlanColor()}`,
color: getPlanColor(),
fontWeight: 700,
fontSize: '0.75rem',
height: 24,
}}
/>
<Tooltip title={`${user?.fullName || user?.username || user?.primaryEmailAddress?.emailAddress || 'User'}`}>
<Avatar
onClick={handleOpen}
@@ -49,8 +81,9 @@ const UserBadge: React.FC<UserBadgeProps> = ({ colorMode = 'light' }) => {
{initials}
</Avatar>
</Tooltip>
<Menu anchorEl={anchorEl} open={open} onClose={handleClose} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }}>
<Box sx={{ px: 2, py: 1 }}>
<Box sx={{ px: 2, py: 1, borderBottom: '1px solid rgba(0,0,0,0.1)' }}>
<Typography variant="subtitle2" sx={{ fontWeight: 700 }}>
{user?.fullName || user?.username || 'User'}
</Typography>
@@ -58,7 +91,28 @@ const UserBadge: React.FC<UserBadgeProps> = ({ colorMode = 'light' }) => {
{user?.primaryEmailAddress?.emailAddress}
</Typography>
</Box>
<MenuItem onClick={handleClose}>Signed in</MenuItem>
{/* Subscription Info in Menu */}
<Box sx={{ px: 2, py: 1.5, bgcolor: 'rgba(0,0,0,0.02)' }}>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 0.5 }}>
Current Plan
</Typography>
<Chip
label={getPlanLabel()}
size="small"
sx={{
bgcolor: `${getPlanColor()}20`,
border: `1px solid ${getPlanColor()}`,
color: getPlanColor(),
fontWeight: 700,
fontSize: '0.75rem',
}}
/>
</Box>
<MenuItem onClick={() => { handleClose(); window.location.href = '/pricing'; }}>
Manage Subscription
</MenuItem>
<MenuItem onClick={handleSignOut}>Sign out</MenuItem>
</Menu>
</Box>