You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
git clone https://github.com/your-username/weaver-ai.git
cd weaver-ai
2. Setup the Backend
cd server
npm install
# Create .env file and fill in all variables (see above)
npm run server # starts with nodemon
3. Setup the Frontend
cd client
npm install
# Create .env file: VITE_SERVER_URL=http://localhost:3000
npm run dev
4. Setup Stripe Webhooks (for local dev)
# Install Stripe CLI and login
stripe listen --forward-to localhost:3000/api/stripe
Copy the webhook signing secret from the CLI output into STRIPE_WEBHOOK_SECRET.
How It Works
Authentication Flow
User submits Login form
→ POST /api/user/login
→ bcrypt.compare(password, hash)
→ JWT signed with user._id
→ Token stored in localStorage
→ AppContext fetches user data
→ App renders protected routes
Text Generation Flow
User types prompt → selects "Text" mode → hits Send
→ POST /api/message/text { chatId, prompt }
→ auth middleware verifies JWT → req.user attached
→ check user.credits >= 1
→ openai.chat.completions.create({ model: "gemini-2.5-flash" })
→ reply saved to Chat.messages in MongoDB
→ user.credits -= 1
→ reply returned to frontend → rendered via react-markdown
Image Generation Flow
User types prompt → selects "Image" mode → hits Send
→ POST /api/message/image { chatId, prompt, isPublished }
→ auth middleware verifies JWT
→ check user.credits >= 2
→ Build ImageKit AI URL: ENDPOINT/ik-genimg-prompt-{encodedPrompt}/...
→ axios.get(url, { responseType: "arraybuffer" })
→ Convert buffer to base64
→ imagekit.upload(base64, filename, folder)
→ Permanent image URL saved to Chat.messages
→ user.credits -= 2
→ URL returned to frontend → <img> rendered
Payment Flow
User visits /credits → sees 3 plans
→ clicks "Buy Now"
→ POST /api/credit/purchase { planId }
→ Transaction created (isPaid: false)
→ stripe.checkout.sessions.create(...)
→ Frontend redirected to Stripe Checkout page
→ User pays on Stripe
→ Stripe sends "payment_intent.succeeded" to /api/stripe webhook
→ Webhook verifies signature using STRIPE_WEBHOOK_SECRET
→ Transaction.isPaid = true
→ User.credits += plan.credits
→ User redirected to /loading page → after 8s fetchUser() called → credits updated in UI
Deployment
Both client and server are deployed separately on Vercel.
Server (server/vercel.json)
Routes all traffic to server.js using the @vercel/node runtime.
Client (client/vercel.json)
All routes rewrite to /index.html to support React Router's client-side routing (SPA fallback).
Credit Plans
Plan
Price
Credits
Best For
Basic
$10
100
Casual users
Pro
$20
500
Regular users
Premium
$30
1000
Power users
Key Design Decisions
OpenAI SDK → Gemini: Used the OpenAI-compatible SDK with Google's baseURL endpoint. This means swapping AI providers in the future requires only changing the baseURL and model name.
Stripe Webhook over Redirect: Credits are only added after the webhook fires (not on redirect), preventing users from getting credits without actually paying.
Optimistic UI: The user's message appears in the chat instantly before the API responds, making the app feel fast.
express.raw() for Webhook: The Stripe webhook route uses raw body parsing (not JSON) so Stripe can verify the payload signature correctly.
MongoDB Aggregation: The community gallery uses $unwind + $match on the nested messages array to extract published images without loading entire chat documents.