Files
openaccounting-server/README.md
Aaron Guise f99a866e13 feat: implement unified S3-compatible storage system
Consolidates storage backends into a single S3-compatible driver that supports:
- AWS S3 (native)
- Backblaze B2 (S3-compatible API)
- Cloudflare R2 (S3-compatible API)
- MinIO and other S3-compatible services
- Local filesystem for development

This replaces the previous separate B2 driver with a unified approach,
reducing dependencies and complexity while adding support for more services.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-01 23:07:44 +12:00

13 KiB

Open Accounting Server

Open Accounting Server is a modern financial accounting system built with Go, featuring GORM integration, Viper configuration management, and Docker support.

Features

  • GORM Integration: Modern ORM with SQLite and MySQL support
  • Viper Configuration: Flexible config management with environment variables
  • Modular Storage: S3-compatible attachment storage (Local, AWS S3, Backblaze B2, Cloudflare R2, MinIO)
  • Docker Ready: Containerized deployment with multi-stage builds
  • SQLite Support: Easy local development and testing
  • Security: Environment variable support for sensitive data

Prerequisites

  • Go 1.24+ (updated from 1.8+)
  • SQLite (for development) or MySQL 5.7+ (for production)
  • Docker (optional, for containerized deployment)
  • Just (optional, for build automation)

Quick Start

# Setup development environment
just dev-setup

# Run in development mode
just run-dev

# Build and run with Docker
just docker-run

Manual Setup

# Install dependencies
go mod download

# Run with SQLite (development)
OA_DATABASE_DRIVER=sqlite ./server

# Run with MySQL (production)
OA_DATABASE_DRIVER=mysql OA_PASSWORD=secret ./server

Configuration

The server now uses Viper for advanced configuration management with multiple sources:

Configuration Sources (in order of precedence)

  1. Environment Variables (highest priority)
  2. Config Files: config.json, config.yaml, config.toml
  3. Default Values (lowest priority)

Config File Locations

  • ./config.json (current directory)
  • /etc/openaccounting/config.json
  • ~/.openaccounting/config.json

Environment Variables

All configuration can be overridden with environment variables using the OA_ prefix:

Environment Variable Config Field Default Description
OA_ADDRESS Address localhost Server bind address
OA_PORT Port 8080 Server port
OA_API_PREFIX ApiPrefix /api/v1 API route prefix
OA_DATABASE_DRIVER DatabaseDriver sqlite Database type: sqlite or mysql
OA_DATABASE_FILE DatabaseFile ./openaccounting.db SQLite database file
OA_DATABASE_ADDRESS DatabaseAddress localhost:3306 MySQL server address
OA_DATABASE Database MySQL database name
OA_USER User Database username
OA_PASSWORD Password Database password ⚠️
OA_MAILGUN_DOMAIN MailgunDomain Mailgun domain
OA_MAILGUN_KEY MailgunKey Mailgun API key ⚠️
OA_MAILGUN_EMAIL MailgunEmail Mailgun email
OA_MAILGUN_SENDER MailgunSender Mailgun sender name

Storage Configuration

Environment Variable Config Field Default Description
OA_STORAGE_BACKEND Storage.Backend local Storage backend: local or s3

Local Storage

Environment Variable Config Field Default Description
OA_STORAGE_LOCAL_ROOTDIR Storage.Local.RootDir ./uploads Root directory for file storage
OA_STORAGE_LOCAL_BASEURL Storage.Local.BaseURL Base URL for serving files

S3-Compatible Storage (AWS S3, Backblaze B2, Cloudflare R2, MinIO)

Environment Variable Config Field Default Description
OA_STORAGE_S3_REGION Storage.S3.Region Region (use "auto" for Cloudflare R2)
OA_STORAGE_S3_BUCKET Storage.S3.Bucket Bucket name
OA_STORAGE_S3_PREFIX Storage.S3.Prefix Optional prefix for all objects
OA_STORAGE_S3_ACCESSKEYID Storage.S3.AccessKeyID Access Key ID ⚠️
OA_STORAGE_S3_SECRETACCESSKEY Storage.S3.SecretAccessKey Secret Access Key ⚠️
OA_STORAGE_S3_ENDPOINT Storage.S3.Endpoint Custom endpoint (see examples below)
OA_STORAGE_S3_PATHSTYLE Storage.S3.PathStyle false Use path-style addressing

