4.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
PIRP (Packed Internes Rechnungsprogramm) is a simple internal invoicing application written in PHP. It's a German-language business tool for managing invoices, customers, expenses, recurring subscriptions, and generating EÜR (Einnahmen-Überschuss-Rechnung / income-expenditure accounting) reports.
Tech Stack
- PHP (vanilla, no framework)
- PostgreSQL database
- Dompdf for PDF invoice generation
- Session-based authentication
- SMF-style UI theme (CSS with gradients, tabs)
Architecture
/var/www/pirp/
├── public/ # Web-accessible files (document root)
│ ├── assets/ # CSS (style.css - SMF-style theme)
│ ├── uploads/ # User-uploaded files
│ │ ├── logos/ # Company logos
│ │ ├── expenses/# Expense receipts (PDFs)
│ │ └── invoices/# Archived invoice PDFs (GoBD-compliant)
│ └── *.php # Page controllers
├── src/ # Business logic (not web-accessible)
│ ├── config.php # Database credentials, BASE_URL, session setup
│ ├── db.php # PDO connection singleton (get_db())
│ ├── auth.php # Login/logout/require_login functions
│ ├── invoice_functions.php # Settings + invoice number generation
│ ├── customer_functions.php # Customer CRUD
│ ├── expense_functions.php # Expense CRUD
│ ├── pdf_functions.php # GoBD-compliant PDF archiving
│ └── recurring_functions.php # Subscription invoice management
├── tools/ # CLI utilities
│ ├── hash.php # Password hash generator
│ ├── migrate_pdf.sql # DB migration for PDF archiving
│ ├── migrate_pdfs.php # Migrate existing invoices to archived PDFs
│ └── migrate_recurring.sql # DB migration for subscriptions
├── schema.sql # Full database schema
└── vendor/ # Composer dependencies
Database
PostgreSQL with tables: users, settings, customers, invoices, invoice_items, expenses, recurring_templates, recurring_template_items, recurring_log. See schema.sql for complete schema.
Key relationships:
invoices→customers(customer_id foreign key)invoice_items→invoices(invoice_id foreign key, CASCADE delete)recurring_templates→customersrecurring_template_items→recurring_templates(CASCADE delete)recurring_log→recurring_templates,invoices
VAT modes: klein (Kleinunternehmer - VAT exempt) or normal (standard VAT).
Development Commands
# Install dependencies
composer install
# Generate password hash for new user
php tools/hash.php YOUR_PASSWORD
# Initialize database (fresh install)
psql -U pirp_user -d pirp -f schema.sql
# Apply migrations (existing database)
psql -U pirp_user -d pirp -f tools/migrate_pdf.sql
psql -U pirp_user -d pirp -f tools/migrate_recurring.sql
# Migrate existing invoices to archived PDFs
php tools/migrate_pdfs.php
Configuration
Database connection in src/config.php. Set BASE_URL if running in a subdirectory (e.g., /pirp).
Key Patterns
- All public pages include
require_login()fromsrc/auth.php - Database access via
get_db()singleton returning PDO instance - Invoice numbers:
PIRP-YYYY-NNNNN(auto-generated) - Customer numbers:
PIKN-NNNNNN(auto-generated)
GoBD-Compliant PDF Archiving
German tax law (GoBD) requires invoices to be stored immutably. PDFs are:
- Generated once at invoice creation
- Stored in
public/uploads/invoices/{year}/ - Protected with chmod 444
- Verified via SHA-256 hash stored in
invoices.pdf_hash
Key functions in src/pdf_functions.php:
archive_invoice_pdf($id)- Generate and store PDFget_archived_pdf_path($id)- Get path to archived PDFverify_invoice_pdf($id)- Verify integrity via hash
Recurring Invoices (Subscriptions)
Subscription invoices for recurring customers with intervals:
monthly- Every monthquarterly- Every 3 monthsyearly- Every year
Key pages:
recurring.php- Overview of subscription templatesrecurring_edit.php- Create/edit templatesrecurring_generate.php- Generate due invoices
Key functions in src/recurring_functions.php:
get_pending_recurring_invoices()- Get due subscriptionsgenerate_invoice_from_template($id)- Create invoice from templatecalculate_next_due_date($interval, $date)- Calculate next due date