# 🔥 OnlyFans-like Platform Blueprint (v0.1.0)
This document outlines the core features, frontend/backend routes, and data models required for building a subscription-based creator platform similar to OnlyFans.
## 📦 Core Modules & Features
### 1. User System
- **Authentication**: Support email/phone registration and login
- **User Roles**: `creator` and `subscriber`
- **Profile Management**: Edit nickname, avatar, and bio
### 2. Content System
- **Post Creation**: Support text, image, video, and audio content
- **Content Visibility**: `subscribers-only` or `pay-to-unlock`
- **Content Bundles**: Group multiple content items into paid packages
- **Content Access**: Subscribers can access creator content
- **Engagement**: Like, comment, and save content
### 3. Subscription & Revenue
- **Monthly Subscriptions**: Recurring payments for content access
- **One-Time Purchases**: Unlock premium posts without subscription
- **Tips**: Support tipping creators
- **Revenue Share**: Platform commission (e.g., 20%)
### 4. Messaging System
- **Direct Messages**: Private messaging between users
- **Paid Messages**: Creators can charge for message access
- **Broadcasts**: Creators can message all subscribers
### 5. Payment System
- **Multiple Currencies**: Support for fiat and cryptocurrencies
- **Payment Methods**: Credit cards and crypto wallets
- **Withdrawals**: Creator earnings withdrawal
### 6. Security & Permissions
- **Content Protection**: Anti-screenshot, watermark, anti-hotlinking
- **User Blocking**: Block users, countries, or IP addresses
### 7. Analytics
- **Earnings Dashboard**: Track income and subscriber trends
- **Content Metrics**: Views, likes, comments, and purchases
- **Subscriber Analytics**: Growth and retention metrics
### 8. Notifications
- **Real-time Updates**: Instant notification delivery
- **Multiple Types**: Subscription, tip, purchase, comment, like, message
- **Management**: Mark as read, delete, filter by type
---
## 🌐 Frontend Routes
### Authentication Pages
```txt
/login → User authentication with email/phone
/register → New user registration with role selection
```
### Discovery Pages
```txt
/explore/posts → Browse and discover posts
/explore/creators → Discover and explore creators
/[handle] → Creator's public profile
/[handle]/posts → Creator's posts listing
/[handle]/medias → Creator's media gallery
/[handle]/subscription → Subscription management
/media/[mediaId] → Individual media view
```
### Creator Pages
```txt
/studio → Creator dashboard
/studio/posts → Post management
/studio/packages → Package management
/studio/broadcasts → Broadcast messages
/studio/scheduled → Scheduled content
/studio/subscribers → Subscriber management
/studio/unlocked → Premium content
/studio/tips → Tips management
/studio/analytics → Analytics dashboard
```
### Subscriber Pages
```txt
/subscriptions → Subscription management
/purchased → Purchased content
/tips → Tips interface
```
### Messaging Pages
```txt
/messages → Messages inbox
/messages/[conversationId] → Chat interface
```
### Wallet Pages
```txt
/wallet → Wallet dashboard
```
### Settings Pages
```txt
/settings → Account settings
/settings/security → Security settings
```
### Notifications Pages
```txt
/notifications → Notifications center
```
---
## 🧩 Data Models
### Enums
```ts
// User Roles
enum UserRole {
CREATOR = 'creator',
SUBSCRIBER = 'subscriber'
}
// Media Types
enum MediaType {
TEXT = 'text',
IMAGE = 'image',
VIDEO = 'video',
AUDIO = 'audio'
}
// Content Visibility
enum Visibility {
SUBSCRIBERS = 'subscribers',
PAY_TO_UNLOCK = 'pay_to_unlock'
}
// Sort Orders
enum SortOrder {
TRENDING = 'trending',
LATEST = 'latest',
POPULAR = 'popular',
NEWEST = 'newest'
}
// Content Filters
enum ContentFilter {
ALL = 'all',
IMAGES = 'images',
VIDEOS = 'videos',
TEXT = 'text'
}
// Feed Types
enum FeedType {
ALL = 'all',
SUBSCRIPTIONS = 'subscriptions',
DISCOVER = 'discover'
}
// Media Status
enum MediaStatus {
PUBLISHED = 'published',
SCHEDULED = 'scheduled',
DRAFT = 'draft'
}
// Time Periods
enum TimePeriod {
DAY = 'day',
WEEK = 'week',
MONTH = 'month',
YEAR = 'year'
}
// Grouping Intervals
enum GroupingInterval {
DAY = 'day',
WEEK = 'week',
MONTH = 'month'
}
// Transaction Types
enum TransactionType {
ALL = 'all',
DEPOSIT = 'deposit',
WITHDRAWAL = 'withdrawal',
PURCHASE = 'purchase',
TIP = 'tip'
}
// Post Type
enum PostType {
TEXT = 'text',
MEDIA = 'media',
BUNDLE = 'bundle'
}
// Post Status
enum PostStatus {
DRAFT = 'draft',
PUBLISHED = 'published',
SCHEDULED = 'scheduled',
ARCHIVED = 'archived'
}
// Interaction Type
enum InteractionType {
LIKE = 'like',
VIEW = 'view',
PURCHASE = 'purchase',
COMMENT = 'comment'
}
// Subscription Status
enum SubscriptionStatus {
ACTIVE = 'active',
CANCELLED = 'cancelled',
EXPIRED = 'expired'
}
// Purchase Status
enum PurchaseStatus {
COMPLETED = 'completed',
PENDING = 'pending',
FAILED = 'failed',
REFUNDED = 'refunded'
}
// Message Status
enum MessageStatus {
SENT = 'sent',
DELIVERED = 'delivered',
READ = 'read',
PAID = 'paid'
}
// Broadcast Status
enum BroadcastStatus {
SENT = 'sent',
SCHEDULED = 'scheduled'
}
// Payment Method Type
enum PaymentType {
CREDIT_CARD = 'credit_card',
CRYPTO = 'crypto'
}
// Fiat Currency
enum FiatCurrency {
USD = 'USD',
CNY = 'CNY',
EUR = 'EUR',
GBP = 'GBP',
JPY = 'JPY'
}
// Crypto Currency
enum CryptoCurrency {
USDC = 'USDC',
USDT = 'USDT',
ETH = 'ETH'
}
// Payment Status
enum PaymentStatus {
PENDING = 'pending',
COMPLETED = 'completed',
FAILED = 'failed',
REFUNDED = 'refunded',
CANCELLED = 'cancelled'
}
// Notification Type
enum NotificationType {
SUBSCRIPTION = 'subscription',
TIP = 'tip',
PURCHASE = 'purchase',
COMMENT = 'comment',
LIKE = 'like',
MESSAGE = 'message',
SYSTEM = 'system'
}
```
### Entities
```ts
// Fiat Amount
interface FiatAmount {
currency: FiatCurrency // Currency type
amount: number // Amount in the specified currency
}
// Crypto Amount
interface CryptoAmount {
currency: CryptoCurrency // Crypto currency type
amount: string // Amount in the specified crypto (as string)
}
// Payment Amount
interface PaymentAmount {
fiat?: FiatAmount[] // Fiat currency amounts
crypto?: CryptoAmount[] // Crypto currency amounts
}
// Payment Details
interface PaymentDetails {
// For credit card
cardNumber?: string // Last 4 digits of card
cardType?: string // Card type (Visa, Mastercard, etc.)
expiryDate?: string // Card expiry date
// For crypto
walletAddress?: string // Crypto wallet address in CAIP10 format
currency?: CryptoCurrency // Crypto currency type
}
// Payment
interface Payment {
type: PaymentType // Type of payment (credit card or crypto)
amount: PaymentAmount // Payment amount in specified currency
details: PaymentDetails // Payment method specific details
}
// Technical details about the media
interface MediaMetadata {
duration?: number // Duration in seconds (for video/audio)
dimensions?: { // Dimensions for images/videos
width: number // Width in pixels
height: number // Height in pixels
}
fileSize: number // Size of the file in bytes
mimeType: string // MIME type of the file
}
// User's social media links
interface SocialLinks {
twitter?: string // Twitter profile URL
instagram?: string // Instagram profile URL
tiktok?: string // TikTok profile URL
youtube?: string // YouTube channel URL
}
```
### User
```ts
id: string // Unique identifier for the user
handle: string // Unique username/handle for the user
email: string // User's email address
phone?: string // User's phone number (optional)
passwordHash: string // Hashed password for authentication
role: UserRole // User's role (creator or subscriber)
username: string // Display name for the user
avatarUrl: string // URL to user's profile picture
bio: string // User's biography/description
coverImageUrl?: string // URL to user's cover image (optional)
isVerified: boolean // Whether the user is verified
socialLinks?: SocialLinks
blockedUserIds: string[] // List of user IDs that this user has blocked
blockedCountries: string[] // List of country codes that are blocked
subscriptionPrice?: PaymentAmount // Price for subscribing to this creator (if creator)
messagePrice?: PaymentAmount // Price for sending message to this creator (if creator)
subscriberIds: string[] // List of user IDs who subscribed to this creator
subscribedCreatorIds: string[] // List of creator IDs this user subscribed to
purchasedPostIds: string[] // List of media IDs this user purchased
createdAt: Date // When the user account was created
updatedAt: Date // When the user account was last updated
```
### Post
```ts
id: string // Unique identifier for the post
creatorId: string // ID of the creator who made the post
type: PostType // Type of post (text, media, or bundle)
content: string // Main content of the post
visibility: Visibility // Who can see this post
price?: PaymentAmount // Price for pay-to-unlock content
allowComments: boolean // Whether comments are allowed
isPinned: boolean // Whether the post is pinned
status: PostStatus // Current status of the post
mediaIds: string[] // List of media IDs in this post, ordered by Media.order
likedUserIds: string[] // List of user IDs who liked this post
viewedUserIds: string[] // List of user IDs who viewed this post
purchasedUserIds: string[] // List of user IDs who purchased this post
commentIds: string[] // List of comment IDs on this post
createdAt: Date // When the post was created
updatedAt: Date // When the post was last updated
```
### Comment
```ts
id: string // Unique identifier for the comment
mediaIds: string[] // ID of the media this comment is on
authorId: string // ID of the user who made the comment
content: string // Content of the comment
parentId?: string // ID of the parent comment (if reply)
parentPostId: string // ID of the post this comment belongs to
isEdited: boolean // Whether the comment has been edited
likedUserIds: string[] // List of user IDs who liked this comment
commentIds: string[]
createdAt: Date // When the comment was created
updatedAt: Date // When the comment was last updated
```
### Media
```ts
id: string // Unique identifier for the media
postId?: string // ID of the post this media belongs to
authorId: string // ID of the creator who made the package
type: MediaType // Type of media (text, image, video, audio)
urls: string[] // URLs to the media files
thumbnailUrl?: string // URL to the thumbnail image
title: string // Title of the media
content?: string // Description of the media
metadata: MediaMetadata
createdAt: Date // When the media was created
updatedAt: Date // When the media was last updated
```
### MediaPackage
```ts
id: string // Unique identifier for the package
postId?: string // ID of the associated post
creatorId: string // ID of the creator who made the package
title: string // Title of the package
description: string // Description of the package
mediaIds: string[] // List of media IDs in this package
coverImageUrl?: string // URL to the package cover image
isActive: boolean // Whether the package is available
createdAt: Date // When the package was created
updatedAt: Date // When the package was last updated
```
### Subscription
```ts
id: string // Unique identifier for the subscription
subscriberId: string // ID of the subscribing user
creatorId: string // ID of the creator being subscribed to
startDate: Date // When the subscription started
endDate: Date // When the subscription ends
isActive: boolean // Whether the subscription is active
autoRenew: boolean // Whether the subscription auto-renews
payment: Payment // Payment details for the subscription
transactionId: string // ID of the payment transaction
createdAt: Date // When the subscription was created
updatedAt: Date // When the subscription was last updated
```
### PaymentTransaction
```ts
id: string // Unique identifier for the payment transaction
type: TransactionType // Type of transaction (deposit, withdrawal, purchase, tip, subscription)
payerId: string // ID of the user making the payment
recipientId: string // ID of the recipient (creator/platform)
payment: Payment // Payment details including type, amount and method details
status: PaymentStatus // Current status of the payment
referenceId?: string // ID of the related entity (subscription, purchase, tip, etc.)
metadata?: Record<string, any> // Additional payment metadata
error?: string // Error message if payment failed
processedAt?: Date // When the payment was processed
createdAt: Date // When the payment was initiated
updatedAt: Date // When the payment was last updated
```
### Tip
```ts
id: string // Unique identifier for the tip
senderId: string // ID of the user sending the tip
creatorId: string // ID of the creator receiving the tip
payment: Payment // Payment details for the tip
message?: string // Optional message with the tip
status: PurchaseStatus // Current status of the tip
transactionId: string // ID of the payment transaction
isAnonymous: boolean // Whether the tip is anonymous
createdAt: Date // When the tip was sent
updatedAt: Date // When the tip was last updated
```
### Message
```ts
id: string // Unique identifier for the message
senderId: string // ID of the user sending the message
receiverId: string // ID of the user receiving the message
payment?: Payment // Payment details for the message
content: string // Content of the message
status: MessageStatus // Current status of the message
transactionId: string // ID of the payment transaction
mediaIds?: string[] // URLs to any attached media
isEdited: boolean // Whether the message has been edited
createdAt: Date // When the message was sent
updatedAt: Date // When the message was last updated
```
### Conversation
```ts
id: string // Unique identifier for the conversation
participantIds: string[] // IDs of users participating in the conversation
lastMessageId: string // ID of the most recent message
lastMessageAt: Date // Timestamp of the most recent message
createdAt: Date // When the conversation was created
updatedAt: Date // When the conversation was last updated
```
### Broadcast
```ts
id: string // Unique identifier for the broadcast
creatorId: string // ID of the creator sending the broadcast
content: string // Content of the broadcast
mediaUrls?: string[] // URLs to any attached media
status: BroadcastStatus // Current status of the broadcast
scheduledAt?: Date // When the broadcast is scheduled for
readUserIds: string[] // List of user IDs who read the broadcast
createdAt: Date // When the broadcast was created
updatedAt: Date // When the broadcast was last updated
```
### Wallet
```ts
userId: string // ID of the user who owns the wallet
balance: PaymentAmount // Current balance in the wallet
transactionIds: string[] // List of payment transaction IDs
createdAt: Date // When the wallet was created
updatedAt: Date // When the wallet was last updated
```
### Notification
```ts
id: string // Unique identifier for the notification
type: NotificationType // Type of notification
title: string // Title of the notification
message: string // Content of the notification
isRead: boolean // Whether the notification has been read
createdAt: Date // When the notification was created
updatedAt: Date // When the notification was last updated
```
---
## 🛠 Backend API Routes (RESTful)
### Authentication & Profile
```txt
POST /api/auth/register → Register a new user
Body: {
email: string
phone?: string
password: string
role: UserRole
username: string
}
Response: {
token: string
user: User
}
POST /api/auth/login → Login an existing user
Body: {
email?: string
phone?: string
password: string
}
Response: {
token: string
user: User
}
GET /api/user/:userId → Fetch user profile
Response: User
PUT /api/user/:userId → Update user profile
Body: {
username?: string
avatarUrl?: string
bio?: string
email?: string
phone?: string
}
Response: User
GET /api/user/me → Get current user's profile
Response: User
```
### Content Management
```txt
POST /api/posts → Create a new post
Body: {
content: string
visibility: Visibility
payment?: Payment
allowComments: boolean
mediaIds?: string[]
}
Response: Post
GET /api/posts/:postId → Get post details
Response: Post
PUT /api/posts/:postId → Update post
Body: {
content?: string
visibility?: Visibility
payment?: Payment
allowComments?: boolean
mediaIds?: string[]
}
Response: Post
DELETE /api/posts/:postId → Delete post
Response: 204 No Content
POST /api/media → Upload media
Body: FormData {
file: File
type: MediaType
postId?: string
}
Response: Media
```
### Comments
```txt
POST /api/comments → Create a new comment
Body: {
postId: string
content: string
mediaIds: string[]
parentId?: string
}
Response: Comment
GET /api/comments → Get comments for a post
Query: {
postId: string
page: number
limit: number
parentId?: string
}
Response: {
comments: Comment[]
total: number
page: number
limit: number
}
PUT /api/comments/:commentId → Update a comment
Body: {
content: string
}
Response: Comment
DELETE /api/comments/:commentId → Delete a comment
Response: 204 No Content
POST /api/comments/:commentId/like → Like a comment
Response: {
success: boolean
likes: number
}
DELETE /api/comments/:commentId/like → Unlike a comment
Response: {
success: boolean
likes: number
}
```
### Subscriptions & Payments
```txt
POST /api/payment → Create a payment
Body: {
type: TransactionType
creatorId: string
payment: Payment
}
Response: {
transaction: PaymentTransaction
}
POST /api/subscriptions → Create subscription
Body: {
creatorId: string
transactionId: string
}
Response: {
subscription: Subscription
transaction: PaymentTransaction
}
GET /api/subscriptions → Get user's subscriptions
Query: {
page: number
limit: number
}
Response: {
subscriptions: Subscription[]
total: number
page: number
limit: number
}
POST /api/purchases → Purchase content
Body: {
postId: string
transactionId: string
}
Response: {
purchase: Purchase
transaction: PaymentTransaction
}
POST /api/tips → Send tip to creator
Body: {
recipientId: string
transactionId: string
message?: string
}
Response: {
tip: Tip
transaction: PaymentTransaction
}
```
### Wallet & Transactions
```txt
GET /api/wallet → Get wallet details
Response: Wallet
POST /api/wallet/withdraw
Body: {
amount: PaymentAmount
}
Response: Wallet
GET /api/wallet/transactions → Get transaction history
Query: {
page: number
limit: number
type?: TransactionType
}
Response: {
transactions: Transaction[]
total: number
page: number
limit: number
}
```
### Notifications
```txt
GET /api/notifications → Get notifications
Query: {
page: number
limit: number
type?: NotificationType
isRead?: boolean
}
Response: {
notifications: Notification[]
total: number
page: number
limit: number
}
PUT /api/notifications/:id → Mark notification as read
Response: Notification
PUT /api/notifications/read-all → Mark all notifications as read
Response: {
success: boolean
count: number
}
DELETE /api/notifications/:id → Delete notification
Response: 204 No Content
```
### Messaging
```txt
POST /api/messages → Send a new message
Body: {
receiverId: string
content: string
mediaUrls?: string[]
transactionId?: string
}
Response: Message
GET /api/messages → Get conversations
Query: {
page: number
limit: number
}
Response: {
conversations: Conversation[]
total: number
page: number
limit: number
}
GET /api/messages/:conversationId → Get messages in a conversation
Query: {
page: number
limit: number
}
Response: {
messages: Message[]
total: number
page: number
limit: number
}
PUT /api/messages/:messageId → Update a message
Body: {
content: string
}
Response: Message
DELETE /api/messages/:messageId → Delete a message
Response: 204 No Content
POST /api/messages/:messageId/read → Mark message as read
Response: Message
POST /api/messages/:messageId/paid → Mark message as paid
Response: Message
POST /api/broadcasts → Send a broadcast message
Body: {
content: string
mediaUrls?: string[]
scheduledAt?: Date
}
Response: Broadcast
GET /api/broadcasts → Get broadcast messages
Query: {
page: number
limit: number
}
Response: {
broadcasts: Broadcast[]
total: number
page: number
limit: number
}
PUT /api/broadcasts/:broadcastId → Update a broadcast
Body: {
content?: string
mediaUrls?: string[]
scheduledAt?: Date
}
Response: Broadcast
DELETE /api/broadcasts/:broadcastId → Delete a broadcast
Response: 204 No Content
POST /api/broadcasts/:broadcastId/read → Mark broadcast as read
Response: Broadcast
```
### Error Responses
All endpoints may return the following error responses:
```txt
400 Bad Request
Response: {
error: string
details?: object
}
401 Unauthorized
Response: {
error: "Unauthorized"
}
403 Forbidden
Response: {
error: "Forbidden"
}
404 Not Found
Response: {
error: "Not Found"
}
500 Internal Server Error
Response: {
error: "Internal Server Error"
}
```
---
## ⚙️ Recommended Tech Stack
- **Frontend**: Next.js, Tailwind CSS, React Query, Zustand
- **Backend**: Node.js (NestJS or Express)
- **Database**: PostgreSQL
- **Storage**: S3-compatible private file storage
- **Auth**: JWT or OAuth (optional)
- **Payment (PoC)**: Virtual wallet / mock credits
- **Deployment**: Vercel + Supabase + Cloudflare