S3-Compatible Service Endpoints:

  • AWS S3: Leave endpoint empty, set appropriate region
  • Backblaze B2: https://s3.us-west-004.backblazeb2.com (replace region as needed)
  • Cloudflare R2: https://<account-id>.r2.cloudflarestorage.com
  • MinIO: http://localhost:9000 (or your MinIO server URL)

⚠️ Security: Always use environment variables for sensitive data like passwords and API keys.

Configuration Examples

Development (SQLite)

# Minimal - uses defaults
./server

# Custom database file and port
OA_DATABASE_FILE=./dev.db OA_PORT=9090 ./server

Production (MySQL)

# With environment variables (recommended)
export OA_DATABASE_DRIVER=mysql
export OA_DATABASE_ADDRESS=db.example.com:3306
export OA_DATABASE=openaccounting_prod
export OA_USER=openaccounting
export OA_PASSWORD=secure_password
export OA_MAILGUN_KEY=key-abc123
./server

# Or inline
OA_DATABASE_DRIVER=mysql OA_PASSWORD=secret OA_MAILGUN_KEY=key-123 ./server

Storage Configuration Examples

# Local storage (default)
export OA_STORAGE_BACKEND=local
export OA_STORAGE_LOCAL_ROOTDIR=./uploads
./server

# AWS S3
export OA_STORAGE_BACKEND=s3
export OA_STORAGE_S3_REGION=us-west-2
export OA_STORAGE_S3_BUCKET=my-app-attachments
export OA_STORAGE_S3_ACCESSKEYID=your-access-key
export OA_STORAGE_S3_SECRETACCESSKEY=your-secret-key
./server

# Backblaze B2 (S3-compatible)
export OA_STORAGE_BACKEND=s3
export OA_STORAGE_S3_REGION=us-west-004
export OA_STORAGE_S3_BUCKET=my-app-attachments
export OA_STORAGE_S3_ACCESSKEYID=your-b2-key-id
export OA_STORAGE_S3_SECRETACCESSKEY=your-b2-application-key
export OA_STORAGE_S3_ENDPOINT=https://s3.us-west-004.backblazeb2.com
export OA_STORAGE_S3_PATHSTYLE=true
./server

# Cloudflare R2
export OA_STORAGE_BACKEND=s3
export OA_STORAGE_S3_REGION=auto
export OA_STORAGE_S3_BUCKET=my-app-attachments
export OA_STORAGE_S3_ACCESSKEYID=your-r2-access-key
export OA_STORAGE_S3_SECRETACCESSKEY=your-r2-secret-key
export OA_STORAGE_S3_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
./server

# MinIO (self-hosted)
export OA_STORAGE_BACKEND=s3
export OA_STORAGE_S3_REGION=us-east-1
export OA_STORAGE_S3_BUCKET=my-app-attachments
export OA_STORAGE_S3_ACCESSKEYID=minioadmin
export OA_STORAGE_S3_SECRETACCESSKEY=minioadmin
export OA_STORAGE_S3_ENDPOINT=http://localhost:9000
export OA_STORAGE_S3_PATHSTYLE=true
./server

Docker

# SQLite with volume mount
docker run -p 8080:8080 \
  -e OA_DATABASE_DRIVER=sqlite \
  -v ./data:/app/data \
  openaccounting-server:latest

# MySQL with environment variables
docker run -p 8080:8080 \
  -e OA_DATABASE_DRIVER=mysql \
  -e OA_DATABASE_ADDRESS=mysql:3306 \
  -e OA_PASSWORD=secret \
  openaccounting-server:latest

# With AWS S3 storage
docker run -p 8080:8080 \
  -e OA_STORAGE_BACKEND=s3 \
  -e OA_STORAGE_S3_REGION=us-west-2 \
  -e OA_STORAGE_S3_BUCKET=my-attachments \
  -e OA_STORAGE_S3_ACCESSKEYID=your-key \
  -e OA_STORAGE_S3_SECRETACCESSKEY=your-secret \
  openaccounting-server:latest

# With Cloudflare R2 storage
docker run -p 8080:8080 \
  -e OA_STORAGE_BACKEND=s3 \
  -e OA_STORAGE_S3_REGION=auto \
  -e OA_STORAGE_S3_BUCKET=my-attachments \
  -e OA_STORAGE_S3_ACCESSKEYID=your-r2-key \
  -e OA_STORAGE_S3_SECRETACCESSKEY=your-r2-secret \
  -e OA_STORAGE_S3_ENDPOINT=https://account-id.r2.cloudflarestorage.com \
  openaccounting-server:latest

Database Setup

SQLite (Development)

