# Project pack: InvoiceShelf @ 98acbe2

Facts about **InvoiceShelf** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v2.md). This pack is pinned to one version and never changes after publication.

> InvoiceShelf is invoicing software for freelancers and small businesses that you run yourself. Create quotes and invoices, turn them into tidy PDFs and email them to customers. Record payments, see who still owes you, log expenses and set up repeat invoices for regular work. Customers get their own page to see their invoices, and your business records stay on your own server.

## Version and source
- Repository: https://github.com/InvoiceShelf/InvoiceShelf
- Pinned commit: `98acbe2622da3d5bc5738b16f5e7ca6688cdd95d`. Use exactly this version.
- Fresh checkout: use the setup below in an empty folder. If you already have this exact source checked out, keep your branch and use the development command instead; do not clone again or reset local changes.
- Or download a zip: https://github.com/InvoiceShelf/InvoiceShelf/archive/98acbe2622da3d5bc5738b16f5e7ca6688cdd95d.zip
- Official docs: https://docs.invoiceshelf.com
- Live demo: https://demo.invoiceshelf.com. Official public demo with sample data that resets automatically; it may run a newer version than the pinned 2.4.7. Don't enter real customer details.
- Licence: **AGPL-3.0-only**. Free to use and change. If you run a changed version that other people use over the internet (for example customers opening the portal), you must offer them your source code under the same licence, for example with a link to your copy. Using it for your own business has no extra obligations.

## Running the pinned source
- Fresh pinned-source setup (skip clone and checkout in an existing worktree):

  ```sh
  git clone https://github.com/InvoiceShelf/InvoiceShelf bespoke-invoiceshelf
  cd bespoke-invoiceshelf
  git checkout --detach 98acbe2622da3d5bc5738b16f5e7ca6688cdd95d
  # Prepare development requirements and local configuration first.
  # Setup notes: interactive Docker setup (MySQL/MariaDB, PostgreSQL or SQLite, optional Gotenberg); then pnpm install && pnpm dev, app at http://invoiceshelf.test. Native alternative: composer run dev
  ./devenv
  ```

The commands below are a starting point from the reviewed source. Prepare the listed tools, local configuration and companion services before starting the app. These instructions have not yet been validated in participant sessions.

### Separate trial of the current release
This tries an upstream release, which may differ from the pinned source above. It does not run your source changes. Use only sample data and a separate data directory or volume. Check the upstream documentation before running it.

  ```sh
  git clone https://github.com/InvoiceShelf/docker.git invoiceshelf
  cd invoiceshelf
  cp docker-compose.sqlite.yml docker-compose.yml
  # Optional: in docker-compose.yml change image: invoiceshelf/invoiceshelf:latest to :2.4.7 to stay on this exact release.
  docker compose up -d
  # Then open http://localhost:8090 and finish the setup wizard.
  ```

- Needs: Docker with Docker Compose, For development, Docker via ./devenv (or PHP 8.4 with Composer natively), plus Node 24 (.node-version) with pnpm
- Develop: `./devenv   # interactive Docker setup (MySQL/MariaDB, PostgreSQL or SQLite, optional Gotenberg); then pnpm install && pnpm dev, app at http://invoiceshelf.test. Native alternative: composer run dev`
- Test: `php artisan test --compact`
- Check/lint: `vendor/bin/pint --test && pnpm test   # pnpm test runs ESLint on resources/scripts`
- Build: `pnpm build`
- Stack: php, typescript, vue (Laravel 13, Vue 3, Pinia, Tailwind CSS 4, Vite, Pest). Difficulty for a non-developer with an AI: **moderate**. A conventional Laravel + Vue app with an AGENTS.md for AI coding tools. Company details, number formats, taxes, payment methods, custom fields and email wording are settings, and a built-in command scaffolds your own invoice and quote PDF layouts. Code changes need a Pest test and must work on SQLite, MySQL and PostgreSQL. The pinned 2.4.7 is the stable 2.x line, which upstream supports with security fixes until 1 September 2027.

