---
# System prepended metadata

title: "\U0001F525 OnlyFans-like Platform Blueprint"

---

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