mdds2 # SimpleMD - A FastAPI Markdown Document Management System

Created: 2024-11-12 03:59:51 | Last updated: 2024-11-12 03:59:51 | Status: Public

A lightweight, modern document management system built with FastAPI, SQLite, and MVP.css. Focused on simplicity and extensibility.

Features

  • 📝 Markdown document management (CRUD operations)
  • 🔍 Full-text search capabilities
  • 🏷️ Tag support for better organization
  • 📸 Image upload handling
  • 🔐 Basic authentication system
  • 💪 Async support throughout
  • 🎨 Clean, minimal UI with MVP.css

Prerequisites

  • Python 3.9+
  • pip

Installation

# Clone the repository
git clone https://github.com/yourusername/simplemd
cd simplemd

# Create a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

Project Structure

simplemd/
├── app/
│   ├── __init__.py
│   ├── main.py
│   ├── database.py
│   ├── config.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── document.py
│   │   ├── user.py
│   │   └── tag.py
│   ├── routes/
│   │   ├── __init__.py
│   │   ├── documents.py
│   │   ├── auth.py
│   │   └── images.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── login.html
│   │   ├── document_list.html
│   │   └── document_edit.html
│   └── static/
│       ├── uploads/
│       └── mvp.css
├── requirements.txt
├── README.md
└── .env.example

Dependencies

fastapi==0.104.0
uvicorn==0.24.0
aiosqlite==0.19.0
python-multipart==0.0.6
python-jose==3.3.0
passlib==1.7.4
Jinja2==3.1.2
aiofiles==23.2.1
python-dotenv==1.0.0

Database Schema

-- Users table
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Documents table
CREATE TABLE documents (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    user_id INTEGER NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users (id)
);

-- Tags table
CREATE TABLE tags (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT UNIQUE NOT NULL
);

-- Document tags relationship
CREATE TABLE document_tags (
    document_id INTEGER NOT NULL,
    tag_id INTEGER NOT NULL,
    PRIMARY KEY (document_id, tag_id),
    FOREIGN KEY (document_id) REFERENCES documents (id),
    FOREIGN KEY (tag_id) REFERENCES tags (id)
);

Key Implementation Details

Authentication

  • Simple JWT-based authentication
  • Passwords are hashed using bcrypt
  • Session management via HTTP-only cookies

Image Handling

async def save_image(file: UploadFile) -> str:
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    original_name = file.filename
    filename = f"{os.path.splitext(original_name)[0]}_{timestamp}{os.path.splitext(original_name)[1]}"

    upload_dir = Path("app/static/uploads")
    upload_dir.mkdir(exist_ok=True)

    file_path = upload_dir / filename

    async with aiofiles.open(file_path, 'wb') as out_file:
        content = await file.read()
        await out_file.write(content)

    return f"/static/uploads/{filename}"

Search Implementation

async def search_documents(query: str, user_id: int):
    async with aiosqlite.connect('database.sqlite') as db:
        db.row_factory = sqlite3.Row
        search_term = f"%{query}%"

        return await db.execute("""
            SELECT d.*, GROUP_CONCAT(t.name) as tags
            FROM documents d
            LEFT JOIN document_tags dt ON d.id = dt.document_id
            LEFT JOIN tags t ON dt.tag_id = t.id
            WHERE d.user_id = ? AND (d.title LIKE ? OR d.content LIKE ?)
            GROUP BY d.id
        """, (user_id, search_term, search_term))

Running the Application

  1. Copy .env.example to .env and configure:
SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///./simplemd.db
UPLOAD_DIR=app/static/uploads
  1. Initialize the database:
python -m app.database
  1. Start the server:
uvicorn app.main:app --reload
  1. Visit http://localhost:8000

API Endpoints

Authentication

  • POST /auth/login - Login user
  • POST /auth/logout - Logout user
  • POST /auth/register - Register new user

Documents

  • GET /documents - List all documents
  • GET /documents/{id} - Get specific document
  • POST /documents - Create new document
  • PUT /documents/{id} - Update document
  • DELETE /documents/{id} - Delete document
  • GET /documents/search - Search documents

Tags

  • GET /tags - List all tags
  • POST /documents/{id}/tags - Add tags to document
  • DELETE /documents/{id}/tags/{tag_id} - Remove tag from document

Images

  • POST /upload - Upload image
  • GET /images/{filename} - Get image

Security Considerations

  • All endpoints (except login/register) require authentication
  • SQL injection prevention through parameterized queries
  • XSS prevention via MVP.css sanitization
  • CSRF protection via secure tokens
  • Rate limiting on authentication endpoints

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

test.png