## The project's own AI instructions
Read these in the repository before changing code: `AGENTS.md`, `.github/CONTRIBUTING.md`.

## Customisation points (settings → extend → code)
- **company-and-preferences** [settings]: Business name, logo, address, currency, language, date format and financial year. → `Settings → Company Information / Preferences (resources/scripts/admin/views/settings/CompanyInfoSettings.vue, PreferencesSetting.vue)`
- **numbering-and-templates** [settings]: Invoice and quote number formats, default notes, due dates and which of the three built-in PDF layouts to use. → `Settings → Customization (resources/scripts/admin/views/settings/customization/); built-in PDF layouts in resources/views/app/pdf/invoice/ and estimate/`
- **taxes-payments-fields** [settings]: VAT rates, accepted payment methods, extra fields on invoices and reusable notes such as bank details. → `Settings → Tax Types, Payment Modes, Custom Fields, Notes, Expense Categories (same settings folder)`
- **mail-and-notifications** [settings]: Send emails from your own address (SMTP, Mailgun, SES or sendmail) and choose which events notify you. → `Settings → Mail Configuration and Notifications (MailConfigSetting.vue, NotificationsSetting.vue)`
- **pdf-engine** [settings]: Switch between the built-in dompdf engine and Gotenberg for better layout and font support. → `Settings → PDF Generation (PDFGenerationSetting.vue), or PDF_DRIVER in .env`
- **custom-pdf-templates** [code]: Your own invoice and quote layout, kept in storage so app updates don't overwrite it. Choose it when creating a document. → `php artisan make:template <name> --type=invoice (or --type=estimate) creates a Blade layout in storage/app/templates/pdf/ (app/Console/Commands/CreateTemplateCommand.php)`
- **theme-colours** [code]: Change the app's purple to your brand colour by editing one colour scale. → `resources/css/themes.css (the --color-primary-* scale), imported by resources/css/invoiceshelf.css; rebuild with pnpm build`
- **api** [extend]: Create invoices or customers from other tools, e.g. a booking form or a spreadsheet. There is no published API reference for 2.x, so read routes/api.php. → `REST API under /api/v1 with Sanctum tokens (routes/api.php)`
- **modules** [extend]: Official add-on modules from the InvoiceShelf marketplace. → `Modules page (resources/scripts/admin/views/modules/), connected with a marketplace API token; installed into the Modules/ folder`
- **screens-and-logic** [code]: New screens or behaviour. Every change needs a Pest test, and migrations must run on SQLite, MySQL and PostgreSQL (see AGENTS.md). → `resources/scripts/admin/views/** (Vue), app/Http/Controllers/V1/**, app/Models/, app/Services/, database/migrations/`

## Must keep working
- Existing invoices, payments and numbering. Never renumber or delete sent invoices; back up before any change.
- Amounts and tax calculations. Totals must stay identical for existing documents.
- Separation between companies. Every query must stay scoped to the current company (company_id and the company header).
- Migrations must work on SQLite, MySQL and PostgreSQL.
- Custom PDF templates in storage/app/templates/pdf/ must survive redeploys; keep that folder in the storage volume and backups.

## Staying updatable
Settings, custom fields, custom PDF templates, the API and modules cover most needs without a fork. Follow AGENTS.md for any code change (Form Requests, policies, API Resources, Pest tests, Pint). The 2.x line now only takes security fixes and documentation, so new features belong on 3.x, which upstream still calls an alpha preview; keep personal 2.x changes small so security releases merge cleanly.

