A self-hosted web application for creating, editing, and managing invoices. Converted from a static jQuery-based invoice template into a full Express + SQLite web app while preserving the original layout, print behavior, and user experience.
- Authentication: Secure login system with session management
- Create, edit, and manage invoices
- Search invoices by invoice number or customer
- Duplicate invoices with automatic date and invoice number updates
- Print-friendly layout (uses existing print.css)
- Persistent storage with SQLite
- Docker support for easy deployment
- Backend: Node.js + Express
- Database: SQLite (better-sqlite3)
- Views: EJS (server-rendered)
- Frontend: jQuery (preserves existing code style)
- Styling: Existing CSS (style.css, print.css)
- Deployment: Docker + docker-compose
- Build and start the application:
docker-compose up --build- Open your browser and navigate to:
http://localhost:3000
- Login with default credentials:
- Username:
admin - Password:
admin(or check console output on first run)
- Username:
The SQLite database will be persisted in the ./data directory.
- Install dependencies:
npm install- Start the application:
npm start- Open your browser and navigate to:
http://localhost:3000
- Login with default credentials:
- Username:
admin - Password:
admin(or check console output on first run)
- Username:
The SQLite database will be created in ./data/app.db.
The application uses session-based authentication. On first run, a default admin user is automatically created:
- Username:
admin - Password:
admin(or the value set inDEFAULT_PASSWORDenvironment variable)
You can set a custom default password using an environment variable:
DEFAULT_PASSWORD=your-secure-password npm startOr in Docker:
environment:
- DEFAULT_PASSWORD=your-secure-passwordNote: For production use, change the default password immediately after first login. You can do this by directly updating the database or by setting a custom DEFAULT_PASSWORD before first run.
- Sessions expire after 24 hours of inactivity
- Set
SESSION_SECRETenvironment variable in production for secure session cookies - For HTTPS deployments, set
secure: truein session configuration (app.js)
- Click "New Invoice" from the invoice list page
- Fill in the invoice details:
- Header (e.g., "INVOICE")
- Your company address
- Customer details
- Invoice number and date
- Line items (name, description, unit cost, quantity)
- Payment terms
- Click "Save Invoice" to persist the invoice
- Click "Edit" next to any invoice in the list
- Make your changes
- Click "Save Invoice" to update
- From the invoice list, click "Duplicate" next to an invoice, OR
- From the invoice editor, click "Duplicate"
- The new invoice will have:
- All fields and line items copied
- A new invoice number (original + "-COPY")
- Date set to today
- Amount paid reset to $0.00
Click the "Print" button in the invoice editor, or use your browser's print function (Cmd/Ctrl+P). The print layout is optimized using the existing print.css.
editableinvoice/
├── app.js # Express application entry point
├── package.json # Node.js dependencies
├── Dockerfile # Docker image definition
├── docker-compose.yml # Docker Compose configuration
├── db/
│ └── database.js # SQLite database initialization and migrations
├── routes/
│ ├── invoices.js # Invoice page routes (list, new, edit)
│ └── api.js # Invoice API routes (create, update, duplicate)
├── views/
│ ├── invoice-list.ejs # Invoice list page
│ └── invoice-editor.ejs # Invoice editor page
├── public/
│ ├── css/ # Stylesheets (style.css, print.css)
│ └── js/ # JavaScript (jQuery, example.js)
└── images/ # Logo images
GET /- Redirects to invoice listGET /invoices- List all invoices (supports ?search=query)GET /invoices/new- New invoice pageGET /invoices/:id- Edit invoice page
POST /api/invoices- Create new invoicePUT /api/invoices/:id- Update existing invoicePOST /api/invoices/:id/duplicate- Duplicate invoice
id(INTEGER PRIMARY KEY)header(TEXT)address(TEXT)logo_url(TEXT)customer_details(TEXT)invoice_number(TEXT)invoice_date(TEXT)payment_terms(TEXT)currency_prefix(TEXT, default: "$ ")amount_paid(TEXT)created_at(DATETIME)updated_at(DATETIME)
id(INTEGER PRIMARY KEY)invoice_id(INTEGER, FOREIGN KEY)name(TEXT)description(TEXT)unit_cost(TEXT)qty(TEXT)sort_order(INTEGER)
PORT- Server port (default: 3000)DB_PATH- SQLite database file path (default: ./data/app.db)DEFAULT_PASSWORD- Default password for admin user on first run (default: "admin")SESSION_SECRET- Secret key for session cookies (default: "invoice-app-secret-key-change-in-production")
- The application preserves the original invoice template's HTML structure and CSS selectors
- Currency formatting supports any prefix (detected automatically from input)
- Calculations are performed client-side; the backend stores structured data
- No authentication is required (single-user system)
- The database is automatically initialized on first run
ISC