Quatrain Core is a modular TypeScript framework designed to accelerate business application development with Backend as a Service (BaaS) solutions like Firebase and Supabase. The framework provides clean separation of concerns between logic, data, and storage, using an adapter pattern to provide consistent interfaces across different BaaS providers.
The framework is specifically designed for modern Backend as a Service platforms that provide:
- Managed databases (Firestore, Supabase Postgres)
- Authentication services (Firebase Auth, Supabase Auth)
- Real-time capabilities (Firestore real-time, Supabase real-time)
- Storage solutions (Firebase Storage, Supabase Storage)
- Edge functions (Firebase Functions, Supabase Edge Functions)
Deployment Flexibility: Solutions like Supabase work seamlessly whether deployed as:
- SaaS (hosted by Supabase)
- Self-hosted via Docker Compose
- Kubernetes for enterprise deployments
- On-premise for data sovereignty requirements
The framework is organized as a monorepo with core packages and BaaS-focused adapters:
@quatrain/core (Foundation - works standalone)
βββ π₯ Firebase Ecosystem
β βββ @quatrain/backend-firestore (Firestore NoSQL)
β βββ @quatrain/auth-firebase (Firebase Auth)
β βββ @quatrain/storage-firebase (Firebase Storage)
β βββ @quatrain/cloudwrapper-firebase (Firebase Functions)
β βββ @quatrain/messaging-firebase (FCM)
βββ π’ Supabase Ecosystem
β βββ @quatrain/backend-postgres (PostgreSQL - works with Supabase)
β βββ @quatrain/auth-supabase (Supabase Auth)
β βββ @quatrain/storage-supabase (Supabase Storage)
β βββ @quatrain/cloudwrapper-supabase (Supabase Edge Functions)
βββ π Traditional Backends (for migration/hybrid scenarios)
β βββ @quatrain/backend-sqlite (Local development)
β βββ @quatrain/storage-s3 (S3-compatible storage)
βββ π¬ Message Queues (for complex workflows)
β βββ @quatrain/queue-amqp (RabbitMQ)
β βββ @quatrain/queue-aws (AWS SQS)
β βββ @quatrain/queue-gcp (Google Pub/Sub)
βββ @quatrain/log (Structured logging)
βββ @quatrain/worker (Background processing)Foundation package providing base components and business objects - works standalone without persistence
@quatrain/backend package and
its adapters.
- Base Objects:
BaseObject,AbstractObject,DataObject- Work entirely in memory - Built-in Models:
User,Entitywith full property definitions - No database required - Property System: Strong typing with validation (
StringProperty,NumberProperty,DateTimeProperty, etc.) - Object URI: Unified resource identification system - Works with or without persistence
- Status Management: Built-in status lifecycle (
created,pending,active,deleted) - Business Logic: Complete object lifecycle management without requiring database connections
import { BaseObject, StringProperty, User } from '@quatrain/core'
// Create a custom model
export class Product extends BaseObject {
static COLLECTION = 'products'
static PROPS_DEFINITION = [
{
name: 'name',
type: StringProperty.TYPE,
mandatory: true,
minLength: 1,
maxLength: 100,
},
{
name: 'price',
type: NumberProperty.TYPE,
mandatory: true,
min: 0,
},
]
}
// Use built-in User model (no database required)
const user = await User.factory()
user._.firstname = 'John'
user._.lastname = 'Doe'
user._.email = 'john@example.com'
// All validation and business logic works without persistence
console.log(user._.name) // "John Doe" (auto-generated)
console.log(user.isValid()) // true/false based on validation rulesThe core package is fully functional without any backend dependencies:
import { User, Entity, StringProperty } from '@quatrain/core'
// Create and validate objects in memory
const user = await User.factory()
user._.firstname = 'Jane'
user._.email = 'jane@example.com'
// Validation works without database
if (user.isValid()) {
console.log('User is valid')
}
// Business logic and relationships work in memory
const entity = await Entity.factory()
entity._.name = 'ACME Corp'
user._.entity = entity
// Object serialization/deserialization
const userData = user.toJSON()
const newUser = await User.factory(userData)Database abstraction layer with CRUD operations and querying - adds persistence to core objects
- Abstract Base:
AbstractBackendAdapterfor consistent database interfaces - Query Builder: Advanced filtering, sorting, and pagination
- Repositories: Business logic layer for data operations
- Middleware Support: Data transformation and validation hooks
import { Backend, Filter, OperatorKeys, User } from '@quatrain/backend'
// Query with filters
const users = await backend.find(
User.factory(),
[
new Filter('status', 'active', OperatorKeys.equals),
new Filter('email', '@company.com', OperatorKeys.like),
],
{ limits: { batch: 10, offset: 0 } }
)
// Repository pattern
class UserRepository extends BaseRepository<User> {
async findActiveUsers() {
return this.find([new Filter('status', 'active', OperatorKeys.equals)])
}
}Authentication and authorization abstractions
- User Management: Registration, login, profile updates
- Token Handling: JWT verification and refresh
- Middleware Integration: Auth checks for backend operations
import { Auth } from '@quatrain/auth'
import { FirebaseAuthAdapter } from '@quatrain/auth-firebase'
// Setup authentication
Auth.addAdapter(
new FirebaseAuthAdapter({
config: {
/* Firebase config */
},
})
)
// Register user
const user = await Auth.register({
email: 'user@example.com',
password: 'securepassword',
firstname: 'John',
lastname: 'Doe',
})
// Authenticate
const token = await Auth.login('user@example.com', 'securepassword')File storage abstractions for various cloud providers
- File Operations: Upload, download, copy, move, delete
- Stream Support: Efficient handling of large files
- Metadata Management: File type detection and custom metadata
import { Storage } from '@quatrain/storage'
import { S3StorageAdapter } from '@quatrain/storage-s3'
// Setup storage
Storage.addAdapter(
new S3StorageAdapter({
config: {
accessKeyId: 'your-key',
secretAccessKey: 'your-secret',
region: 'us-east-1',
endpoint: 'https://s3.amazonaws.com',
},
})
)
// Upload file
const file = await Storage.create({
name: 'document.pdf',
path: 'documents/',
buffer: fileBuffer,
contentType: 'application/pdf',
})
// Download file
const downloadedFile = await Storage.read('documents/document.pdf')Message queue abstractions for asynchronous processing
- Multiple Providers: AMQP, AWS SQS, GCP Pub/Sub
- Message Publishing: Send messages to queues/topics
- Worker Patterns: Background job processing
import { Queue } from '@quatrain/queue'
import { AmqpQueueAdapter } from '@quatrain/queue-amqp'
// Setup queue
Queue.addAdapter(
new AmqpQueueAdapter({
connectionString: 'amqp://localhost:5672',
})
)
// Send message
await Queue.publish('email-queue', {
to: 'user@example.com',
subject: 'Welcome!',
template: 'welcome',
})
// Process messages
Queue.subscribe('email-queue', async (message) => {
await emailService.send(message.data)
})Structured logging for applications
- Multiple Log Levels: DEBUG, INFO, WARN, ERROR
- Adapter Pattern: Pluggable logging backends
- Domain-specific Loggers: Separate loggers for different components
import { Log, LogLevel } from '@quatrain/log'
// Setup logging
const logger = Log.addLogger('myapp', new ConsoleLoggerAdapter(), true)
logger.setLogLevel(LogLevel.INFO)
// Log messages
logger.info('Application started')
logger.warn('Low disk space')
logger.error('Database connection failed')PostgreSQL adapter with full SQL support
import { PostgresAdapter } from '@quatrain/backend-postgres'
const adapter = new PostgresAdapter({
config: {
host: 'localhost',
port: 5432,
database: 'myapp',
user: 'postgres',
password: 'password',
},
})
// Setup database schema (see DATABASE_SETUP.md)
// Supports complex queries, transactions, and PostgreSQL-specific featuresGoogle Firestore NoSQL adapter
import { FirestoreAdapter } from '@quatrain/backend-firestore'
const adapter = new FirestoreAdapter({
config: {
projectId: 'my-firebase-project',
keyFilename: './service-account-key.json',
},
})
// Automatic subcollection handling and Firestore-optimized queriesSQLite adapter for local development and testing
import { SQLiteAdapter } from '@quatrain/backend-sqlite'
const adapter = new SQLiteAdapter({
config: {
filename: './data.sqlite',
},
})
// Perfect for development, testing, and small applicationsFirebase Authentication - Google's managed auth service
import { FirebaseAuthAdapter } from '@quatrain/auth-firebase'
const authAdapter = new FirebaseAuthAdapter({
config: {
apiKey: 'your-api-key',
authDomain: 'project.firebaseapp.com',
},
})
// Supports email/password, social logins, custom tokensSupabase Authentication - open-source Firebase alternative with deployment flexibility
import { SupabaseAuthAdapter } from '@quatrain/auth-supabase'
// Works with Supabase SaaS
const authAdapter = new SupabaseAuthAdapter({
config: {
url: 'https://project.supabase.co',
anonKey: 'your-anon-key',
},
})
// Or self-hosted Supabase (Docker/Kubernetes)
const selfHostedAuth = new SupabaseAuthAdapter({
config: {
url: 'https://your-domain.com', // Your self-hosted instance
anonKey: 'your-anon-key',
},
})
// Row-level security and Postgres-backed authentication
// Works identically whether SaaS or self-hostedAWS S3 and S3-compatible storage
import { S3StorageAdapter } from '@quatrain/storage-s3'
const storageAdapter = new S3StorageAdapter({
config: {
accessKeyId: 'your-key',
secretAccessKey: 'your-secret',
region: 'us-east-1',
},
})
// Works with AWS S3, MinIO, DigitalOcean Spaces, etc.Firebase Cloud Storage - Google's managed file storage
import { FirebaseStorageAdapter } from '@quatrain/storage-firebase'
const storageAdapter = new FirebaseStorageAdapter({
config: {
/* Firebase config */
},
})
// Integrated with Firebase security rules and authentication
// Automatic CDN distribution and image transformationsSupabase Storage - S3-compatible with deployment flexibility
import { SupabaseStorageAdapter } from '@quatrain/storage-supabase'
// Works with Supabase SaaS or self-hosted
const storageAdapter = new SupabaseStorageAdapter({
config: {
url: 'https://project.supabase.co', // or your self-hosted URL
anonKey: 'your-anon-key',
},
})
// Row-level security policies for files
// Compatible with any S3-compatible backend when self-hostedRabbitMQ and AMQP-compatible message brokers
import { AmqpQueueAdapter } from '@quatrain/queue-amqp'
const queueAdapter = new AmqpQueueAdapter({
connectionString: 'amqp://user:pass@localhost:5672',
})AWS SQS message queuing
import { SqsAdapter } from '@quatrain/queue-aws'
const queueAdapter = new SqsAdapter({
region: 'us-east-1',
credentials: {
/* AWS credentials */
},
})Quatrain Core embraces the BaaS philosophy to accelerate development:
- π Rapid Development: Skip infrastructure setup, focus on business logic
- π Built-in Security: Authentication, authorization, and data validation out-of-the-box
- π Real-time Features: Live data synchronization without complex WebSocket setup
- π± Multi-platform: Same backend for web, mobile, and desktop applications
- π Global Scale: CDN, edge functions, and global data distribution included
- π° Cost-effective: Pay-as-you-scale pricing models
- π§ DevOps-free: No servers to maintain, automatic scaling and backups
// Same code works across all deployment models:
// 1. SaaS (Managed by Supabase)
const saasConfig = {
url: 'https://xyz.supabase.co',
anonKey: 'eyJ...',
}
// 2. Self-hosted (Docker Compose)
const dockerConfig = {
url: 'http://localhost:8000',
anonKey: 'eyJ...',
}
// 3. Kubernetes deployment
const k8sConfig = {
url: 'https://supabase.yourcompany.com',
anonKey: 'eyJ...',
}
// Same Quatrain code, different deployment targets
const adapter = new SupabaseAuthAdapter({ config: saasConfig })Here's a complete example showing how to build a simple blog application:
// 1. Install packages
// yarn add @quatrain/core @quatrain/backend @quatrain/backend-postgres
// 2. Setup
import { BaseObject, StringProperty, DateTimeProperty } from '@quatrain/core'
import { Backend, User } from '@quatrain/backend'
import { PostgresAdapter } from '@quatrain/backend-postgres'
// 3. Define models
class BlogPost extends BaseObject {
static COLLECTION = 'posts'
static PROPS_DEFINITION = [
...BaseObjectProperties, // Includes name, status, audit fields
{
name: 'title',
type: StringProperty.TYPE,
mandatory: true,
maxLength: 200,
},
{
name: 'content',
type: StringProperty.TYPE,
mandatory: true,
},
{
name: 'author',
type: ObjectProperty.TYPE,
instanceOf: 'User',
mandatory: true,
},
{
name: 'publishedAt',
type: DateTimeProperty.TYPE,
},
]
}
// 4. Setup backend
const backend = new PostgresAdapter({
config: {
host: 'localhost',
database: 'blog',
user: 'postgres',
password: 'password',
},
})
Backend.addAdapter(backend, 'default')
// 5. Create and save a blog post
const author = await User.factory()
author._.firstname = 'Jane'
author._.lastname = 'Doe'
author._.email = 'jane@example.com'
await backend.create(author.dataObject)
const post = await BlogPost.factory()
post._.title = 'My First Post'
post._.content = 'This is the content of my first blog post...'
post._.author = author
post._.publishedAt = new Date()
await backend.create(post.dataObject)
// 6. Query posts
const posts = await backend.find(
BlogPost.factory(),
[new Filter('status', 'active', OperatorKeys.equals)],
{
limits: { batch: 10, offset: 0 },
sortings: [{ prop: 'publishedAt', order: 'DESC' }],
}
)All packages include comprehensive test suites. Use the provided test utilities:
// Testing with mock adapter
import { MockAdapter } from '@quatrain/backend'
const mockBackend = new MockAdapter()
// Mock backend stores data in memory - perfect for unit tests
// Testing with real databases
// Each adapter package includes test schemas and setup instructions- Each package includes detailed README files
- API documentation generated from TypeScript definitions
- Example implementations in
__test__directories - Database setup guides (e.g.,
DATABASE_SETUP.mdfor PostgreSQL)
The framework follows a consistent pattern across all packages:
- Abstract base classes define interfaces
- Concrete adapters implement specific providers
- Comprehensive testing with both unit and integration tests
- TypeScript-first with full type safety
- Modular design - use only what you need
AGPL v3 License - See individual package.json files for details.
Quatrain DΓ©veloppement SAS - Building robust business applications with clean architecture.