Removes local vendor directory in favor of Go module proxy for cleaner repository and improved dependency management. Dependencies will now be fetched automatically from proxy.golang.org during builds. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
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
Using Just (Recommended)
# 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)
- Environment Variables (highest priority)
- Config Files:
config.json,config.yaml,config.toml - 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
- Config file not found: The server will use environment variables and defaults if no config file is found
- Database connection failed: Check your database credentials and connectivity
- 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:
- Existing
config.jsonfiles continue to work - Add environment variables for sensitive data
- Use SQLite for easier local development
- 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.