Skip to content

brdweb/billmanager

Repository files navigation

BillManager - Financial Tracker

A secure multi-user web application for tracking recurring expenses and income with complete data separation. Built with React + Mantine frontend and Flask + PostgreSQL backend.

BillManager Screenshot


🎉 What's New in v4.0.1

Social Login & Two-Factor Authentication - Sign in with Google, Apple, Microsoft, or your own OIDC provider. Protect your account with email OTP or passkey-based two-factor authentication.

Highlights

  • Social Login (OIDC) - Connect Google, Apple, Microsoft, or custom OIDC providers for one-click sign-in
  • Two-Factor Authentication - Email OTP and passkey (WebAuthn) support for account security
  • Recovery Codes - Backup access codes in case you lose your 2FA device
  • Linked Accounts - Manage connected OAuth providers from your Security Settings
  • Security Hardened - ID token signature verification, state replay protection, cryptographic OTP generation

Features

  • Income & Expense Tracking: Track both recurring bills and deposits to forecast cash flow
  • Account Management: Organize transactions by account with intelligent filtering
  • Payment Analytics: Visual charts and comprehensive payment history across all transactions
  • Multi-Tenant Architecture: Row-level data isolation with granular user permissions
  • Enhanced Frequencies: Weekly, bi-weekly, monthly (including 1st & 15th), quarterly, yearly, and custom schedules
  • Auto-Payments: Automatic payment processing for recurring transactions
  • Modern UI: Responsive design with dark/light mode, 70+ custom icons, and visual calendar
  • Mobile App: Native iOS and Android apps with offline support and push notifications
  • Email Invitations: Invite users via email with configurable roles and access control
  • Bill Groups: Organize finances into separate groups (personal, business, family, etc.)
  • Bill Sharing: Share bills with other users and split costs by percentage, fixed amount, or equally

License

This project is licensed under the O'Saasy License - a modified MIT license that permits broad use while restricting SaaS commercialization by third parties.

Learn more at osaasy.dev

Quick Start

Prerequisites

  • Docker and Docker Compose installed
  • Web browser

Run the Application

  1. Create a docker-compose.yml file with the following content:

    services:
      bills-app:
        image: ghcr.io/brdweb/billmanager:latest
        container_name: billmanager
        ports:
          - "5000:5000"
        restart: unless-stopped
        environment:
          - DATABASE_URL=postgresql://billsuser:billspass@db:5432/billsdb
          - FLASK_SECRET_KEY=change-this-to-a-secure-random-string
        depends_on:
          - db
    
      db:
        image: postgres:16-alpine
        container_name: bills-db
        restart: unless-stopped
        environment:
          - POSTGRES_USER=billsuser
          - POSTGRES_PASSWORD=billspass
          - POSTGRES_DB=billsdb
        volumes:
          - postgres_data:/var/lib/postgresql/data
    
    volumes:
      postgres_data:
  2. Run the application:

    docker compose up -d
  3. Open your browser and visit: http://localhost:5000

Using Your Own PostgreSQL Database

If you already have a PostgreSQL server or prefer to use a managed database service (AWS RDS, DigitalOcean, Supabase, etc.), you can run just the application container:

  1. Create your database on your PostgreSQL server:

    CREATE DATABASE billsdb;
    CREATE USER billsuser WITH ENCRYPTED PASSWORD 'your-secure-password';
    GRANT ALL PRIVILEGES ON DATABASE billsdb TO billsuser;
  2. Create a simplified docker-compose.yml:

    services:
      bills-app:
        image: ghcr.io/brdweb/billmanager:latest
        container_name: billmanager
        ports:
          - "5000:5000"
        restart: unless-stopped
        environment:
          - DATABASE_URL=postgresql://billsuser:your-secure-password@your-db-host:5432/billsdb
          - FLASK_SECRET_KEY=change-this-to-a-secure-random-string
  3. Or run with Docker directly:

    docker run -d \
      --name billmanager \
      -p 5000:5000 \
      -e DATABASE_URL=postgresql://billsuser:your-secure-password@your-db-host:5432/billsdb \
      -e FLASK_SECRET_KEY=change-this-to-a-secure-random-string \
      ghcr.io/brdweb/billmanager:latest

Database URL Format:

postgresql://USERNAME:PASSWORD@HOST:PORT/DATABASE
Component Example Description
USERNAME billsuser PostgreSQL username
PASSWORD secretpass PostgreSQL password (URL-encode special characters)
HOST db.example.com Database server hostname or IP
PORT 5432 PostgreSQL port (default: 5432)
DATABASE billsdb Database name

Examples:

Environment Variables

