A distributed file metadata storage and content deduplication system with SHA256-based clone detection, epoch file tracking, and multiple storage backends.
- FastAPI - Modern async web framework
- MongoDB (PyMongo Async) - Native async MongoDB driver (PyMongo 4.10+)
- Argon2 - Modern password hashing algorithm
- JWT - JSON Web Tokens for authentication
- AWS SES - Email service for user registration confirmation
- boto3 - AWS SDK for Python (SES integration)
- uv - Fast Python package manager
- pytest - Comprehensive test suite with 125+ tests
Note: This project uses PyMongo's native async support (introduced in PyMongo 4.9+) which provides better performance than the deprecated Motor library through direct asyncio implementation.
- π File Metadata Tracking - Store file metadata with SHA256 hashes across your infrastructure
- π Content Deduplication - Upload files only once, deduplicated by SHA256
- π₯ Clone Detection - Track duplicate files across all users with epoch file identification
- πΎ Multiple Storage Backends - Local filesystem or AWS S3 for file content
- π Flexible Authentication - Username/password login with JWT tokens and Google OAuth
- π§ Email Confirmation - Secure email verification for new user registrations via AWS SES
- π Google Sign-In Integration - One-click authentication with Google accounts
- π Interactive Web UI - Tree-based file browser with clone visualization
- π Production Ready - Comprehensive tests, TOML configuration, graceful interrupt handling
π Full documentation: https://putplace.readthedocs.io/
- Installation Guide
- Quick Start Guide
- Client Usage Guide
- API Reference
- Deployment Guide
- Architecture Overview
- Python 3.10 - 3.14
- uv - Fast Python package installer
- MongoDB (locally installed via Homebrew)
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone repository
git clone https://github.com/jdrumgoole/putplace.git
cd putplace
# Complete setup (venv + dependencies)
invoke setup
# Configure the server (create admin user, check AWS, set storage backend)
source .venv/bin/activate
invoke configure
# Or directly: pp_configure
# Start MongoDB and server
invoke quickstartThe server will be available at http://localhost:8000
PutPlace includes a configuration wizard to set up your server after installation:
# Interactive configuration (recommended for first-time setup)
pp_configure
# Non-interactive configuration (for automation/CI/CD)
pp_configure --non-interactive \
--admin-username admin \
--admin-email admin@example.com \
--storage-backend local
# With S3 storage
pp_configure --non-interactive \
--admin-username admin \
--admin-email admin@example.com \
--storage-backend s3 \
--s3-bucket my-putplace-bucket \
--aws-region us-west-2
# Environment-specific configuration (auto-suffixes bucket name)
# User provides: --s3-bucket=putplace --envtype=prod
# System creates: putplace-prod bucket
pp_configure --non-interactive \
--envtype prod \
--admin-username admin \
--admin-email admin@example.com \
--storage-backend s3 \
--s3-bucket putplace \
--aws-region us-west-2
# Skip validation checks (useful for testing)
pp_configure --skip-checks
# Standalone AWS tests (new in v0.5.2)
pp_configure S3 # Test S3 access
pp_configure SES # Test SES access
pp_configure S3 --aws-region us-west-2 # Test in specific region
# Via invoke task
invoke configure --test-mode=S3
invoke configure --test-mode=SESFeatures:
- β Creates admin user with secure password generation
- β Tests MongoDB connection before configuration
- β Checks AWS S3 and SES access (optional)
- β Standalone S3/SES tests - Test AWS credentials independently
- β Configures storage backend (local or S3)
- β
Generates
ppserver.tomlconfiguration file - β Non-interactive mode for automation
- β Beautiful terminal UI with rich formatting (when available)
Interactive Mode:
- Step-by-step wizard with prompts
- Automatic password generation option
- AWS connectivity checks
- Storage backend selection based on availability
Non-Interactive Mode:
- Perfect for automation and CI/CD pipelines
- All configuration via command-line flags
- Optional validation checks can be skipped
- Secure password auto-generation
# Scan a directory and upload metadata
pp_client --path /var/log
# Dry run (no upload)
pp_client --path /var/log --dry-run
# With authentication
pp_client --path /var/log --username admin --password your-passwordCross-platform desktop application built with Electron and TypeScript:
# Run the packaged app (recommended - correct menu names)
invoke gui-electron
# Or run in development mode with DevTools
invoke gui-electron --dev
# Package the app into a distributable .app bundle
invoke gui-electron-package
# Test installation/uninstallation flow (manual)
invoke gui-electron-test-install
# Test installation/uninstallation flow (automated)
invoke gui-electron-test-install --automated
# Build only (compile TypeScript)
invoke gui-electron-build
# Run unpacked development version (menu shows "Electron")
invoke gui-electron --packaged=FalseThe Electron GUI provides:
- π₯οΈ Native cross-platform desktop application (Windows, macOS, Linux)
- π Native OS directory picker
- π Dual authentication: Username/password OR Google Sign-In
- π Google OAuth integration: One-click sign-in with Google accounts
- ποΈ Password visibility toggle
- βοΈ Settings panel with persistence (server URL, hostname, IP)
- π Exclude patterns manager with wildcards support
- π Real-time progress tracking with statistics
- π Color-coded log output (success, error, warning, info)
- πΎ Settings saved between sessions (localStorage)
- π Secure IPC communication
- π¨ Custom menu bar with proper branding
See the Client Guide and OAuth Setup Guide for more details.
putplace/
βββ src/putplace/ # Main application code
β βββ main.py # FastAPI application
β βββ models.py # Pydantic models
β βββ database.py # MongoDB operations
β βββ storage.py # Storage backends (local/S3)
β βββ auth.py # Authentication (JWT & API keys)
β βββ ppserver.py # Server manager
βββ tests/ # Test suite (125+ tests, parallel execution)
βββ docs/ # Documentation (Sphinx)
βββ tasks.py # Invoke task automation
βββ pyproject.toml # Project configuration
This project uses invoke for task automation:
# Setup
invoke setup # Complete project setup (venv + dependencies)
invoke configure # Configure server (interactive wizard)
invoke setup-venv # Create virtual environment only
invoke install # Install dependencies
# MongoDB
invoke mongo-start # Start local MongoDB
invoke mongo-stop # Stop local MongoDB
invoke mongo-status # Check MongoDB status
invoke mongo-logs # View MongoDB logs
# Running
invoke serve # Development server (auto-reload)
invoke serve-prod # Production server (4 workers)
invoke quickstart # Start MongoDB + dev server
# Testing
invoke test-all # Run all tests (parallel, 4 workers, ~40% faster)
invoke test-all --parallel=False # Run serially (most stable)
invoke test # Run tests with coverage
invoke test-one tests/test_api.py # Run specific test file
pytest -m "not integration" # Skip integration tests
pytest -m integration # Run only integration tests
# Code Quality
invoke lint # Run ruff linter
invoke lint --fix # Auto-fix linting issues
invoke format # Format code with black
invoke typecheck # Run mypy type checker
invoke check # Run all checks (format, lint, typecheck, test)
# GUI Client
invoke gui-electron-build # Build Electron desktop app
invoke gui-electron # Run Electron desktop app
invoke gui-electron --dev # Run Electron app with DevTools
# Other
invoke build # Build package
invoke clean # Clean build artifacts
invoke --list # List all tasksThe project includes 125+ comprehensive tests covering:
- Unit tests for models, API endpoints, database operations
- Integration tests with real server and MongoDB
- End-to-end tests including file upload and deduplication
- Console script installation tests
- Parallel test execution with isolated databases (4 workers, ~40% faster)
# Run all tests with coverage (parallel by default, ~40% faster)
invoke test-all
# Run tests serially (most stable)
invoke test-all --parallel=False
# Run with more workers
invoke test-all --workers=8
# Run specific test file
invoke test-one tests/test_models.py
# Run specific test function
invoke test-one tests/test_api.py::test_put_file_valid
# Skip integration tests (faster, no MongoDB required)
pytest -m "not integration"
# View coverage report
open htmlcov/index.htmlParallel Testing: Tests run in parallel by default using pytest-xdist with isolated databases per worker, preventing race conditions while providing significant speed improvements.
See tests/README.md for detailed testing documentation.
pp_server start # Start server
pp_server start --port 8080 # Custom port
pp_server status # Check status
pp_server stop # Stop server
pp_server restart # Restart server
pp_server logs # View logs
pp_server logs --follow # Follow logsFiles are stored in ~/.putplace/:
ppserver.pid- Process IDppserver.log- Server logs
PutPlace uses TOML configuration files. Copy the example and customize:
cp ppserver.toml.example ppserver.toml
nano ppserver.tomlThe server looks for ppserver.toml in:
./ppserver.toml(current directory)~/.config/putplace/ppserver.toml(user config)/etc/putplace/ppserver.toml(system config)
You can also use invoke configure or pp_configure for guided setup. Environment variables can override TOML settings if needed. See Configuration Guide for details.
Once the server is running:
- Home: http://localhost:8000
- API Docs: http://localhost:8000/docs (Swagger UI)
- Alternative Docs: http://localhost:8000/redoc (ReDoc)
- Health Check: http://localhost:8000/health
File Operations:
POST /put_file- Store file metadata (requires JWT or API key)GET /get_file/{sha256}- Retrieve file by SHA256 (requires JWT or API key)POST /upload_file/{sha256}- Upload file content (requires JWT or API key)GET /api/clones/{sha256}- Get all file clones (requires JWT)GET /api/my_files- Get user's files (requires JWT)
Authentication (regstack):
User accounts, registration, email verification, password reset, JWT sessions, and Google OAuth are all served by the embedded regstack library:
POST /api/v2/auth/registerβ Register a new user (triggers verification email)POST /api/v2/auth/verifyβ Confirm email by tokenPOST /api/v2/auth/loginβ Exchange credentials for a JWTPOST /api/v2/auth/forgot-password/POST /api/v2/auth/reset-passwordPOST /api/v2/auth/change-password/POST /api/v2/auth/change-emailGET /api/v2/auth/me/DELETE /api/v2/auth/accountGET /account/login,/account/register,/account/forgot, ... β themed HTML pages
API keys (putplace-owned):
POST /api_keysβ Create API key (requires JWT)GET /api_keysβ List API keys (requires JWT)
Email verification and password reset are handled by regstack out of the
box. Putplace ships branded email templates in
packages/putplace-server/src/putplace_server/regstack_email_templates/
that override regstack's defaults via regstack.add_template_dir().
Email sending is configured via REGSTACK_EMAIL__* environment variables
(or a regstack.toml):
REGSTACK_EMAIL__BACKEND=ses
REGSTACK_EMAIL__FROM_ADDRESS=noreply@example.com
REGSTACK_EMAIL__SES_REGION=eu-west-1Disabling registration: set REGSTACK_ALLOW_REGISTRATION=false
in the server's environment, then restart (or restart-on-config-change in
AWS App Runner). No redeployment needed.
The script will: Note: AWS SES must be out of sandbox mode to send to any email address.
Google Sign-In Setup:
regstack handles the full Google OAuth flow (authorization code + PKCE). Configure it via:
REGSTACK_OAUTH__GOOGLE_CLIENT_ID=<your-client-id>
REGSTACK_OAUTH__GOOGLE_CLIENT_SECRET=<your-client-secret>Then visit /account/login β the Google sign-in button appears
automatically when both env vars are set. See the
regstack docs
for the threat model and configuration details.
See API Reference for complete endpoint documentation.
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Client β β Client β β Client β
β (Server A) β β (Server B) β β (Server C) β
ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ
β JWT Bearer Auth β β
βββββββββββββ¬ββββββββββββ΄βββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β PutPlace API β
β (FastAPI) β
ββββββββββ¬βββββββββ
β
βββββββββ΄βββββββββ
β β
βΌ βΌ
ββββββββββββββ ββββββββββββββ
β MongoDB β β Storage β
β (Metadata) β β Backend β
ββββββββββββββ ββββββββββββββ
β
βββββββ΄ββββββ
β β
βΌ βΌ
ββββββββββββ ββββββββββββ
β Local β β AWS β
β FS β β S3 β
ββββββββββββ ββββββββββββ
See Architecture Guide for detailed design documentation.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linting (
invoke check) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See Development Guide for more details.
See LICENSE file for details.
- Documentation: https://putplace.readthedocs.io/
- Issues: https://github.com/jdrumgoole/putplace/issues
- Source: https://github.com/jdrumgoole/putplace
See CHANGELOG.md for version history and release notes.