## Data, costs and safety
- Personal data: **yes**. Stored in: SQLite file in the storage volume by default (or MySQL/MariaDB/PostgreSQL); PDFs, logos, receipts and custom PDF templates in storage/ or on an assigned file disk. Customer names, addresses, emails, invoices, payments and expenses: business records you may be legally required to keep. Use the built-in backups (Settings → Backup, which can save to a separate file disk) and back up the storage volume and database before every upgrade or code change.
- Service: Email (SMTP, Mailgun, Amazon SES or sendmail) (optional, free with most providers): Emailing invoices, quotes, receipts and payment reminders to customers.
- Service: S3, Dropbox or DigitalOcean Spaces (optional, pay-per-use): Keep PDFs, uploads and backups off the server (Settings → File disk).
- Service: Gotenberg (optional, free (runs locally)): Optional PDF engine based on Chromium (PDF_DRIVER=gotenberg, or Settings → PDF generation); dompdf is the default.
- Service: InvoiceShelf module marketplace (optional, free and paid modules): Official add-on modules from invoiceshelf.com, connected with a marketplace API token on the Modules page.
- Setting `APP_KEY` (**secret**: the person enters it themselves, never in chat): Laravel encryption key. The installer or Docker image sets it up. Back it up and never paste it into an AI chat.
- Setting `APP_URL`: The address you open InvoiceShelf at, including http or https and any port. Links in customer emails use it.
- Setting `DB_CONNECTION`: sqlite (the default), mysql or pgsql. DB_HOST, DB_PORT, DB_DATABASE and DB_USERNAME go with it.
- Setting `DB_PASSWORD` (**secret**: the person enters it themselves, never in chat): Database password for MySQL/MariaDB or PostgreSQL.
- Setting `SESSION_DOMAIN`: Your domain name or IP address. Must match how you open the app or logins fail.
- Setting `SANCTUM_STATEFUL_DOMAINS`: The domain and port you open the app at (e.g. localhost:8090), comma-separated if several. Must match or logins fail.
- Setting `PDF_DRIVER`: dompdf (default) or gotenberg. With Gotenberg also set GOTENBERG_HOST, and GOTENBERG_ALLOWED_PRIVATE_HOST if it runs on a private network.
- Setting `DOMPDF_ENABLE_REMOTE`: Keep false (the default) so text in PDF notes can't make the server fetch other addresses. Only set true if you trust all PDF content.
- Setting `CRON_JOB_AUTH_TOKEN` (**secret**: the person enters it themselves, never in chat): Only for hosts without a crontab that call /api/cron from an outside scheduler; sent in the x-authorization-token header. The Docker image runs the scheduler itself.
- Run 2.4.7 or later. Earlier Docker images shipped a PHP version with critical remote-code-execution flaws (CVE-2026-109618/109619).
- Customers open the portal and documents from the internet, so serve InvoiceShelf over HTTPS behind a reverse proxy and keep it updated.
- API tokens (issued per device by /api/v1/auth/login) don't expire by default and there is no screen to list them. Keep them private and call /api/v1/auth/logout to revoke one.
- Keep DOMPDF_ENABLE_REMOTE=false unless you trust every note and template that goes into a PDF.
- Keep APP_KEY, database passwords and the modules API token out of AI chats.

---

# Customising InvoiceShelf

InvoiceShelf is a Laravel (PHP) backend with a Vue 3 single-page app. **Most business set-up is settings.** This listing is pinned to release 2.4.7, the stable 2.x line, which upstream supports with security fixes until 1 September 2027. Upstream ships an `AGENTS.md`; any AI making code changes must read it first.

Upstream is also building 3.x, which it still calls an alpha preview. Its screens, settings and docs differ, so make sure any guide you follow is for version 2.

## Level 1: Settings (no code)
- **Your business:** Settings → Company Information (name, logo, address) and Preferences (currency, language, date format, financial year).
- **Numbers and layouts:** Settings → Customization. Number formats such as `INV-000001`, default notes and terms, due dates. Pick one of the three built-in PDF layouts when creating a document.
- **Tax, payments, fields:** Settings → Tax Types (e.g. 20% VAT), Payment Modes, Custom Fields (e.g. "PO number"), Notes (reusable text such as bank details), Expense Categories.
- **Email:** Settings → Mail Configuration (SMTP, Mailgun, SES or sendmail) to send from your own address; Settings → Notifications for what you get told about.
- **Recurring invoices:** create one from the Recurring Invoices page and tick "Send Automatically" if it should email itself. The Docker image runs the scheduler for you; a manual install needs a crontab entry (see `.env.example`).
- **People:** Users, and Settings → Roles for what each one may do.
- **Running it:** Settings → File Disk (S3, Dropbox, DigitalOcean Spaces), Backup, PDF Generation (dompdf or Gotenberg), Exchange Rate and Update App.