Variable Description Default
DATABASE_URL PostgreSQL connection string postgresql://billsuser:billspass@db:5432/billsdb
FLASK_SECRET_KEY Secret key for session encryption Required in production
JWT_SECRET_KEY Secret key for mobile API tokens Falls back to FLASK_SECRET_KEY
RESEND_API_KEY Email provider API key (enables invitations) None
FROM_EMAIL Sender email address None
APP_URL Application URL for email links http://localhost:5000
ALLOWED_ORIGINS Comma-separated list of allowed CORS origins Uses APP_URL or localhost
DEPLOYMENT_MODE self-hosted or saas self-hosted
ENABLE_2FA Enable two-factor authentication flows false
ENABLE_PASSKEYS Enable passkey (WebAuthn) support false
WEBAUTHN_RP_ID WebAuthn relying party ID (domain only) Derived from APP_URL
WEBAUTHN_RP_NAME WebAuthn relying party display name BillManager
WEBAUTHN_ORIGIN WebAuthn origin (must match app origin) APP_URL
OAUTH_AUTO_REGISTER Auto-create users during social sign-in false
OAUTH_GOOGLE_ENABLED Enable Google sign-in false
OAUTH_GOOGLE_CLIENT_ID Google OAuth client ID None
OAUTH_GOOGLE_CLIENT_SECRET Google OAuth client secret None
OAUTH_APPLE_ENABLED Enable Apple sign-in false
OAUTH_APPLE_CLIENT_ID Apple Services ID (client ID) None
OAUTH_APPLE_TEAM_ID Apple Developer Team ID None
OAUTH_APPLE_KEY_ID Apple Sign in with Apple key ID None
OAUTH_APPLE_PRIVATE_KEY Apple private key (.p8, multiline or \n escaped) None
OAUTH_MICROSOFT_ENABLED Enable Microsoft sign-in false
OAUTH_MICROSOFT_CLIENT_ID Microsoft OAuth client ID (Azure AD app registration) None
OAUTH_MICROSOFT_CLIENT_SECRET Microsoft OAuth client secret None
OAUTH_MICROSOFT_TENANT_ID Azure AD tenant ID (common for multi-tenant, or specific tenant GUID) common
OAUTH_OIDC_ENABLED Enable generic OIDC sign-in (for Authentik, Authelia, Keycloak, etc.) false
OAUTH_OIDC_CLIENT_ID OIDC provider client ID None
OAUTH_OIDC_CLIENT_SECRET OIDC provider client secret None
OAUTH_OIDC_DISCOVERY_URL OIDC provider discovery URL (.well-known/openid-configuration) None
OAUTH_OIDC_DISPLAY_NAME Display name shown on login button SSO
OAUTH_OIDC_ICON Icon name for login button (Tabler icon without Icon prefix) lock
OAUTH_OIDC_SCOPES OAuth scopes to request openid email profile
OAUTH_OIDC_EMAIL_CLAIM Claim name for user's email address email
OAUTH_OIDC_USERNAME_CLAIM Claim name for username preferred_username
OAUTH_OIDC_NAME_CLAIM Claim name for display name name
OAUTH_OIDC_SKIP_EMAIL_VERIFICATION Skip email verification check (for providers that don't include email_verified) false

Security Note: In production, JWT_SECRET_KEY or FLASK_SECRET_KEY must be explicitly set. The application will refuse to start without it. Generate secure keys with: openssl rand -hex 32

CORS Configuration

BillManager uses a three-tier priority system for CORS origins:

  1. ALLOWED_ORIGINS - Explicit comma-separated list (e.g., https://app1.com,https://app2.com)
  2. APP_URL - Single origin for typical deployments
  3. Localhost defaults - For development without configuration

This ensures secure self-hosted deployments while remaining flexible for development.

2FA and Social Login Notes

  • For passkeys in production, set ENABLE_2FA=true, ENABLE_PASSKEYS=true, WEBAUTHN_RP_ID, and WEBAUTHN_ORIGIN.
  • For Apple sign-in, OAUTH_APPLE_PRIVATE_KEY may be provided as a single line with \n escapes.
  • OAuth callback URL for Google/Apple should be: https://<your-domain>/auth/callback.
  • For Microsoft sign-in, register an app in Azure AD and set redirect URI to: https://<your-domain>/auth/callback
  • For generic OIDC, set OAUTH_OIDC_DISCOVERY_URL to your provider's .well-known/openid-configuration URL
  • Self-hosted OIDC providers (Authentik, Authelia) may need OAUTH_OIDC_SKIP_EMAIL_VERIFICATION=true if they don't include email_verified in tokens
  • Custom claim mapping (OAUTH_OIDC_EMAIL_CLAIM, etc.) is available when your OIDC provider uses non-standard claim names

For complete configuration options, see the Self-Hosted Installation Guide.

First Login

On first startup, BillManager creates a default admin account with a randomly generated secure password. This password is printed to the container logs:

docker-compose logs billmanager | grep -A 5 "INITIAL ADMIN CREDENTIALS"

You will see:

============================================================
INITIAL ADMIN CREDENTIALS (save these now!)
   Username: admin
   Password: xK9mP2vL7nQr3wYz
   You will be required to change this password on first login.
============================================================

Save this password immediately! It is only shown once during initial startup.

For detailed setup and usage instructions, see the documentation.

Sharing Bills

BillManager allows you to share bills with other users and split costs in flexible ways:

Creating a Share

  1. Open any bill in your database
  2. Click the "Share" button
  3. Enter the recipient's username or email address
  4. Choose how to split the bill:
    • Percentage: Split by percentage (e.g., 50% each)
    • Fixed Amount: Assign a fixed dollar amount to the recipient
    • Equal: Split equally among all recipients
    • Full Amount: Share the full bill amount (no split)

Accepting Shares

Username-based shares (self-hosted):

  • Recipients receive a notification and can accept/decline in the "Shared Bills" section

Email-based shares (SaaS):

  • Recipients receive an email invitation with a secure link
  • Click the link and log in (or create an account) to accept the share

Managing Shared Bills

As the Bill Owner:

  • View all shares for your bills
  • Update split configurations
  • Revoke shares at any time
  • See recipient payment status

As a Share Recipient:

  • View bills shared with you in-line with your own bills
  • Mark your portion as paid to track your contributions
  • Leave a shared bill if you no longer need access

Payment Tracking

When a bill is shared:

  • Recipients can mark their portion as paid independently
  • Owners can see who has paid their share
  • Payment dates are tracked separately for each recipient

Security

  • Only bill owners can create, update, or revoke shares
  • Only the intended recipient can accept a share
  • Email shares require token-based verification
  • All share operations are logged for audit purposes

For more details, see the Sharing Bills Guide in the documentation.

Documentation

Complete documentation is available at docs.billmanager.app:

Application Management

Start Application

docker compose up -d

View Logs

docker compose logs -f bills-app

Stop Application

docker compose down

Update to New Version

docker compose pull
docker compose down
docker compose up -d

Backup PostgreSQL Data

# Create backup
docker exec bills-db pg_dump -U billsuser billsdb > backup.sql

# Restore backup
docker exec -i bills-db psql -U billsuser billsdb < backup.sql

Data Persistence

Docker Compose uses a named volume for PostgreSQL data:

  • postgres_data - All application data (users, databases, bills, payments)
  • Your data is automatically preserved between deployments!

Security Features

  • Secure Default Credentials: Random admin password generated on first run (self-hosted)
  • Forced Password Change: Admin credentials require immediate password update on first login
  • Production-Safe Configuration: Secret keys must be explicitly set in production
  • Input Validation: Comprehensive server-side validation for all user inputs
  • Rate Limiting: All API endpoints protected with tiered rate limits (60/min reads, 30/min writes)
  • Row-Level Isolation: Complete data separation between user groups
  • JWT Authentication: Secure token-based authentication for all clients
  • CORS Protection: Configurable allowed origins for API security
  • Password Requirements: Strong password enforcement (8+ chars, uppercase, lowercase, digit)
  • Email Verification: Optional email verification for new accounts
  • HTTPS Ready: Deploy behind a reverse proxy (Traefik, nginx, Caddy) for SSL
  • Content Security Policy: Strict CSP headers prevent XSS and injection attacks
  • Secure Token Storage: Mobile apps use platform-secure storage (Keychain/Keystore) with backup exclusion

Technical Details

Architecture

  • Frontend (Web): React 19 + TypeScript + Mantine 7 + Vite
  • Frontend (Mobile): React Native + Expo + TypeScript
  • Backend: Python 3.12+ + Flask + SQLAlchemy ORM
  • Database: PostgreSQL 16 with row-level tenancy
  • Authentication: JWT tokens (access + refresh)
  • WSGI Server: Gunicorn
  • Deployment: Docker Compose with persistent volumes

API

  • REST API (v2): JWT-based authentication at /api/v2/*
  • Documentation: Interactive Swagger UI at /api/v2/docs
  • Features: Delta sync, offline support, device registration, push notifications
  • Legacy API (v1): Session-based endpoints at /login, /bills, etc. (deprecated)

Key Technologies

  • Icons: Tabler Icons (70+ categories)
  • Email: Resend for transactional emails
  • Security: Flask-Limiter, Flask-Talisman, bcrypt password hashing
  • Validation: Server-side input validation with RFC-compliant patterns

Ready to organize your finances securely? Get started with BillManager!

Licensed under O'Saasy | Documentation | View on GitHub

About

A vibe-coded app to track your monthly bills and subscriptions

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors