Skip to main content

Prerequisites

Python 3.8+

Mirage is built with Flask and requires Python 3.8 or higher

SQLite

Lightweight database that comes bundled with Python
No additional database setup required! Mirage uses SQLite which is initialized automatically on first run.

Local Development Setup

1

Clone the repository

Get the source code from GitHub:
git clone https://github.com/your-org/mirage.git
cd mirage
2

Install dependencies

Install required Python packages using pip:
pip install -r requirements.txt
Key dependencies:
  • Flask - Web framework
  • Flask-CORS - Cross-origin resource sharing
  • Werkzeug - Password hashing utilities
Consider using a virtual environment to keep dependencies isolated:
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -r requirements.txt
3

Configure the application

Review and customize settings in app/config.py:
app/config.py
# Database
DB_FILE = "db.sqlite"

# Message Configuration
MAX_MESSAGES = 100  # Max messages stored per room
MESSAGE_LIFESPAN = 60 * 30  # 30 minutes in seconds
MESSAGES_FILE = "messages.txt"

# File Upload
UPLOAD_URL = 'https://cpp-webserver.onrender.com/upload'

# Allowed HTML for Markdown
ALLOWED_TAGS = [
    'a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 
    'i', 'li', 'ol', 'strong', 'ul', 'p', 'br', 'img',
    'h1', 'h2', 'h3', 'h4', 'pre'
]
Update UPLOAD_URL to point to your own file upload service in production.
4

Initialize the database

The database initializes automatically on first run. Review the schema in app/db.py:
app/db.py
def init_db():
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    
    # Users table
    c.execute('''
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE NOT NULL,
        email TEXT UNIQUE NOT NULL,
        avatar_url TEXT,
        description TEXT,
        password TEXT NOT NULL,
        token TEXT,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    )
    ''')
    
    # More tables: rooms, posts, following, etc.
    # ...
Database Tables:
  • users - User accounts and authentication
  • rooms - Chat room definitions
  • room_members - Room membership tracking
  • posts - User posts and content
  • post_votes - Upvote/downvote tracking
  • replies - Post replies
  • following - User follow relationships
  • user_profile - User statistics
  • inbox_messages - Direct messages
5

Start the development server

Run the Flask application:
python server.py
The server starts on http://0.0.0.0:5000 in debug mode.
server.py
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
Debug mode enables auto-reload on code changes and detailed error pages.
6

Verify installation

Test the server is running:
curl http://localhost:5000/api/ping
Expected response:
{
  "message": "pong"
}
Check total user count:
curl http://localhost:5000/api/usercount
Returns: 0 (plain text)

Production Deployment

Never run Flask’s development server in production! Use a production WSGI server instead.
1

Install Gunicorn

pip install gunicorn
2

Create a WSGI entry point

Create wsgi.py in the project root:
wsgi.py
from app import create_app

app = create_app()

if __name__ == "__main__":
    app.run()
3

Run with Gunicorn

gunicorn --bind 0.0.0.0:5000 --workers 4 wsgi:app
Gunicorn options:
  • --workers 4 - Run 4 worker processes
  • --timeout 120 - Request timeout (useful for file uploads)
  • --access-logfile - - Log to stdout

Option 2: Docker

1

Create a Dockerfile

Dockerfile
FROM python:3.11-slim

WORKDIR /app

# Copy requirements and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 5000

# Run with gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "wsgi:app"]
2

Build and run

# Build image
docker build -t mirage:latest .

# Run container
docker run -d -p 5000:5000 \
  -v $(pwd)/db.sqlite:/app/db.sqlite \
  -v $(pwd)/messages.txt:/app/messages.txt \
  --name mirage-app \
  mirage:latest
Mount volumes for db.sqlite and messages.txt to persist data across container restarts.

Option 3: Platform-as-a-Service

  1. Create a new Web Service on Render
  2. Connect your GitHub repository
  3. Configure build settings:
    • Build Command: pip install -r requirements.txt
    • Start Command: gunicorn --bind 0.0.0.0:$PORT wsgi:app
  4. Add environment variables if needed
  5. Deploy!
Render’s free tier includes auto-sleep after inactivity. Consider paid tiers for production use.

Environment Variables

For production deployments, use environment variables for sensitive configuration:
.env
# Flask Configuration
FLASK_ENV=production
SECRET_KEY=your-secret-key-here