## Level 2: Extend (no fork)
- **REST API** under `/api/v1`. Get a token with `POST /api/v1/auth/login` (email, password, device_name) and send it as a Bearer token with a `company` header. There is no published API reference for 2.x; `routes/api.php` lists every endpoint. Use it to create customers and invoices from forms or spreadsheets.
- **Modules** from the official marketplace: connect a marketplace API token on the Modules page. Modules install into the `Modules/` folder (a volume in Docker).
- **Customer portal:** turn on Portal Access for a customer; they sign in at `https://your-address/<company-slug>/customer/login`.

## Level 3: Code
Read upstream `AGENTS.md` first. Summary:

| Change | Where |
|---|---|
| Your own invoice and quote layout | `php artisan make:template <name> --type=invoice` (or `--type=estimate`) creates a Blade file in `storage/app/templates/pdf/`. Keep that folder in your storage volume and backups |
| Built-in PDF layouts | `resources/views/app/pdf/invoice/`, `estimate/`, `payment/` (Blade, rendered by dompdf by default: use static TTF fonts) |
| Brand colour | `resources/css/themes.css` (`--color-primary-*`), imported by `resources/css/invoiceshelf.css`; rebuild with `pnpm build`. There is no dark mode in 2.x |
| Screens | `resources/scripts/admin/views/**` (staff), `resources/scripts/customer/**` (portal); routes in `admin/admin-router.js` |
| API and logic | `routes/api.php`, controllers in `app/Http/Controllers/V1/**`, Form Requests, policies in `app/Policies/`, `app/Services/` |
| Data | `database/migrations/` (must run on SQLite, MySQL and PostgreSQL) |
| Text | `lang/en.json` (other languages come from Crowdin) |

## Running locally
- **Just use it:**
  1. `git clone https://github.com/InvoiceShelf/docker.git invoiceshelf && cd invoiceshelf`
  2. `cp docker-compose.sqlite.yml docker-compose.yml`. Its image `invoiceshelf/invoiceshelf:latest` is the stable 2.x release; change it to `:2.4.7` to stay on exactly this version.
  3. `docker compose up -d`, then open http://localhost:8090 and follow the wizard.
- **Develop** (`docker/development/README.md`):
  1. `cp .env.example .env`, then `./devenv` and pick a database (and optionally Gotenberg). It sets up Docker and the `invoiceshelf.test` host name.
  2. `./devenv run composer install` and `./devenv run php artisan key:generate`.
  3. On the host, with Node 24: `corepack enable && pnpm install --frozen-lockfile && pnpm dev`, then open http://invoiceshelf.test.
  4. Native alternative: `composer install && pnpm install && composer run dev`.
- **Check:** `php artisan test --compact`, `vendor/bin/pint --test`, `pnpm test` (ESLint). Rebuild assets with `pnpm build` after frontend changes.

## Pitfalls
- Back up first (Settings → Backup, plus the storage volume). Invoices are legal records.
- Use 2.4.7 or later: earlier Docker images had a PHP version with critical security flaws, and recurring invoices could be skipped.
- Logins fail if `SESSION_DOMAIN` and `SANCTUM_STATEFUL_DOMAINS` don't match the address you use.
- Every code change needs a Pest test; CI runs Pint and the tests.
- Don't change how totals and taxes are calculated for existing documents.
- Upstream's 2.x branch only accepts security fixes and documentation now, so keep personal changes in your own copy.

---
Machine-readable: [bespoke.yaml](https://handoff.bespokeai.software/p/invoiceshelf/98acbe2/r2/bespoke.yaml) · Hosting options: [hosting.md](https://handoff.bespokeai.software/p/invoiceshelf/98acbe2/r2/hosting.md) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/invoiceshelf/98acbe2/r2/SKILL.md)
