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
- Copy
.env.example
to.env
and configure:
SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///./simplemd.db
UPLOAD_DIR=app/static/uploads
- Initialize the database:
python -m app.database
- Start the server:
uvicorn app.main:app --reload
- Visit http://localhost:8000
API Endpoints
Authentication
POST /auth/login
- Login userPOST /auth/logout
- Logout userPOST /auth/register
- Register new user
Documents
GET /documents
- List all documentsGET /documents/{id}
- Get specific documentPOST /documents
- Create new documentPUT /documents/{id}
- Update documentDELETE /documents/{id}
- Delete documentGET /documents/search
- Search documents
Tags
GET /tags
- List all tagsPOST /documents/{id}/tags
- Add tags to documentDELETE /documents/{id}/tags/{tag_id}
- Remove tag from document
Images
POST /upload
- Upload imageGET /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
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.