Skip to content

System Architecture

MyPost is built as a modern, containerized microservices application designed for self-hosted deployment.

High-Level Overview

┌─────────────────────────────────────────────────────────────────┐
│                    External Traffic (HTTPS)                      │
└─────────────────────────────┬───────────────────────────────────┘
                    ┌─────────▼─────────┐
                    │     Traefik       │  ← TLS termination
                    │  (Reverse Proxy)  │
                    └─────────┬─────────┘
                    ┌─────────▼─────────┐
                    │   Gateway (Nginx) │  ← Request routing
                    │   /api/* → API    │
                    │   /*     → Web    │
                    └─────────┬─────────┘
        ┌─────────────────────┼─────────────────────┐
        │                     │                     │
  ┌─────▼─────┐       ┌───────▼───────┐     ┌──────▼──────┐
  │    Web    │       │     API       │     │   Worker    │
  │   (SPA)   │       │   (Hono)      │     │ (Background)│
  │  React +  │       │  TypeScript   │     │   Jobs      │
  │  Vite     │       │   REST API    │     │             │
  └───────────┘       └───────┬───────┘     └──────┬──────┘
                              │                    │
        ┌─────────────────────┼────────────────────┤
        │                     │                    │
  ┌─────▼─────┐       ┌───────▼───────┐    ┌──────▼──────┐
  │   MinIO   │       │  PostgreSQL   │    │    Redis    │
  │    (S3)   │       │   (Database)  │    │   (Queue)   │
  └───────────┘       └───────────────┘    └─────────────┘

Service Components

Gateway (Nginx)

Purpose: Routes requests to appropriate services

Route Service Description
/api/* API REST API endpoints
/health API Health check
/* Web React SPA

Configuration: nginx.conf (in project root)

Web (Frontend)

Technology: React + TypeScript + Vite + TailwindCSS

Features: - Mixpost-inspired dark theme UI - Responsive design (mobile-first) - Role-aware rendering - Real-time updates via WebSocket

Key Routes: | Route | Component | Description | |-------|-----------|-------------| | / | Dashboard | Overview and stats | | /compose | Composer | Create/edit posts | | /calendar | Calendar | Schedule view | | /media | Media Library | Asset management | | /analytics | Analytics | Reports and insights | | /settings | Settings | Configuration |

API (Backend)

Technology: Hono (TypeScript) + Drizzle ORM

Architecture:

src/
├── routes/          # API endpoints
│   ├── auth.ts      # Authentication
│   ├── posts.ts     # Post CRUD
│   ├── brands.ts    # Brand management
│   └── ...
├── middleware/      # Request processing
│   ├── auth.ts      # JWT validation
│   ├── permissions.ts # RBAC checks
│   └── audit.ts     # Activity logging
├── workers/         # Background jobs
│   ├── publish.ts   # Post publishing
│   └── token-refresh.ts # OAuth refresh
├── adapters/        # Social network APIs
│   ├── facebook.ts
│   ├── instagram.ts
│   ├── x.ts
│   └── linkedin.ts
└── db/
    └── schema/      # Drizzle schemas

Worker (Background Jobs)

Responsibilities: - Post publishing at scheduled times - OAuth token refresh (before expiry) - Analytics data collection - Media processing

Queue System: Redis-backed with BullMQ


Data Model

Entity Hierarchy

Tenant (System-level)
  └── Workspace (Organization)
        └── Brand (Social presence)
              ├── Social Accounts
              ├── Posts
              └── Media Assets

Core Tables

Table Purpose
users User accounts and authentication
workspaces Top-level organization units
brands Social media brands/identities
social_accounts Connected network accounts
posts Content to be published
post_targets Post → Account mappings
media_assets Uploaded images/videos
roles Permission templates
audit_events Activity logging

Key Relationships

-- User → Workspace (many-to-many via workspace_users)
workspace_users (user_id, workspace_id, role_id)

-- Workspace → Brand (one-to-many)
brands (workspace_id)

-- Brand → Social Account (one-to-many)
social_accounts (brand_id)

-- Post → Social Account (many-to-many via post_targets)
post_targets (post_id, social_account_id)

Security Architecture

Authentication Flow

1. User submits credentials
   └→ POST /api/v1/auth/login

2. Server validates credentials
   └→ Check password hash
   └→ Check account status

3. Issue tokens
   └→ Access token (JWT, 15min)
   └→ Refresh token (7 days, httpOnly cookie)

4. Client stores access token
   └→ Authorization: Bearer <token>

5. Token refresh (when expired)
   └→ POST /api/v1/auth/refresh

Permission System (RBAC)

30+ granular permissions:

Category Permissions
Posts posts.create, posts.edit, posts.delete, posts.publish
Brands brands.create, brands.edit, brands.delete
Accounts accounts.connect, accounts.disconnect
Team users.invite, users.manage, roles.manage
Analytics analytics.view, analytics.export
Admin workspace.settings, billing.manage

Token Encryption

OAuth tokens are encrypted at rest using AES-256-GCM:

// Encryption (before storage)
encrypt(accessToken)  base64(iv + ciphertext + authTag)

// Decryption (when needed)
decrypt(encryptedToken)  plainAccessToken

White-Label Architecture

Custom Domain Flow

1. Client configures DNS
   client.example.com → CNAME → mypost.your-server.com

2. Add domain in MyPost
   POST /api/v1/workspaces/:id/custom-domain

3. Domain verification
   └→ DNS TXT record check
   └→ SSL certificate provisioning

4. Request routing
   └→ Domain → workspace_id lookup
   └→ X-Workspace-ID header injection

Branding Customization

Element Customizable
Logo
Colors
Login page
Email templates
Footer text
Favicon

Network Adapters

Each social network has a dedicated adapter implementing a common interface:

interface NetworkAdapter {
  // Authentication
  getAuthUrl(): string;
  exchangeCode(code: string): Promise<TokenSet>;
  refreshToken(token: TokenSet): Promise<TokenSet>;

  // Publishing
  publish(post: Post, account: SocialAccount): Promise<PublishResult>;

  // Analytics
  getMetrics(accountId: string, range: DateRange): Promise<Metrics>;
}

Supported Networks

Network Features
Facebook Pages, Groups, Stories
Instagram Feed, Stories, Reels
X (Twitter) Tweets, Threads, Media
LinkedIn Posts, Articles, Pages
TikTok Videos
YouTube Videos, Community, Shorts

Caching Strategy

Redis Cache Layers

Key Pattern TTL Purpose
user:{id} 1h User profile data
workspace:{id} 1h Workspace config
domain:{domain} 1h Domain → workspace mapping
session:{token} 15m Active sessions
rate:{key} 1s-1m Rate limiting counters

Cache Invalidation

// On entity update
await cache.del(`workspace:${id}`);

// On domain change
await cache.del(`domain:${oldDomain}`);
await cache.set(`domain:${newDomain}`, workspaceId);

Scaling Considerations

Horizontal Scaling

Component Scalable Notes
Web Stateless, add replicas
API Stateless, add replicas
Worker Scale based on queue depth
PostgreSQL ⚠️ Use read replicas
Redis ⚠️ Cluster mode for HA
Load API Replicas Workers PostgreSQL
Small (<100 users) 1 1 1 primary
Medium (<1000 users) 2-3 2 1 primary + 1 replica
Large (1000+ users) 4+ 4+ Primary + replicas + PgBouncer

For More Details