SQLite databases are created automatically. No manual setup required.

# Uses ./openaccounting.db by default
OA_DATABASE_DRIVER=sqlite ./server

# Custom location
OA_DATABASE_DRIVER=sqlite OA_DATABASE_FILE=./data/myapp.db ./server

MySQL (Production)

Use the provided schema files to create your MySQL database:

-- Create database and user
CREATE DATABASE openaccounting;
CREATE USER 'openaccounting'@'%' IDENTIFIED BY 'secure_password';
GRANT ALL PRIVILEGES ON openaccounting.* TO 'openaccounting'@'%';

The server will automatically create tables and run migrations on startup.

Building

Local Build

# Development build
go build -o server ./core/

# Production build (optimized)
CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -ldflags="-w -s" -o server ./core/

Docker Build

# Build image
docker build -t openaccounting-server:latest .

# Multi-platform build
docker buildx build --platform linux/amd64,linux/arm64 -t openaccounting-server:latest .

Running

Development

# Local with SQLite
just run-dev

# Or manually
OA_DATABASE_DRIVER=sqlite OA_PORT=8080 ./server

Production

# With Docker Compose (recommended)
docker-compose up -d

# Or manually with environment file
export $(cat .env | xargs)
./server

Just Recipes

This project includes a justfile with common tasks:

just --list                 # Show all available recipes
just build                  # Build the application
just run-dev                # Run in development mode
just docker-build           # Build Docker image
just docker-run             # Run container
just test                   # Run tests
just config-help            # Show configuration help
just dev-setup              # Complete development setup

API

The server provides a REST API at /api/v1/ (configurable via OA_API_PREFIX).

Health Check

curl http://localhost:8080/api/v1/health

Development

Prerequisites

# Install Go dependencies
go mod download

# Install development tools (optional)
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

Running Tests

just test
# or
go test ./...

Code Quality

# Format code
just fmt

# Lint code (requires golangci-lint)
just lint

Docker

Official Images

Docker images are available with multi-stage builds for optimal size and security:

  • Non-root user for security
  • Alpine Linux base for minimal attack surface
  • Health checks included
  • Volume support for data persistence

Environment Variables in Docker

ENV OA_DATABASE_DRIVER=sqlite \
    OA_DATABASE_FILE=/app/data/openaccounting.db \
    OA_ADDRESS=0.0.0.0 \
    OA_PORT=8080

Data Persistence

# Mount volume for SQLite data
docker run -v ./data:/app/data openaccounting-server:latest

# Use named volume
docker volume create openaccounting-data
docker run -v openaccounting-data:/app/data openaccounting-server:latest

Deployment

Docker Compose

version: '3.8'
services:
  openaccounting:
    image: openaccounting-server:latest
    ports:
      - "8080:8080"
    environment:
      OA_DATABASE_DRIVER: mysql
      OA_DATABASE_ADDRESS: mysql:3306
      OA_DATABASE: openaccounting
      OA_USER: openaccounting
      OA_PASSWORD: ${DB_PASSWORD}
    depends_on:
      - mysql
  
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: openaccounting
      MYSQL_USER: openaccounting
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: openaccounting-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: openaccounting-server
  template:
    metadata:
      labels:
        app: openaccounting-server
    spec:
      containers:
      - name: openaccounting-server
        image: openaccounting-server:latest
        ports:
        - containerPort: 8080
        env:
        - name: OA_DATABASE_DRIVER
          value: "mysql"
        - name: OA_PASSWORD
          valueFrom:
            secretKeyRef:
              name: openaccounting-secrets
              key: db-password

Troubleshooting

Common Issues

  1. Config file not found: The server will use environment variables and defaults if no config file is found
  2. Database connection failed: Check your database credentials and connectivity
  3. Permission denied: Ensure proper file permissions for SQLite database files

Debug Mode

# Enable verbose logging
OA_LOG_LEVEL=debug ./server

# Check configuration
just config-help

Health Checks

# Application health
curl http://localhost:8080/api/v1/health

# Docker health check
docker inspect --format='{{.State.Health.Status}}' container_name

Migration from Legacy Setup

The server maintains backward compatibility with existing config.json files while adding Viper features:

  1. Existing config.json files continue to work
  2. Add environment variables for sensitive data
  3. Use SQLite for easier local development
  4. Leverage Docker for production deployments

Help & Support

  • Documentation: This README and inline code comments
  • Issues: GitHub Issues for bug reports and feature requests
  • Community: Join our Slack chatroom

License

See LICENSE file for details.