# 🔥 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