Skip to content

Latest commit

 

History

History
555 lines (399 loc) · 10.6 KB

File metadata and controls

555 lines (399 loc) · 10.6 KB

CI

Dabir

Dabir is an open-source letter numbering and registry system for organizations that need a simple, auditable, and structured replacement for spreadsheet-based letter tracking.

It provides a clean backend API, a web-based admin panel, role-based access control, Jalali date support, Excel migration, manual numbering, scanned letter attachments, S3-compatible object storage integration, and Kubernetes-ready deployment manifests.


Features

  • Letter numbering and registry management
  • Create, edit, preview, soft-delete, and search letters
  • Multiple numbering modes:
    • Fixed prefix numbering, such as DABIR-000001
    • Jalali yearly numbering, such as 405-0001
    • Manual numbering, such as 405-158, 405-ق-103, or any custom structure
  • Smart manual number suggestion based on the entered prefix
  • Support for Persian and Arabic digits in date and number inputs
  • Jalali / Persian calendar support
  • Persian and English UI foundation
  • RTL-friendly user interface
  • Role-based access control
  • User management
  • Password change and password reset
  • Excel import for migrating existing letters
  • Import preview and duplicate detection
  • Preserving original imported letter numbers
  • Audit logs for important system actions
  • Setup wizard for first-time initialization
  • Optional scanned letter / attachment upload
  • S3-compatible object storage support for attachments
  • Private attachment storage with presigned download/view URLs
  • Attachment management: upload, view/download, and delete
  • Dark mode support
  • REST API with OpenAPI documentation
  • Docker Compose deployment
  • Kubernetes deployment with Helm
  • External PostgreSQL support
  • GitHub Actions CI

Roles

Dabir currently supports three access levels:

Role Description
superuser Full system access, user management, imports, audit logs, settings, and attachment management
editor Can create, edit, delete, and view letters; can manage attachments
readonly Can view letters and attachments

Tech Stack

Backend

  • Go
  • PostgreSQL
  • Chi Router
  • JWT authentication
  • Clean architecture style
  • Database migrations
  • S3-compatible object storage client

Frontend

  • Next.js
  • TypeScript
  • Tailwind CSS
  • shadcn/ui-style components
  • Jalali date picker
  • Dark mode
  • Persian / English localization foundation

Deployment

  • Docker Compose
  • Helm Chart
  • Kubernetes
  • External PostgreSQL
  • S3-compatible object storage, such as MinIO

Project Structure

.
├── cmd/
│   └── api/
├── internal/
│   ├── application/
│   ├── domain/
│   ├── delivery/
│   ├── infrastructure/
│   └── shared/
├── migrations/
├── web/
├── charts/
│   └── dabir/
├── deployments/
├── docs/
│   ├── openapi.yaml
│   └── wiki/
└── README.md

Quick Start with Docker Compose

Create environment file:

cp .env.example .env

Edit important values:

DB_PASSWORD=change-this-db-password
JWT_SECRET=change-this-secret-in-production

S3_ENDPOINT=http://localhost:9000
S3_REGION=us-east-1
S3_BUCKET=dabir-attachments
S3_ACCESS_KEY=dabir
S3_SECRET_KEY=dabir_minio_secret
S3_USE_SSL=false
S3_FORCE_PATH_STYLE=true
S3_PRESIGNED_URL_TTL_MINUTES=15
S3_MAX_UPLOAD_SIZE_MB=20

Start services:

make compose-up

Run migrations:

make migrate-up

Open the web UI:

http://localhost:3000

On the first run, Dabir redirects to the setup page where you can create the first superuser.


Local Development

Start PostgreSQL and MinIO:

make compose-up

Run backend:

export $(grep -v '^#' .env | xargs)
make run

Run frontend:

cd web
npm install
npm run dev

Frontend URL:

http://localhost:3000

Backend URL:

http://localhost:8080

MinIO Console URL:

http://localhost:9001

Default local MinIO credentials, unless changed in .env:

username: dabir
password: dabir_minio_secret

Numbering Modes

Dabir supports multiple numbering modes to fit different organizational workflows.

Fixed Prefix

Example:

DABIR-000001
DABIR-000002

Jalali Yearly

Example:

405-0001
405-0002
406-0001

Manual Numbering

Manual numbering stores the letter number exactly as entered by the user.

Examples:

405-158
405-ق-103
1401-MM-DM-95
HR-2026-0042

Manual numbering also includes smart suggestions. When a user starts typing a prefix, Dabir searches for the latest similar number and suggests the next one.

Examples:

Input prefix: 405-
Latest similar number: 405-158
Suggested number: 405-159
Input prefix: 405-ق-
Latest similar number: 405-ق-102
Suggested number: 405-ق-103

Persian and Arabic digits are normalized for suggestion lookup, so inputs such as ۴۰۵-ق- are also supported.


Letter Attachments / Scanned Letters

Dabir supports optional scanned letter attachments.

Supported file types:

PDF
JPG / JPEG
PNG

Attachment flow:

Create or edit a letter
Upload one or more optional files
Store files in S3-compatible object storage
Store only metadata in PostgreSQL
View/download files through short-lived presigned URLs
Delete attachments when needed

Attachments are stored privately in object storage. Dabir does not make the bucket public. The backend generates presigned URLs for viewing or downloading files.


