Manage Transactions Daily
A lightweight, self-hosted bookkeeping tool for UK sole traders and the self-employed.
Features • Quick Start • Desktop App • Local Development • Self-Hosted Deployment • Documentation
MTDify is a Django-based bookkeeping application designed specifically for UK sole traders and self-employed individuals. It provides a simple, privacy-focused way to track income, expenses, and VAT—all while keeping your data under your complete control.
Key Principles:
- You own your data — Everything is stored locally in SQLite
- Privacy first — No cloud dependencies, no data sharing
- Simple and focused — Built for sole traders, not enterprise accounting
- UK tax year aware — Automatically handles April-to-April tax years and UK dates.
- Transaction Management — Track income and expenses with categorisation
- VAT Calculations — Automatic VAT rate application and tracking
- Quarterly Summaries — View your finances by UK tax quarters (Q1-Q4)
- Tax Year Reports — Year-to-date profit/loss statements
- CSV Exports — Export all your data when needed
- Receipt Storage — Attach receipt images to expenses
- Recurring Entries — Set up automatic monthly transactions
- Multi-Currency Display — Each user can choose their preferred symbol (£, €, or $) in Settings
- Native Desktop App — Run as a standalone Windows app in its own window — no browser required (see Desktop App)
- Daily Backups — Automatic database backups - backups appear at /app/data/db/backups/ inside the container
- Multi-user Ready — Support for multiple user accounts
MTDify uses Adminita, a clean and modern Django admin theme. Adminita provides a new look for the Django admin panel with improved typography, spacing, and visual hierarchy.
Choose your preferred deployment method:
| Method | Best For | Difficulty |
|---|---|---|
| Desktop App (Windows) | A standalone Windows app for non-technical users — no Python needed | Easy |
| Local Development | Testing, development, personal use on your machine | Easy |
| Self-Hosted (Docker) | Production server deployment | Medium |
| Self-Hosted (Manual) | VPS/dedicated server without Docker | Medium |
Run MTDify locally on your machine for development, testing, or personal use. This method runs the Django development server which is perfect for single-user scenarios.
- Python 3.11 or higher
- pip (Python package manager)
- Git
-
Clone the repository
git clone https://github.com/djangify/mtdify.git cd mtdify -
Create a virtual environment
python -m venv .venv # On Windows: .venv\Scripts\activate # On macOS/Linux: source .venv/bin/activate
-
Install dependencies
pip install -r requirements.txt
-
Create environment file
cp .env.example .env
Edit
.envand set your configuration (see Configuration below). -
Initialize the database
python manage.py migrate
-
Create a superuser account
python manage.py createsuperuser
Or create a default demo user:
python manage.py create_default_user
This creates a user with email
demo@example.comand passworddemo123. -
Collect static files
python manage.py collectstatic --noinput
-
Run the development server
python manage.py runserver
-
Access the application
Open your browser and navigate to:
- Application: http://127.0.0.1:8000
- Admin Panel: http://127.0.0.1:8000/admin
python manage.py runserver 0.0.0.0:8080To access MTDify from other devices (phone, tablet, other computers):
-
Add your local IP to
ALLOWED_HOSTSin.env:ALLOWED_HOSTS=localhost,127.0.0.1,192.168.1.100 -
Run the server binding to all interfaces:
python manage.py runserver 0.0.0.0:8000
-
Access from other devices at
http://192.168.1.100:8000(use your actual local IP).
MTDify can run as a true local-first desktop application — it opens in its own native window (no browser, no address bar) and can be packaged into a single standalone .exe that needs no Python installation on the end user's machine.
Under the hood this uses PyWebView for the window, waitress as the local server, and PyInstaller to bundle everything (Python, Django, your code) into one folder.
Double-click start_desktop.bat, or from a terminal:
python desktop.pyThis sets up the virtual environment, applies migrations, starts the local server, and opens MTDify in a desktop window. The first launch also creates the default login (see below).
Double-click build_exe.bat, or run it from a terminal:
build_exe.batThis installs dependencies and PyInstaller, collects static files, and runs PyInstaller using mtdify.spec. When it finishes you'll have:
dist/MTDify/MTDify.exe
To distribute: zip the entire dist/MTDify folder and share the zip. The .exe needs the _internal folder beside it, so don't send the .exe on its own. End users just unzip and double-click MTDify.exe — no Python, no setup. A simple, non-technical guide for them is in HOW-TO-OPEN-MTDIFY.md.
The desktop app creates a default account on first launch:
- Email:
demo@example.com - Password:
demo123
(Override these by setting DEFAULT_USER_EMAIL / DEFAULT_USER_PASSWORD in .env before building. You can change the password later in the app's Settings.)
| Run mode | Database & receipts location |
|---|---|
start_desktop.bat / python desktop.py (dev) |
data/ inside the project folder |
Packaged MTDify.exe |
%LOCALAPPDATA%\MTDify (persists across app updates) |
The packaged app keeps user data outside the program folder so it survives reinstalls and isn't lost when you replace the app with a new build.
- Windows 10 or 11. The build is Windows-only — it must be built on Windows, and the resulting
.exeruns only on Windows. A Mac build would need to be produced on a Mac. - PyWebView uses the WebView2 runtime, which ships with Windows 11 and most updated Windows 10 machines. On a rare PC without it, Windows offers it as a free one-time download.
- New apps trigger a "Windows protected your PC" SmartScreen warning. This is normal for unsigned indie software — click More info → Run anyway. This is covered in the end-user guide.
- The app icon is read from
static/images/mtdify.ico(referenced bymtdify.spec). Replace that file to change the icon. - If the build fails mentioning
magic/libmagic, runpip install python-magic-binand rebuild. To see detailed errors, setconsole=Trueinmtdify.spec.
Deploy MTDify on your own server for production use with multiple users or remote access.
The recommended way to deploy MTDify in production.
- Docker and Docker Compose installed
- A domain name (optional, for HTTPS)
-
Clone the repository
git clone https://github.com/djangify/mtdify.git cd mtdify -
Create environment file
cp .env.example .env
Edit
.envwith production settings:DEBUG=False SECRET_KEY=your-very-long-random-secret-key-here ALLOWED_HOSTS=your-domain.com,www.your-domain.com
Generate a secure secret key:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" -
Build and start the container
docker-compose up -d --build
-
Run initial setup
# Run migrations docker-compose exec web python manage.py migrate # Create superuser docker-compose exec web python manage.py createsuperuser # Collect static files docker-compose exec web python manage.py collectstatic --noinput
-
Access the application
- HTTP: http://your-server-ip:8000
- With reverse proxy: https://your-domain.com
# Start services
docker-compose up -d
# Stop services
docker-compose down
# View logs
docker-compose logs -f web
# Run Django management commands
docker-compose exec web python manage.py <command>
# Restart services
docker-compose restart
# Rebuild after code changes
docker-compose up -d --buildData is persisted in Docker volumes:
| Volume | Purpose |
|---|---|
mtdify_data |
SQLite database and media files |
mtdify_static |
Collected static files |
To backup your data:
# Backup database
docker-compose exec web cp /app/data/db/db.sqlite3 /app/data/db/backup-$(date +%Y%m%d).sqlite3
# Copy backup to host
docker cp mtdify_web_1:/app/data/db/backup-*.sqlite3 ./backups/Deploy without Docker on a VPS or dedicated server.
- Python 3.11+
- A web server (Nginx recommended)
- Supervisor or systemd for process management
-
Clone and configure
git clone https://github.com/djangify/mtdify.git cd mtdify python -m venv .venv source .venv/bin/activate pip install -r requirements.txt
-
Configure environment
cp .env.example .env # Edit .env with production settings -
Initialize application
python manage.py migrate python manage.py createsuperuser python manage.py collectstatic --noinput
-
Create systemd service
Create
/etc/systemd/system/mtdify.service:[Unit] Description=MTDify Gunicorn Daemon After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/path/to/mtdify Environment="PATH=/path/to/mtdify/.venv/bin" ExecStart=/path/to/mtdify/.venv/bin/gunicorn \ --workers 3 \ --bind unix:/path/to/mtdify/mtdify.sock \ mtdify.wsgi:application [Install] WantedBy=multi-user.target
Enable and start:
sudo systemctl enable mtdify sudo systemctl start mtdify -
Configure Nginx
Create
/etc/nginx/sites-available/mtdify:server { listen 80; server_name your-domain.com; location /static/ { alias /path/to/mtdify/staticfiles/; } location /media/ { alias /path/to/mtdify/data/media/; } location / { proxy_pass http://unix:/path/to/mtdify/mtdify.sock; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
Enable the site:
sudo ln -s /etc/nginx/sites-available/mtdify /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx
-
Set up HTTPS (recommended)
sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your-domain.com
Create a .env file in the project root with the following variables:
| Variable | Description | Default | Required |
|---|---|---|---|
DEBUG |
Enable debug mode | True |
No |
SECRET_KEY |
Django secret key | change-me-in-production |
Yes (production) |
ALLOWED_HOSTS |
Comma-separated list of allowed hosts | localhost,127.0.0.1 |
Yes (production) |
DEBUG=True
SECRET_KEY=dev-secret-key-not-for-production
ALLOWED_HOSTS=localhost,127.0.0.1DEBUG=False
SECRET_KEY=your-super-long-random-secret-key-minimum-50-characters
ALLOWED_HOSTS=mtdify.yourdomain.com,www.mtdify.yourdomain.comWhen DEBUG=False, the following security features are automatically enabled:
- HTTPS redirect (
SECURE_SSL_REDIRECT) - Secure session cookies (
SESSION_COOKIE_SECURE) - Secure CSRF cookies (
CSRF_COOKIE_SECURE) - CSRF trusted origins based on
ALLOWED_HOSTS
Important: Always use HTTPS in production and ensure your reverse proxy sets the X-Forwarded-Proto header.
mtdify/
├── accounts/ # User authentication and management
├── bookkeeping/ # Core transaction tracking
│ ├── models.py # Income, Expense, Category, RecurringEntry
│ ├── views/ # Transaction and report views
│ └── utils.py # Tax year utilities
├── business/ # Business profile management
├── mtdify/ # Django project settings
│ ├── settings.py # Application configuration
│ ├── urls.py # URL routing
│ └── views.py # Dashboard and home views
├── templates/ # HTML templates
├── static/ # CSS, JS, images (incl. app icon mtdify.ico)
├── data/ # SQLite database and media (gitignored)
│ ├── db/ # Database files
│ └── media/ # Uploaded receipts
├── desktop.py # Desktop app launcher (PyWebView + waitress)
├── mtdify.spec # PyInstaller build config for the .exe
├── start_desktop.bat # Run the app in its own window (dev)
├── build_exe.bat # Build the standalone Windows .exe
├── HOW-TO-OPEN-MTDIFY.md # Plain-language guide for end users
├── start.bat # Run via the browser (Django dev server)
├── requirements.txt # Python dependencies
├── manage.py # Django management script
├── Dockerfile # Docker image definition
└── docker-compose.yml # Docker Compose configuration
- Log in with your created account
- Create a Business — Navigate to Business → Add Business
- Set your tax year — The system defaults to the current UK tax year
- Start tracking — Add income and expenses from the dashboard
When you generate printable reports, MTDify displays your email address by default. To include your full name and business name on reports:
- Go to Admin Panel (
/admin) - Navigate to Users and select your account
- Add your First Name and Last Name
- Ensure you've created a Business with your business name
Reports will then display your name, email, and business name in the header — useful for professional record-keeping.
Income:
- Navigate to Bookkeeping → Add Income
- Enter date, description, amount, and category
- Optionally add client name and invoice number
Expenses:
- Navigate to Bookkeeping → Add Expense
- Enter date, description, amount, and category
- Set VAT rate (0%, 5%, or 20%)
- Upload receipt image (optional)
Access reports from the Dashboard:
- Quarterly Summary — View income, expenses, and profit by quarter
- Category Breakdown — See spending by category
- CSV Export — Download data for your accountant
MTDify follows the UK tax year (6 April – 5 April):
- Q1: April – June
- Q2: July – September
- Q3: October – December
- Q4: January – March
Switch between tax years using the dropdown in the navigation bar.
MTDify does not currently expose a public API. All interactions are through the web interface.
"CSRF verification failed"
- Ensure
ALLOWED_HOSTSincludes your domain - Check that your reverse proxy passes the
X-Forwarded-Protoheader
Static files not loading
- Run
python manage.py collectstatic --noinput - Check that WhiteNoise is properly configured (it is by default)
Database locked errors
- SQLite can have issues with concurrent writes
- For heavy multi-user scenarios, consider PostgreSQL
Permission denied on data directory
- Ensure the application user has write access to
data/directory - In Docker, check volume permissions
- Documentation:
- Issues: https://github.com/djangify/mtdify/issues
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
- Fork the repository
- Clone your fork
- Create a virtual environment and install dependencies
- Create a branch for your feature
- Make your changes
- Run tests (when available)
- Submit a pull request
This project is licensed under the MIT License. See the LICENSE file for details.
Built with:
- Django — The web framework
- django-allauth — Authentication
- WhiteNoise — Static file serving
- Gunicorn — WSGI server (server deployments)
- waitress — WSGI server (desktop app)
- PyWebView — Native desktop window
- PyInstaller — Packaging the standalone
.exe - Tailwind CSS — Styling
MTDify is provided "as is" without warranty of any kind. If you choose to self-host this software, you do so at your own risk. The developer accepts no responsibility for data loss, inaccuracies, or any issues arising from its use. Always maintain your own backups and verify calculations independently.
Made for UK self employed and sole traders
Introducing Manage Transactions Daily
Maintained by Diane Corriette