# Database
DATABASE_URL=sqlite:///db.sqlite

# File Upload Service
UPLOAD_URL=https://your-upload-service.com/upload

# CORS Settings
CORS_ORIGINS=https://your-frontend.com
Load environment variables in app/config.py:
import os
from dotenv import load_dotenv

load_dotenv()

DB_FILE = os.getenv('DATABASE_URL', 'db.sqlite')
UPLOAD_URL = os.getenv('UPLOAD_URL', 'https://cpp-webserver.onrender.com/upload')

Security Considerations

In server.py, set debug=False for production:
app.run(host='0.0.0.0', port=5000, debug=False)
Or use environment variables:
import os
app.run(debug=os.getenv('FLASK_ENV') == 'development')
Always use HTTPS in production. Configure your reverse proxy (nginx/Apache) or use a platform that provides SSL automatically (Render, Heroku, Railway).
In production, restrict CORS to specific origins in app/__init__.py:
CORS(app, 
     resources={r"/*": {
         "origins": ["https://your-frontend.com"],
         "methods": ["GET", "POST", "PUT", "DELETE"]
     }}
)
Regularly backup your db.sqlite file:
# Create timestamped backup
cp db.sqlite "db.sqlite.backup.$(date +%Y%m%d_%H%M%S)"

Monitoring & Maintenance

Database Maintenance

Room messages auto-cleanup is handled in the code, but you may want to archive old posts:
# Example cleanup script
import sqlite3
from datetime import datetime, timedelta

conn = sqlite3.connect('db.sqlite')
c = conn.cursor()

# Archive posts older than 1 year
one_year_ago = datetime.now() - timedelta(days=365)
c.execute('DELETE FROM posts WHERE created_at < ?', (one_year_ago,))

conn.commit()
conn.close()

Health Checks

Monitor your deployment with the ping endpoint:
curl https://your-mirage-app.com/api/ping
Set up automated monitoring with services like:
  • UptimeRobot
  • Pingdom
  • StatusCake

Logs

Access application logs:
# Gunicorn logs
gunicorn --access-logfile access.log --error-logfile error.log wsgi:app

# Docker logs
docker logs mirage-app

# Platform logs
heroku logs --tail
railway logs

Troubleshooting

SQLite can have concurrency issues under high load. Consider:
  • Using a connection pool
  • Migrating to PostgreSQL for production
  • Increasing timeout in database connections
Verify:
  • UPLOAD_URL is configured correctly in app/config.py
  • Your upload service is accessible
  • File size is under 24MB limit
  • Request timeout is sufficient (increase with --timeout in Gunicorn)
Check CORS configuration in app/__init__.py:
  • Ensure your frontend origin is allowed
  • Verify Authorization header is in allow_headers
  • Check browser console for specific CORS errors

Next Steps

API Reference

Explore all available endpoints and integrate with your frontend

Quickstart

Learn how to use Mirage from a user perspective

Contributing

Contribute to the Mirage project on GitHub

GitHub

View source code and star the repository

Quick Reference

Development Commands

# Install dependencies
pip install -r requirements.txt

# Run development server
python server.py

# Run with Gunicorn (production)
gunicorn --bind 0.0.0.0:5000 --workers 4 wsgi:app

# Database backup
cp db.sqlite db.sqlite.backup.$(date +%Y%m%d)

File Structure

mirage/
├── app/
│   ├── __init__.py          # App factory and blueprint registration
│   ├── config.py            # Configuration settings
│   ├── db.py                # Database initialization
│   ├── routes/
│   │   ├── auth.py          # Authentication endpoints
│   │   ├── chat.py          # Room chat endpoints
│   │   ├── posts.py         # Post and voting endpoints
│   │   ├── users.py         # User profile endpoints
│   │   ├── feed.py          # For You Page endpoint
│   │   ├── inbox.py         # Direct messaging
│   │   └── upload.py        # File upload handling
│   ├── utils.py             # Utility functions
│   └── store.py             # In-memory message storage
├── server.py                # Main application entry point
├── requirements.txt         # Python dependencies
├── db.sqlite               # SQLite database (auto-created)
└── messages.txt            # Message persistence (auto-created)

Build docs developers (and LLMs) love