Object Storage / S3 Configuration

Dabir uses S3-compatible object storage for attachments. MinIO is recommended for local development and small to medium on-prem deployments.

Required environment variables:

S3_ENDPOINT=http://minio:9000
S3_REGION=us-east-1
S3_BUCKET=dabir-attachments
S3_ACCESS_KEY=dabir
S3_SECRET_KEY=dabir_minio_secret
S3_USE_SSL=false
S3_FORCE_PATH_STYLE=true
S3_PRESIGNED_URL_TTL_MINUTES=15
S3_MAX_UPLOAD_SIZE_MB=20

For production, use a private bucket and a dedicated access key with limited permissions to only the required bucket.

Recommended production notes:

- Keep the bucket private
- Use TLS for the S3 endpoint
- Use a dedicated access key for Dabir
- Configure object storage backup or replication
- Keep S3_MAX_UPLOAD_SIZE_MB aligned with the ingress upload limit

For NGINX Ingress, make sure the upload size is higher than S3_MAX_UPLOAD_SIZE_MB:

nginx.ingress.kubernetes.io/proxy-body-size: "25m"

Kubernetes Deployment

Dabir includes a Helm chart:

charts/dabir

Dabir does not deploy PostgreSQL inside Kubernetes by default. It expects an external PostgreSQL database.

Dabir also expects an S3-compatible object storage endpoint for attachments, such as MinIO, Ceph RGW, or a cloud S3-compatible service.

Create namespace:

kubectl create namespace dabir

Create secret:

kubectl -n dabir create secret generic dabir-secret \
  --from-literal=DB_PASSWORD='YOUR_DB_PASSWORD' \
  --from-literal=JWT_SECRET='YOUR_LONG_RANDOM_JWT_SECRET' \
  --from-literal=S3_ACCESS_KEY='YOUR_S3_ACCESS_KEY' \
  --from-literal=S3_SECRET_KEY='YOUR_S3_SECRET_KEY'

Install with Helm:

helm upgrade --install dabir charts/dabir \
  -n dabir \
  --create-namespace \
  -f charts/dabir/examples/values-prod.yaml

Run database migrations separately against the external PostgreSQL database.


Helm S3 Values

The Helm chart supports S3 configuration through API environment variables and secrets.

Example values:

api:
  env:
    S3_ENDPOINT: "https://s3.example.com"
    S3_REGION: "us-east-1"
    S3_BUCKET: "dabir-attachments"
    S3_USE_SSL: "true"
    S3_FORCE_PATH_STYLE: "true"
    S3_PRESIGNED_URL_TTL_MINUTES: "15"
    S3_MAX_UPLOAD_SIZE_MB: "20"

  secrets:
    create: true
    existingSecret: ""
    DB_PASSWORD: "change-this-db-password"
    JWT_SECRET: "change-this-jwt-secret"
    S3_ACCESS_KEY: "change-this-s3-access-key"
    S3_SECRET_KEY: "change-this-s3-secret-key"

When using an existing secret, it must contain:

DB_PASSWORD
JWT_SECRET
S3_ACCESS_KEY
S3_SECRET_KEY

Excel Import

Dabir can import existing letters from Excel files.

Supported format:

.xlsx

Supported logical columns:

Field Supported column names
letter_number letter_number, number, no, شماره نامه, شماره
title title, subject, عنوان, عنوان نامه, موضوع
letter_date letter_date, date, تاریخ, تاریخ نامه
sender sender, from, فرستنده, ارسال کننده
receiver receiver, to, گیرنده, دریافت کننده, مقصد

Import flow:

Upload Excel
Preview and validate
Detect duplicates
Commit import
Preserve original letter numbers
Continue numbering from the imported data

The importer supports real-world legacy files and can preserve original manual letter numbers instead of forcing them into a generated numeric format.


Jalali Date Support

Dabir supports official Iranian Jalali dates in the UI.

Accepted input examples:

1405/03/01
۱۴۰۵/۰۳/۰۱

Dates are stored in PostgreSQL as standard DATE values and returned by the API in both Gregorian and Jalali formats.

Example API response:

{
  "letter_date": "2026-05-22",
  "letter_date_jalali": "1405/03/01"
}

API Documentation

OpenAPI specification:

docs/openapi.yaml

Validate OpenAPI:

docker run --rm -v "$PWD:/work" redocly/cli lint /work/docs/openapi.yaml

Useful Commands

Run backend tests:

go test $(go list ./... | grep -v '/web/')

Run frontend checks:

cd web
npm run lint
npm run build

Lint Helm chart:

helm lint charts/dabir

Render Helm templates:

helm template dabir charts/dabir -n dabir

Check rendered S3 environment variables:

helm template dabir charts/dabir -n dabir > /tmp/dabir-rendered.yaml
grep -n "S3_" /tmp/dabir-rendered.yaml

Documentation

More detailed documentation is available in:

docs/

The previous full development guide is archived here:

docs/wiki/full-project-guide.md

Roadmap

  • Dashboard statistics endpoint
  • Better runtime configuration for web deployment
  • Print / export letter confirmation
  • Advanced letter search and filters
  • Full i18n coverage
  • Migration Job support in Helm
  • Release automation
  • Attachment thumbnails and richer preview experience
  • Export letters to Excel / PDF

License

This project is licensed under the Apache License 2.0.