Part 4 of the “Building Money-Making AI Apps” Series
Hey there! Rock back again. Today we’re getting our hands dirty with actual code. I’m gonna show you exactly how I built my AI writing assistant app that’s now making $3k/month. Whether you’re following our series or just want to learn app development, let’s build something cool together!
Planning Your App’s Features
Before we write any code, here’s how I plan my features:
- Core Feature: AI Text Generation
- User Management
- API Integration
- Payment Processing
- Usage Tracking
Let’s build these one by one!
Setting Up the Project
First, let’s create our project structure:
# Create project directory
mkdir ai-writer-app
cd ai-writer-app
# Initialize frontend
npx create-next-app@latest frontend
cd frontend
npm install @chakra-ui/react axios jsonwebtoken
# Initialize backend
mkdir backend
cd backend
npm init -y
npm install express mongoose openai dotenv jsonwebtoken
Building the Core Features
1. AI Text Generation Service
Here’s our AI service that actually makes money:
# backend/services/aiService.js
import OpenAI from 'openai';
class AIService {
constructor() {
this.client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
}
async generateContent(prompt, style, length) {
try {
const completion = await this.client.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: `You are a professional writer. Write in a ${style} style.`
},
{
role: "user",
content: prompt
}
],
max_tokens: length,
temperature: 0.7
});
return {
success: true,
content: completion.choices[0].message.content
};
} catch (error) {
console.error('AI Generation Error:', error);
return {
success: false,
error: 'Failed to generate content'
};
}
}
}
export default new AIService();
2. User Interface
Here’s our main content generation component:
// frontend/components/ContentGenerator.js
import React, { useState } from 'react';
import { Box, Button, Textarea, Select, useToast } from '@chakra-ui/react';
export default function ContentGenerator() {
const [prompt, setPrompt] = useState('');
const [style, setStyle] = useState('professional');
const [loading, setLoading] = useState(false);
const [result, setResult] = useState('');
const toast = useToast();
const generateContent = async () => {
try {
setLoading(true);
const response = await fetch('/api/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt, style }),
});
const data = await response.json();
if (data.success) {
setResult(data.content);
} else {
throw new Error(data.error);
}
} catch (error) {
toast({
title: 'Error',
description: error.message,
status: 'error',
duration: 3000,
});
} finally {
setLoading(false);
}
};
return (
<Box p={5}>
<Textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="What would you like me to write about?"
mb={4}
/>
<Select
value={style}
onChange={(e) => setStyle(e.target.value)}
mb={4}
>
<option value="professional">Professional</option>
<option value="casual">Casual</option>
<option value="creative">Creative</option>
</Select>
<Button
onClick={generateContent}
isLoading={loading}
colorScheme="blue"
mb={4}
>
Generate Content
</Button>
{result && (
<Box
p={4}
borderWidth={1}
borderRadius="md"
whiteSpace="pre-wrap"
>
{result}
</Box>
)}
</Box>
);
}
3. User Management
Here’s how we handle user accounts:
// backend/models/User.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
credits: {
type: Number,
default: 0
},
subscription: {
type: String,
enum: ['free', 'basic', 'pro'],
default: 'free'
},
usageHistory: [{
date: Date,
promptType: String,
credits: Number
}]
});
module.exports = mongoose.model('User', userSchema);
4. Payment Integration
Here’s our Stripe integration:
// backend/services/paymentService.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const createSubscription = async (userId, priceId) => {
try {
const user = await User.findById(userId);
const session = await stripe.checkout.sessions.create({
customer_email: user.email,
line_items: [{
price: priceId,
quantity: 1
}],
mode: 'subscription',
success_url: `${process.env.FRONTEND_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.FRONTEND_URL}/pricing`,
});
return session;
} catch (error) {
console.error('Subscription Error:', error);
throw error;
}
};
5. Usage Tracking
Here’s how we track API usage:
// backend/middleware/usageTracker.js
const trackUsage = async (req, res, next) => {
const startTime = Date.now();
res.on('finish', async () => {
try {
const duration = Date.now() - startTime;
await Usage.create({
userId: req.user.id,
endpoint: req.path,
duration,
status: res.statusCode,
timestamp: new Date()
});
} catch (error) {
console.error('Usage Tracking Error:', error);
}
});
next();
};
Testing Your App
Here’s my testing setup:
// tests/ai.test.js
describe('AI Content Generation', () => {
it('should generate content successfully', async () => {
const result = await aiService.generateContent(
'Write about AI',
'professional',
500
);
expect(result.success).toBe(true);
expect(result.content).toBeTruthy();
});
it('should handle errors gracefully', async () => {
const result = await aiService.generateContent(
'',
'professional',
500
);
expect(result.success).toBe(false);
});
});
Common Development Challenges
- Rate Limiting
const rateLimit = require('express-rate-limit');
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', apiLimiter);
- Error Handling
// backend/middleware/errorHandler.js
const errorHandler = (err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
success: false,
error: err.message || 'Something went wrong!'
});
};
app.use(errorHandler);
What’s Next?
In our next post, we’ll cover how to launch your app and get your first users. I’ll share the exact steps I took to launch my app and get paying customers within the first week!
Pro Tip: Start with a simple MVP and add features based on user feedback. My first version only had the AI text generation – everything else came from user requests!
This post is Part 4 of our “Building Money-Making AI Apps” series. Just joining us? Check out:
- [Part 1: The Complete Guide to Building Profitable AI Apps in 2025]
- [Part 2: Essential Tools and Resources for AI App Development]
- [Part 3: Technical Foundation: Setting Up Your AI App Environment]
- [Part 4: Step-by-Step AI App Development Guide]
- [Part 5: Launching Your AI App Successfully]
- [Part 6: Monetization Strategies for AI Apps]
- [Part 7: Scaling Your AI App Business]
- [Part 8: Maintaining and Updating Your AI App]