- Aashir Mallik β aashir.mallik@mail.utoronto.ca (utorid: mallika9)
- Mealad Ebadi β mealad.ebadi@mail.utoronto.ca (utorid: ebadimea)
- Ji Sung Han β jishan.han@mail.utoronto.ca (utorid: hanji11)
DEPLOYED AT - https://draw2play.xyz/dashboard\
DEMO VIDEO - https://youtu.be/VdPCRcsOttc
Draw2StoryPlay is a creative web application that allows children to draw simple sketches and generate fully animated storybooks or interactive 2D games from their creations using AI.
Users draw directly on a canvas and input a prompt (e.g., "This stickman goes on a space adventure"). Our system then generates:
- an illustrated storybook with text-to-speech and pronunciation highlighting, and/or
- a simple interactive animation/game where the drawn character can walk, jump, and interact.
Main Features:
- βοΈ Real-time collaborative drawing canvas
- π AI-generated stories with voice support and letter highlighting for learning
- πΉοΈ Basic animations (walking, jumping, attacking) for stick figure characters
- π§Έ Export as storybook or playable 2D experience
- π Shareable marketplace (with review, feedback, and reusability features)
| Component | Technology |
|---|---|
| Frontend | Vue 3 (SPA with Composition API) |
| Backend | Express.js (REST API) |
| Main Database | PostgreSQL |
| Realtime Feature | Socket.IO |
| Task Queue | BullMQ with Redis |
| Authentication | OAuth 2.0 (Google login) |
| Payments | Stripe Checkout (Sandbox mode, subscription required) |
| Deployment | Google Cloud VM + Docker + Docker Compose |
| CI/CD | GitHub Actions |
-
Real-Time Functionality
Collaborative drawing board that reflects changes across users without refreshing (via Socket.IO) -
Task Queue Functionality
Story and animation generation is handled asynchronously through task queues (BullMQ + Redis)
| Version | Goals |
|---|---|
| πΉ Alpha | Set up drawing board, basic OAuth login, REST API scaffold |
| πΉ Beta | Implement real-time collaboration, AI story/game generation with task queue, Stripe integration |
| πΉ Final | Full animation system, storybook/game export, GCP deployment, CI/CD setup |
The application will be deployed on a Google Cloud Virtual Machine using Docker and Docker Compose. All Docker and CI/CD configuration files will be included in the repository. The deployed application will be publicly accessible without needing whitelisting or extra credentials.
- OAuth 2.0 (Google) authentication
- Stripe Checkout in sandbox mode (subscription required to access app)
- Subscription status determines login behavior:
- No subscription β redirect to payment page
- Cancelled/failure β block access
- User data securely stored (hashed passwords, encrypted sensitive fields)
This app promotes creative storytelling, reading, and digital literacy among children by turning their imagination into stories and simple games.
It combines education and entertainment, while fostering collaboration and sharing through a marketplace system.
=======
A modern Single Page Application built with Vue 3 and Express.js featuring Google OAuth 2.0 authentication and Stripe subscription management.
- Google OAuth 2.0 Authentication - Secure login with Google accounts
- Stripe Subscription Management - Monthly subscription billing with CLI testing
- Protected Routes - Access control based on subscription status
- Modern UI - Clean, responsive design with Tailwind CSS
- Secure Backend - JWT tokens, webhook validation, and encrypted data
- Real-time Updates - Subscription status updates via webhooks
- Local Development - Stripe CLI integration for easy testing
- Vue 3 with Composition API
- TypeScript
- Vue Router
- Tailwind CSS
- Stripe.js
- Express.js
- SQLite Database
- JWT Authentication
- Stripe SDK
- Google OAuth 2.0
- Node.js 18+ and npm
- Google Cloud Platform account
- Stripe account (test mode)
- Stripe CLI (for local development)
# Install frontend dependencies
npm install
# Install backend dependencies
cd server
npm install
cd ..macOS (Homebrew):
brew install stripe/stripe-cli/stripeWindows (Chocolatey):
choco install stripeLinux/Manual Installation: Download from Stripe CLI releases
Authenticate with Stripe:
stripe login- Go to Google Cloud Console
- Create a new project or select existing one
- Enable Google+ API
- Create OAuth 2.0 credentials:
- Choose Web application
- Add authorized redirect URI:
http://localhost:5173/auth/callback
- Copy Client ID and Client Secret
- Go to Stripe Dashboard
- Switch to Test mode
- Go to Developers β API keys
- Copy Publishable and Secret keys
- Go to Products β Add product
- Set name: "Monthly Subscription"
- Set pricing: Recurring, Monthly, $9.99
- Copy the Price ID (starts with
price_)
CRITICAL: This step is required for payment testing!
- Start the webhook listener (keep this running during development):
stripe listen --forward-to localhost:3000/webhook- Copy the webhook signing secret from the CLI output:
> Ready! Your webhook signing secret is whsec_1234567890abcdef...- Important: The webhook secret changes each time you restart the CLI, so you'll need to update your environment files accordingly.
Frontend (.env):
VITE_GOOGLE_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
VITE_API_URL=http://localhost:3000
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_publishable_keyBackend (server/.env):
GOOGLE_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your_google_client_secret
JWT_SECRET=your_super_secret_jwt_key_make_it_long_and_random
PORT=3000
FRONTEND_URL=http://localhost:5173
STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key
STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_publishable_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_from_cli
MONTHLY_PRICE_ID=price_your_monthly_price_idYou need 3 terminal windows:
Terminal 1 - Backend Server:
cd server
npm run devTerminal 2 - Stripe Webhook Listener:
stripe listen --forward-to localhost:3000/webhookCopy the webhook secret from this output to your server/.env file
Terminal 3 - Frontend Server:
npm run devAlternative: Start Frontend and Backend Together:
npm run dev:fullNote: You still need to run the Stripe CLI separately
- Sign in with Google
- You'll be redirected to subscription page
- Click "Subscribe Now"
- Use test card:
4242 4242 4242 4242 - Complete payment
- You'll be redirected to dashboard
- Success:
4242 4242 4242 4242 - Declined:
4000 0000 0000 0002 - Requires 3D Secure:
4000 0025 0000 3155
Use any future expiry date, any 3-digit CVC, and any ZIP code.
Test subscription events without going through checkout:
# Simulate successful subscription
stripe trigger checkout.session.completed
# Simulate failed payment
stripe trigger invoice.payment_failed
# Simulate subscription cancellation
stripe trigger customer.subscription.deleted
# Simulate subscription update
stripe trigger customer.subscription.updatedWatch the Stripe CLI output to see events in real-time:
stripe listen --forward-to localhost:3000/webhookYou should see events like:
2024-01-15 10:30:45 --> checkout.session.completed [evt_1ABC123]
2024-01-15 10:30:45 <-- [200] POST http://localhost:3000/webhook [evt_1ABC123]
- JWT Authentication with 7-day expiration
- HTTP-only cookies for token storage
- Webhook signature verification using Stripe CLI secrets
- Route protection with subscription validation
- Environment variable protection
- Secure database operations
- User visits app β Redirected to login
- Google OAuth β User authenticates with Google
- Subscription check β If no active subscription, redirect to payment
- Stripe Checkout β User completes payment
- Webhook processing β Subscription status updated via Stripe CLI
- Dashboard access β User can access premium features
Webhook not receiving events
- Ensure Stripe CLI is running:
stripe listen --forward-to localhost:3000/webhook - Check webhook secret in server/.env matches CLI output
- Restart server after updating webhook secret
Webhook signature verification failed
- The webhook secret changes each time you restart
stripe listen - Copy the new secret from CLI output to server/.env
- Restart your backend server
OAuth redirect mismatch
- Verify redirect URI in Google Cloud Console:
http://localhost:5173/auth/callback - Check FRONTEND_URL in server/.env
Payment not completing
- Verify STRIPE_WEBHOOK_SECRET matches CLI output
- Check webhook events are being received (watch CLI output)
- Monitor server logs for webhook errors
Database issues
- Restart server to release SQLite locks
- Check file permissions in server directory
- Always start Stripe CLI first before testing payments
- Update webhook secret in .env when restarting CLI
- Monitor CLI output to see webhook events
- Use test cards for all payment testing
- Check server logs for detailed error information
GET /auth/google- Start OAuth flowPOST /auth/google/callback- Handle OAuth callbackGET /auth/me- Get current userPOST /auth/logout- Logout user
GET /check-subscription-status- Check subscription statusPOST /create-checkout-session- Create Stripe checkoutPOST /webhook- Handle Stripe webhooks (secured with CLI secret)
GET /dashboard-data- Get dashboard data (requires active subscription)
- Switch Stripe to live mode
- Get live API keys from Stripe Dashboard
- Configure production webhook endpoint in Stripe Dashboard
- Use webhook secret from Dashboard (not CLI)
- Update OAuth redirect URIs for production domain
- Set production environment variables
- Enable HTTPS
- Configure production database
- Set up proper webhook endpoints
Instead of Stripe CLI, configure webhooks in Stripe Dashboard:
- Go to Developers β Webhooks
- Add endpoint:
https://yourdomain.com/webhook - Select the same events as listed in the development setup
- Use the webhook secret from the Dashboard
MIT License - see LICENSE file for details
- Install Node.js and npm
- Install Stripe CLI and authenticate
- Set up Google OAuth credentials
- Set up Stripe test account and get API keys
- Create Stripe subscription product
- Copy environment variables to .env files
- Start Stripe CLI webhook listener
- Copy webhook secret to server/.env
- Start backend server
- Start frontend server
- Test authentication and payment flow
Remember: The Stripe CLI webhook secret changes each time you restart the listener!
Create a 10-15 page childrenβs storybook using AI (powered by Cohere)!
- On the dashboard, enter a prompt and (optionally) upload an image.
- Click "Generate Storybook".
- The backend calls Cohere's Command model to generate a storybook (1-2 sentences per page, 10-15 pages, ~20-30 sentences total).
- The storybook (prompt, image, pages) is saved to your account.
- You can view all your previous storybooks on the dashboard, and read them in a paginated, book-like viewer.
- Go to the Dashboard (after subscribing and logging in)
- Enter a creative prompt (e.g., "A dragon who learns to dance")
- (Optional) Upload an image to inspire the story
- Click Generate Storybook
- Wait for the AI to generate your storybook (may take a few seconds)
- View your new storybook and all previous storybooks below
POST /api/storybooks(auth required)- Form fields:
prompt(string, required),image(file, optional) - Returns:
{ storybook: { id, prompt, image_url, pages, created_at } }
- Form fields:
GET /api/storybooks(auth required)- Returns:
{ storybooks: [ ... ] }
- Returns:
DELETE /api/storybooks/:id(auth required)- Deletes a single storybook
DELETE /api/storybooks(auth required)- Deletes all storybooks for the user
- Table:
storybooksid(serial, PK)user_id(int, FK)prompt(text)image_url(text, local file path)pages(jsonb, array of strings)created_at(timestamp)
- Uploaded images are stored in
backend/uploads/and served at/uploads/<filename> - No external image hosting required
- Cohere API key: Add
COHERE_API_KEY=your_actual_key_hereto your.envfile in the backend - Cohere free tier is sufficient for prototyping
COHERE_API_KEY=your_actual_key_here
- If storybook generation fails, check your Cohere API key and quota at https://dashboard.cohere.com/
- Images must be under 10MB
- If you see
[object Object]in story pages, check backend logs for errors - If stories are not paginated, the app will automatically split the story into pages (2 sentences per page)