Overview
Plant Together is built as a microservices architecture with six main components working together to provide real-time collaborative PlantUML diagram editing. The system uses Docker Compose to orchestrate these services, ensuring seamless communication and data persistence.Architecture Diagram
Components
1. React Frontend
Purpose: Single-page application providing the user interface for collaborative diagram editing. Technology Stack:- React 18 with TypeScript
- Vite for build tooling
- Monaco Editor (VSCode editor for the web)
- Yjs for CRDT-based collaboration
- plantuml-core for client-side diagram rendering
- Real-time collaborative editing using Yjs
- PlantUML syntax highlighting and autocomplete
- Live diagram preview with zoom and pan
- SVG diagram export
- Offline editing with sync on reconnection
- Cross-tab communication
- HTTP requests to Express backend for user authentication and room management
- WebSocket connection to Y-Redis for real-time document synchronization
2. Express Backend
Purpose: REST API server handling authentication, authorization, and business logic. Technology Stack:- Node.js with Express framework
- TypeScript
- Firebase Admin SDK for authentication
- PostgreSQL client for database operations
- Redis client for session management
- User authentication and session management
- Room creation and access control
- Room signature verification for WebSocket connections
- User profile management
- API rate limiting and security
POST /api/auth/login- User authenticationPOST /api/rooms- Create new roomGET /api/rooms/:id- Get room detailsPOST /api/rooms/:id/join- Generate room access token
3. Y-Redis WebSocket Server
Purpose: Scalable WebSocket server for real-time collaborative editing using Yjs and Redis. Technology Stack:- @y/redis - Redis-backed Yjs WebSocket provider
- uWebSockets.js for high-performance WebSocket handling
- Redis for pub/sub and message distribution
- PostgreSQL for document persistence
- CRDT-based conflict resolution using Yjs
- Horizontal scalability through Redis pub/sub
- Persistent document storage in PostgreSQL
- Automatic document cleanup
- Cross-server synchronization
- Clients connect via WebSocket with a room-specific URL
- Y-Redis loads the document from PostgreSQL (if it exists)
- Updates are broadcast to all connected clients in real-time
- Changes are published to Redis for cross-server distribution
- Document state is periodically persisted to PostgreSQL
4. PostgreSQL Database
Purpose: Primary data store for persistent data including user information, room metadata, and document states. Technology Stack:- PostgreSQL 16.2
- Custom schema for user and room management
- User profiles and authentication metadata
- Room configurations and access permissions
- Yjs document states (binary CRDT data)
- Room activity logs and metadata
- Express connects for user/room data operations
- Y-Redis connects for document persistence
- PgAdmin connects for database management
5. Redis Cache
Purpose: In-memory data store for session management and Y-Redis pub/sub messaging. Technology Stack:- Redis 6.2
- Session Storage: User session tokens managed by Express
- Pub/Sub: Real-time message distribution between Y-Redis instances
- Rate Limiting: API request throttling
- Caching: Temporary data caching for performance
6. PgAdmin
Purpose: Web-based PostgreSQL administration interface. Technology Stack:- PgAdmin 4 (version 8.4)
- Visual database management
- Query editor and execution
- Schema visualization
- User and permission management
- Database backup and restore
- URL:
http://localhost:1007 - Default credentials:
ADMIN_EMAIL/ADMIN_PASSfrom environment variables
Data Flow
User Authentication Flow
Room Joining Flow
Signature Generation
Express validates permissions, generates signed room token using
ROOM_SIGNATURE_SECRET.Collaborative Editing Flow
Network Architecture
Development Networks
Development uses a single Docker network for all services:Production Networks
Production separates services into two networks for security: plant-together-network:- React frontend
- Express backend
- PostgreSQL database
- PgAdmin
- Y-Redis WebSocket server
- Redis cache
- (Also includes Express and React for cross-network communication)
- Network isolation for sensitive services
- Flexible scaling of Y-Redis independently
- Reduced attack surface
Scalability Considerations
Horizontal Scaling
Y-Redis Servers: Multiple Y-Redis instances can run simultaneously, sharing state through Redis pub/sub:Vertical Scaling
Adjust container resources indocker-compose.yaml:
Database Scaling
- Read Replicas: PostgreSQL can use read replicas for query distribution
- Connection Pooling: Use PgBouncer for efficient connection management
- Partitioning: Partition large tables by room or date
Security Architecture
Authentication & Authorization
- Firebase Authentication: Industry-standard OAuth 2.0 authentication
- JWT Tokens: Stateless authentication for API requests
- Session Management: Redis-backed sessions with configurable expiration
- Room Signatures: HMAC-signed tokens prevent unauthorized WebSocket access
Network Security
- Internal Networks: Services communicate over private Docker networks
- Port Exposure: Only necessary ports exposed to host machine
- TLS/SSL: Production deployments should use HTTPS/WSS with certificates
Data Security
- Environment Variables: Sensitive credentials stored outside code
- Password Hashing: PostgreSQL passwords should be strong and hashed
- Secrets Management: Use Docker secrets or external secret managers in production
Monitoring & Observability
Logging
Each service produces structured logs:Health Checks
Implement health check endpoints:- Express:
GET /health - PostgreSQL:
pg_isready - Redis:
redis-cli ping
Analytics (Production)
- PostHog: Product analytics and feature flags
- Microsoft Clarity: Session recording and heatmaps
Backup & Recovery
Database Backups
Volume Backups
Performance Optimization
Client-Side Rendering
- PlantUML Rendering: Runs in browser using WebAssembly (plantuml-core)
- Reduces Server Load: No server-side diagram rendering needed
- Faster Response: Diagrams update instantly without network roundtrip
WebSocket Efficiency
- Binary Protocol: Yjs uses efficient binary encoding
- Delta Synchronization: Only changes are transmitted, not full documents
- Compression: WebSocket messages can be compressed
Database Optimization
- Indexes: Create indexes on frequently queried columns
- Connection Pooling: Reuse database connections
- Query Optimization: Use EXPLAIN ANALYZE for slow queries
Caching Strategy
- Redis Caching: Frequently accessed data cached in Redis
- Client-Side Caching: Browser caches static assets
- CDN: Serve static assets through CDN in production
Development vs Production
| Aspect | Development | Production |
|---|---|---|
| Hot Reload | Enabled (volume mounts) | Disabled (built images) |
| Logging | Verbose | Filtered by level |
| Networks | Single network | Multiple isolated networks |
| Restart Policy | None | restart: always |
| Analytics | Disabled | Enabled (optional) |
| Port Exposure | All ports exposed | Only necessary ports |
| Resource Limits | None | Configured limits |
| TLS/SSL | Optional | Required |
Next Steps
- Set up Docker Compose deployment
- Configure environment variables
- Implement monitoring and alerting
- Set up automated backups
- Configure CI/CD pipeline for deployments