crystalbank

An open source core-banking system written in crystal

CrystalBank (CI)

crystalbank

CrystalBank is an open source, event-sourced multi-purpose ledger system built in Crystal. It is designed to serve as a solid foundation for financial applications — demonstrating how core banking concepts can be implemented cleanly on a minimal, self-contained infrastructure.

What it does

At its core, CrystalBank is an event-sourced ledger (powered by crystal-es) with first-class support for accounts, transfers, and customers. Every state change is recorded as an immutable event, making the full history of the system auditable and replayable.

The system is multi-tenant ready through an embedded roles and permissions model that provides fine-grained data scoping and ownership. Access rights and data visibility are controlled at the data level — not just at the API boundary.

Multi-layer approval workflows allow financial operations to be reviewed and approved across multiple levels before they take effect, making the system suitable for regulated environments where maker-checker controls are required.

The entire stack runs on PostgreSQL — the same database instance handles the event store, projections, and the outbox queue. This keeps the infrastructure footprint minimal while preserving flexibility across different deployment contexts.

A Svelte-based frontend dashboard provides a visual interface to the system, making it accessible to non-engineers and easier to demonstrate.

Capabilities

Domain Status Description
Accounts ✅ Full account lifecycle management including opening, blocking, and unblocking with stackable cause tracking
Payments ✅ SEPA credit transfer processing with approval workflow integration and automated ledger posting
Ledger ✅ Double-entry bookkeeping engine recording all money movements as immutable debit/credit entries
Customers ✅ Customer onboarding and profile management for natural persons and organisations
Users ✅ User management with role assignment and scope-based access control
API Keys ✅ Generation, rotation, and revocation of API keys for programmatic access
Authentication ✅ API key and credential-based authentication for both human users and machine clients
Approval Workflows ✅ Multi-layer maker-checker workflows allowing sensitive operations to be reviewed and approved across multiple levels
Roles & Permissions ✅ Fine-grained permission model with role grouping for controlling what each user can see and do
Scopes ✅ Hierarchical tenant and business unit isolation — controls data ownership and visibility across the ledger
Events ✅ Queryable audit trail exposing the full stream of domain events to authorised users

Roadmap

  • More refined and optimized frontend
  • Dedicated project website
  • Full event replay to re-project state at any point in time (via crystal-es)

Next up:

  • Self sign-up to the platform
  • ISO 8583 connectors
  • ISO 20022 connectors

Potential improvements under exploration:

  • Dynamic Consistency Boundary — evaluating whether DCB-style aggregate boundaries could improve consistency guarantees and reduce coupling across domains without sacrificing the event-sourced model

Project Structure

crystalbank/
├── app/
│   ├── frontend/       # Svelte-based SPA dashboard
│   │   ├── src/        # Svelte components and application logic
│   │   ├── package.json
│   │   └── vite.config.js
│   ├── public/         # Built frontend assets (generated by build-frontend)
│   ├── src/            # Crystal backend source
│   └── spec/           # Crystal specs
├── docker-compose.yml
└── Makefile

Setup

Prerequisites

Start the environment

$ make dev

This builds the Docker image (if not already present), starts the database, API server, and API documentation services, and opens a console in the running container.

All available make targets can be listed with:

$ make help

Seed the environment

In order to access the API, the initial API credentials need to be seeded. Run this inside the console:

$ crystal app/src/server/start.cr --seed

This will output credentials for two admin users — a Super Admin (initiator) and an Approver:

-----------------------------------------------------
--- Seed credentials Super Admin
client_id:     '0193cc51-cc9b-7955-82ca-7a6482587201'
client_secret: 'secret'
-----------------------------------------------------
-----------------------------------------------------
--- Seed credentials Approver
client_id:     '0193cc51-dd2e-8866-93db-8b7593698312'
client_secret: 'secret'
-----------------------------------------------------

Start the API server

$ crystal src/server/start.cr

The API is exposed on http://localhost:4000.

Build the Svelte frontend

The frontend is a Svelte SPA located in app/frontend/. It is built with Vite and outputs static assets into app/public/, which is served by the Crystal backend.

To build the frontend, run from the project root:

$ make build-frontend

This runs npm install && npm run build inside a node:22-alpine Docker container — no local Node.js installation required. The build produces:

  • app/public/app.js — bundled JavaScript
  • app/public/style.css — bundled CSS

To iterate on the frontend locally outside of Docker, use the Vite dev server directly:

$ cd app/frontend
$ npm install
$ npm run dev

Generate OpenAPI specs

To regenerate the API specification:

$ crystal src/server/start.cr -d -f openapi.json

The updated spec is automatically picked up by the running API documentation services.

View API documentation

Access the PostgreSQL database

postgres://<user>:<password>/eventstore@localhost:4010

Contributing

  1. Fork it (https://github.com/your-github-user/crystalbank/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

Repository

crystalbank

Owner
Statistic
  • 10
  • 1
  • 6
  • 0
  • 0
  • 2 months ago
  • October 23, 2024
License

MIT License

Links
Synced at

Sun, 16 Aug 2026 21:34:03 GMT

Languages