diff --git a/.github/workflows/docs-pipeline.yml b/.github/workflows/docs-pipeline.yml index 1bb60a3d..009c4deb 100644 --- a/.github/workflows/docs-pipeline.yml +++ b/.github/workflows/docs-pipeline.yml @@ -5,9 +5,19 @@ on: push: branches: - main + - develop paths: - 'docs/**' - 'scripts/build-docs.ts' + - 'okf/**' + pull_request: + branches: + - main + - develop + paths: + - 'docs/**' + - 'scripts/build-docs.ts' + - 'okf/**' schedule: - cron: '0 3 * * *' # Tous les jours à 03:00 UTC @@ -30,6 +40,7 @@ jobs: fetch-depth: 0 - name: Log in to the Container registry + if: github.event_name != 'pull_request' uses: docker/login-action@v3 # NOSONAR with: registry: ${{ env.REGISTRY }} @@ -57,8 +68,8 @@ jobs: with: context: . file: docs/ContainerFile - platforms: linux/amd64,linux/arm64 - push: true + platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }} + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha diff --git a/.gitignore b/.gitignore index 3425c1c2..223687a7 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,8 @@ packages/**/.*.txt !bin/**/*.js !**/bin/**/*.js !/*.js +!docs/*.js +!docs/pages/**/_meta.js *.tsbuildinfo # Generated App @@ -37,5 +39,8 @@ packages/**/.*.txt .turbo/ **/.turbo/ +docs/.next/ +docs/out/ +docs/.yarn/ firestore-debug.log firebase-debug.log diff --git a/.tycho/knowledge/quatrain-core/package.json b/.tycho/knowledge/quatrain-core/package.json new file mode 100644 index 00000000..0deb15ab --- /dev/null +++ b/.tycho/knowledge/quatrain-core/package.json @@ -0,0 +1,7 @@ +{ + "name": "quatrain-core", + "version": "1.0.0", + "description": "Quatrain Core architecture guidelines, OKF v0.1 knowledge base, and strongly-typed code patterns", + "targets": ["gemini", "claude", "cursor", "hermes"], + "license": "AGPL-3.0" +} diff --git a/.tycho/knowledge/quatrain-core/post-install.sh b/.tycho/knowledge/quatrain-core/post-install.sh new file mode 100755 index 00000000..4603db92 --- /dev/null +++ b/.tycho/knowledge/quatrain-core/post-install.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# Quatrain Core — Tycho Knowledge Package Post-Install Hook +# Integrates Quatrain Core OKF v0.1 knowledge base into AI agent configurations +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +OKF_SOURCE="$REPO_ROOT/okf" + +echo "🧠 [Quatrain Core] Tycho Knowledge Package Post-Install" +echo " Source OKF: $OKF_SOURCE" + +if [[ ! -d "$OKF_SOURCE" ]]; then + echo "❌ Error: OKF directory not found at $OKF_SOURCE" + exit 1 +fi + +LINKED=0 + +# 1. Integrate into ~/.tycho/knowledge/agents-okf if installed +TYCHO_AGENTS_OKF="$HOME/.tycho/knowledge/agents-okf" +if [[ -d "$TYCHO_AGENTS_OKF/content" ]]; then + TARGET="$TYCHO_AGENTS_OKF/content/quatrain-core" + rm -rf "$TARGET" + ln -s "$OKF_SOURCE" "$TARGET" + echo "✅ Linked into Tycho AGENTS.okf: $TARGET" + LINKED=1 + + if command -v bun &>/dev/null && [[ -f "$TYCHO_AGENTS_OKF/package.json" ]]; then + echo "🔨 Refreshing AGENTS.okf routers..." + (cd "$TYCHO_AGENTS_OKF" && bun run build && bun run sync:local 2>/dev/null || true) + fi +fi + +# 2. Check for local AGENTS.okf repository in standard workspace locations +LOCAL_CANDIDATES=( + "$HOME/CODE/CRAPOUGNAX/AGENTS.okf" + "$HOME/CODE/AGENTS.okf" + "$HOME/projects/AGENTS.okf" +) + +for candidate in "${LOCAL_CANDIDATES[@]}"; do + if [[ -d "$candidate/content" ]]; then + TARGET="$candidate/content/quatrain-core" + if [[ ! -e "$TARGET" ]]; then + ln -s "$OKF_SOURCE" "$TARGET" + echo "✅ Linked into local AGENTS.okf repo: $TARGET" + LINKED=1 + + if command -v bun &>/dev/null && [[ -f "$candidate/package.json" ]]; then + echo "🔨 Refreshing local AGENTS.okf routers..." + (cd "$candidate" && bun run build && bun run sync:local 2>/dev/null || true) + fi + else + echo "ℹ️ Target already exists: $TARGET" + LINKED=1 + fi + fi +done + +if [[ $LINKED -eq 0 ]]; then + echo "ℹ️ No automatic AGENTS.okf directory detected." + echo " You can manually link $OKF_SOURCE to your agent knowledge base:" + echo " ln -s $OKF_SOURCE /path/to/AGENTS.okf/content/quatrain-core" +fi + +echo "" +echo "🎉 Quatrain Core OKF knowledge package configured successfully!" diff --git a/.tycho/repository.json b/.tycho/repository.json new file mode 100644 index 00000000..98f1efee --- /dev/null +++ b/.tycho/repository.json @@ -0,0 +1,6 @@ +{ + "name": "quatrain-core", + "description": "Quatrain Core architecture guidelines, domain modeling standards, and OKF knowledge base", + "author": "Quatrain", + "version": "1.0.0" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..642c0329 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,95 @@ +# LLM Agent Instructions & Guidelines — Quatrain Core + +> **Audience**: AI Coding Agents & Human Pair Programming +> **Platform**: Monorepo TypeScript (Yarn 4 / Node 22) + Hexagonal Architecture + OKF v0.1 + Tycho +> **Upstream Canonical Repository (SOA)**: `https://github.com/Quatrain/Core` +> **License**: AGPL-v3 + +--- + +## 🧭 1. Base Guidelines & Primary Hierarchy + +All AI coding agents interacting with this workspace **MUST** strictly adhere to the author's primary development rules, GitFlow protocol, and 3-tier forking architecture defined in: +👉 **[AGENTS.okf Knowledge Base](https://github.com/crapougnax/AGENTS.okf)** — Start at [`content/index.md`](file:///Users/crapougnax/CODE/CRAPOUGNAX/AGENTS.okf/content/index.md) +👉 **[Online Gist Reference](https://gist.github.com/crapougnax/47971b85aa73dd702f4372a89858111c)** (compiled router) + +### Progressive Disclosure & Local OKF Repository +Quatrain Core embeds an authoritative architectural knowledge base adhering strictly to **OKF v0.1** under [`okf/`](okf/index.md). +Before writing code or refactoring packages, agents **MUST** consult the matching concept fiche: + +| Domain | Scope | Concept Fiches | +| :--- | :--- | :--- | +| **Domain Modeling** | Schemas, properties, FSM | [`okf/domain-modeling/`](okf/domain-modeling/index.md) (`core-base-object-and-properties.md`, `state-machines-and-workflows.md`) | +| **Persistence** | Repositories, SQL/NoSQL | [`okf/persistence-adapters/`](okf/persistence-adapters/index.md) (`quatrain-repository-pattern.md`, `database-adapters-setup.md`, `schema-and-data-migrations.md`) | +| **Auth & Security** | Providers, SSO, RBAC | [`okf/auth-and-security/`](okf/auth-and-security/index.md) (`auth-providers-and-sso.md`, `rbac-and-field-level-security.md`) | +| **Object Storage** | S3, MinIO, Local FS | [`okf/storage-and-assets/`](okf/storage-and-assets/index.md) (`unified-object-storage.md`) | +| **Queues & Events** | RabbitMQ, workers | [`okf/queues-and-events/`](okf/queues-and-events/index.md) (`asynchronous-event-streaming.md`) | +| **APIs & Gateways** | Fetch client, CrudEndpoint | [`okf/api-and-gateways/`](okf/api-and-gateways/index.md) (`isomorphic-api-client.md`, `api-server-and-endpoints.md`) | +| **AI & LLM** | Gemini models, JSON schemas | [`okf/ai-and-agents/`](okf/ai-and-agents/index.md) (`ai-gemini-and-skills.md`) | + +--- + +## 🏗️ 2. Project-Specific Architecture & Guidelines + +### A. Hexagonal Architecture & 7 Architectural Layers +Quatrain decouples business domain modeling from infrastructure across 71 packages: +1. **Domain & Entities (`@quatrain/core`)**: Pure domain models extending `BaseObject`. Zero external runtime dependencies. +2. **Databases & Persistence (`@quatrain/backend`)**: Persistent entities extending `PersistedBaseObject`, dynamic `Model.repository()`, and adapter registration via `Backend.addBackend(adapter, alias, setDefault)`. +3. **Authentication & RBAC (`@quatrain/auth`, `@quatrain/auth-rbac`)**: Identity abstraction (`Auth.addProvider()`) and granular Field-Level Security (`RbacPolicyEngine`, `sanitizeWrite`, `ExpressRbacMiddleware.handler()`). +4. **Object Storage (`@quatrain/storage`)**: Abstract object storage (`Storage.addStorage()`, `adapter.create(fileType, stream)`). +5. **Queues & Messaging (`@quatrain/queue`)**: Asynchronous worker queues (`Queue.addQueue()`, `adapter.send()`, `adapter.listen(topic, handler, { concurrency })`). +6. **APIs & Gateways (`@quatrain/api`, `@quatrain/api-client`, `@quatrain/api-server`)**: Isomorphic fetch client and higher-order controllers (`server.addEndpoint(CrudEndpoint(Model), path, options)`). +7. **AI & Cognitive (`@quatrain/ai`, `@quatrain/ai-gemini`)**: Official Google GenAI integration with schema-guaranteed JSON generation (`generateStructured`). + +### B. Strict TypeScript & Code Quality Rules +- **No `as any` Type Bypasses**: Never use `as any`, `@ts-ignore`, or `@ts-nocheck` to silence TypeScript compiler errors. Always construct fully compliant, strongly-typed objects that satisfy interfaces. +- **Strongly-Typed Property Definitions**: Always use `.TYPE` constants (`StringProperty.TYPE`, `BooleanProperty.TYPE`, `NumberProperty.TYPE`) in `PROPS_DEFINITION`. Never use raw string literals (`'string'`, `'BooleanProperty'`). +- **Global Reflection Registration**: Always register model classes via `Core.addClass('ModelName', ModelName)` at the bottom of the file to resolve circular references. +- **Relational Property Naming**: Properties referencing other models must use **camelCase** matching the target class name, without `Id` or `_id` suffix (e.g. `user`, `studioModel`). + +### C. Developer & Contributor Guide Paths +- **Building applications using Quatrain**: Follow [`okf/`](okf/index.md) and [`guidelines/AGENTS.md`](guidelines/AGENTS.md). +- **Contributing to the Quatrain Core monorepo**: Follow [`guidelines/CONTRIBUTING_AGENTS.md`](guidelines/CONTRIBUTING_AGENTS.md). + +--- + +## 🛠️ 3. Essential Verification Commands + +| Action | Command | +| :--- | :--- | +| **Run Unit Tests (all workspaces)** | `yarn test` | +| **Run Specific Workspace Test** | `yarn --cwd packages/ test` | +| **Build Documentation & TypeDoc** | `yarn docs:build` | +| **Start Nextra Documentation Server** | `yarn docs:dev` (accessible on `http://localhost:3000`) | +| **Typecheck Documentation Script** | `yarn ts-node scripts/build-docs.ts` | + +--- + +## 🔄 4. GitFlow Protocol & Contributions + +- **Active Integration Branch**: `develop`. All work branches off from `develop`. +- **Branch Naming**: `feat/-` or `fix/-` strictly from `develop`. +- **Conventional Commits**: Format `(): ` in International English (e.g. `feat(backend): add connection pool timeout`). +- **Pull Requests**: Target `--base develop` via `gh pr create`. Always link relevant issues. + +--- + +## ⚡ 5. Tycho Package Orchestration (`tycho knowledge`) + +Quatrain Core is packaged natively as a **Tycho Knowledge Package**: +- **Repository Manifest**: [`.tycho/repository.json`](.tycho/repository.json) +- **Knowledge Specification**: [`.tycho/knowledge/quatrain-core/package.json`](.tycho/knowledge/quatrain-core/package.json) +- **Post-Install Automation**: [`.tycho/knowledge/quatrain-core/post-install.sh`](.tycho/knowledge/quatrain-core/post-install.sh) + +To annex this knowledge base into your local agent configuration (`AGENTS.okf`): +```bash +# 1. Register repository in Tycho +tycho repo add quatrain Quatrain/Core + +# 2. Install knowledge package +tycho knowledge install quatrain/quatrain-core + +# 3. Verify active packages +tycho knowledge list +``` +The post-install script automatically links `okf/` into your active knowledge router and rebuilds agent configurations. diff --git a/GEMINI.md b/GEMINI.md deleted file mode 100644 index 53f5147e..00000000 --- a/GEMINI.md +++ /dev/null @@ -1,42 +0,0 @@ -# Quatrain Core - Gemini Agent Guidelines & Instruction Pointer - -> [!NOTE] -> **Updated:** May 23, 2026 | **Engine:** Gemini 3.5 Flash (High) | **License:** AGPL-v3 - -This document serves as the dedicated instruction and guidelines pointer specifically tailored for the Gemini AI Coding Agent. - -When executing tasks or responding to requests in this repository, you MUST load and comply with the following instructions: - ---- - -## 🧭 Guidelines & Instruction Paths - -### 1. Building Applications with Quatrain -If the task is to construct or design application schemas, models, repositories, and business features **using** the Quatrain ecosystem, follow the guidelines in: -👉 [AGENTS.md (Application Development Guidelines)](./guidelines/AGENTS.md) - -### 2. Modifying Quatrain Core Codebase -If the task requires editing, refactoring, fixing, or extending the packages, monorepo workspaces, containers, or CI/CD pipelines of the **Quatrain Core repository itself**, follow the strict guidelines in: -👉 [CONTRIBUTING_AGENTS.md (Monorepo Contributing Guidelines)](./guidelines/CONTRIBUTING_AGENTS.md) - -### 3. GitFlow Lifecycle & Pull Requests -All contributions follow the GitFlow lifecycle defined in [AGENTS.okf](file:///Users/crapougnax/CODE/CRAPOUGNAX/AGENTS.okf/content/workflow/gitflow-protocol.md): -- Active integration branch: `develop` -- Branching: `feat/-` or `fix/-` strictly from `develop` -- Pull Requests: Target `--base develop` via `gh pr create` - ---- - -## 👤 Personal Rules & Custom Settings - -In addition to the framework-level guidelines, you MUST adhere to the user's personal coding preferences, custom shortcuts, and general development rules published in: -👉 [AGENTS.okf Knowledge Base](file:///Users/crapougnax/CODE/CRAPOUGNAX/AGENTS.okf/content/index.md) | [GitHub Repository](https://github.com/crapougnax/AGENTS.okf) -👉 [Gist: Personal Gemini Rules & Instructions](https://gist.github.com/crapougnax/47971b85aa73dd702f4372a89858111c) - - ---- - -## 🛑 Strict TypeScript & Code Quality Rules - -- **No `as any` Type Bypasses**: Never use `as any`, `@ts-ignore`, `@ts-nocheck`, or type assertion shortcuts to silence TypeScript errors. Always construct fully compliant, strongly-typed objects that satisfy the target interfaces and schemas. - diff --git a/README.md b/README.md index 5663f286..2f0ad5a4 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,240 @@
- Core Logo + Quatrain Core Logo +

Quatrain Core

+

A Modular, Sovereign & Universal TypeScript Backend Framework

+

"Business Logic outlives Infrastructure"

+ + [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Quatrain_Core&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Quatrain_Core) + [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Quatrain_Core&metric=coverage)](https://sonarcloud.io/summary/new_code?id=Quatrain_Core) + [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=Quatrain_Core&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=Quatrain_Core) + [![License](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](LICENSE.md) + [![Monorepo Packages](https://img.shields.io/badge/packages-71%20active-success.svg)](#-ecosystem--packages-map)
-# Core - A Modular & Universal Backend Framework +--- + +## 🌟 At a Glance -> **"Business Logic outlives Infrastructure"** +**Quatrain Core** is an enterprise-grade, modular TypeScript framework designed to build resilient, cloud-agnostic applications. Built around the **Hexagonal / Adapter Pattern**, it completely decouples domain modeling and business rules from the underlying infrastructure. -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Quatrain_Core&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Quatrain_Core) -[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Quatrain_Core&metric=coverage)](https://sonarcloud.io/summary/new_code?id=Quatrain_Core) -[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=Quatrain_Core&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=Quatrain_Core) +Write your domain logic once, then seamlessly swap or mix: +* **Databases**: PostgreSQL, SQLite, Firestore, or REST backends. +* **Authentication**: Supabase Auth, Firebase Auth, OIDC / OAuth2, PocketBase, or HTTP Basic. +* **Storage**: AWS S3, MinIO, Local Filesystem, Google Cloud Storage, or Git. +* **Queuing & Messaging**: RabbitMQ (AMQP), MQTT, SQLite queues, AWS SQS, or GCP Pub/Sub. -Core (a product of Quatrain) is a modular TypeScript framework designed to accelerate business application development. Built upon a powerful **Adapter Pattern**, it decouples your core business logic from the underlying infrastructure, allowing you to deploy **100% on-premise** with standard open-source blocks, leverage modern **Backend as a Service (BaaS)** platforms (like Supabase and Firebase), or run a **hybrid** architecture. +Target **100% on-premise sovereign setups** or modern **Backend-as-a-Service (BaaS) cloud platforms** with the exact same codebase. + +--- + +## 📚 Table of Contents + +- [Core Principles](#-core-principles) +- [Quick Start](#-quick-start) +- [Ecosystem & Packages Map](#-ecosystem--packages-map) +- [Documentation & API Reference](#-documentation--api-reference) +- [Open Knowledge Base (OKF) & Tycho](#-open-knowledge-base-okf-v01--tycho-integration) +- [Companion Projects](#-companion-projects) +- [Monorepo Development](#-monorepo-development) +- [License & Support](#-license--support) --- ## 🎯 Core Principles -- **BaaS & On-Premise Synergy**: Build modern cloud-native apps leveraging managed services like Firebase/Supabase, or target strict data-sovereign environments using traditional self-hosted infrastructure (PostgreSQL, SQLite, S3, OIDC/OAuth, RabbitMQ). The exact same codebase runs in both worlds. -- **Clean Abstraction**: Write your business logic once. Decouple your models and processes from transport layers, databases, file storages, or messaging brokers. -- **No Vendor Lock-In**: Seamlessly swap database engines (SQLite, PostgreSQL, Firestore), auth providers (Supabase Auth, Firebase Auth, OIDC/OAuth, Basic Auth), object storage backends (Local FileSystem, AWS S3, MinIO), or message queues (AMQP/RabbitMQ, AWS SQS, GCP Pub/Sub) via simple configuration changes. -- **Modular by Design**: The framework is split into clean, highly factorized packages. Use only the bricks you need, from core object validation to authentication, storage, and pub/sub queues. -- **Standalone Core**: The `@quatrain/core` package works entirely in-memory for defining models, validation, and business logic, without requiring any database or network connection. +1. **Clean Hexagonal Abstraction**: Entities, validation rules, and business logic live in `@quatrain/core` with zero external dependencies. They remain fully testable in-memory. +2. **True Sovereignty & Zero Vendor Lock-In**: Avoid proprietary traps. You can run your stack on self-hosted bare metal (PostgreSQL + RabbitMQ + S3-compatible storage) or managed cloud platforms with a single configuration line. +3. **Zero-Boilerplate Active Record & Repositories**: Every entity provides dynamic, strongly-typed repositories with built-in schema validation, serialization, relationships, and aggregations (`sum`, `count`, `avg`, `min`, `max`). +4. **Fine-Grained Modularity**: A factorized monorepo of **71 independent packages**. Import only what your service needs to keep production bundles light. --- -## 🧠 Philosophy +## 🚀 Quick Start -Core is built upon three foundational pillars to ensure enterprise-grade reliability and longevity: +### 1. Install Dependencies -- **Sovereignty by Design**: Deploy anywhere, from your local laptop to the largest hyperscalers (AWS, GCP, Azure). Core's adapter pattern prevents vendor lock-in, ensuring you retain total control over your data and infrastructure choices. -- **Cybersecurity by Design**: We rely on rock-solid, audited, and widely adopted components. By keeping the core architecture simple and maintainable, we reduce the attack surface and make security patching straightforward. -- **Cloud-Native Best Practices**: Designed to build robust applications that withstand the test of time. Core embraces stateless execution, ephemeral environments, and seamless horizontal scaling to effortlessly adapt to technological innovations. +Install the core modeling engine and the backend adapter of your choice: ---- +```bash +# Using Yarn +yarn add @quatrain/core @quatrain/backend @quatrain/backend-postgres + +# Using npm +npm install @quatrain/core @quatrain/backend @quatrain/backend-postgres +``` + +### 2. Define a Domain Model -## 📐 1. Design +Define entity attributes, types, and validation rules declaratively: -The Design phase is all about modeling your domain and laying the foundations of your application without worrying about the underlying database or UI framework logic. +```typescript +import { PersistedBaseObject } from '@quatrain/backend' +import { StringProperty, NumberProperty, BooleanProperty } from '@quatrain/core' -### Core Ecosystem -- **`@quatrain/core`**: Foundation package. Works standalone in-memory. Defines models, properties, validation, and serialization. -- **`@quatrain/types`**: Shared contracts, types, interfaces, and exceptions for Core. -- **`@quatrain/studio`**: Visual interface and meta-modeling package used by the visual studio application. -- **`@quatrain/ux`**: Core styling and component logic (Mantine-based) for consistent frontend experiences. +export class Product extends PersistedBaseObject { + static COLLECTION = 'products' -> [!TIP] -> For complete documentation, modeling details, and quick-start tutorials on these packages, please refer to the **[Core Wiki](https://github.com/Quatrain/Core/wiki)**. + static PROPS_DEFINITION = [ + { name: 'name', type: StringProperty.TYPE, required: true }, + { name: 'sku', type: StringProperty.TYPE, required: true }, + { name: 'price', type: NumberProperty.TYPE, required: true }, + { name: 'inStock', type: BooleanProperty.TYPE, default: true } + ] +} +``` + +### 3. Connect Adapter & Persist Data + +Configure the backend adapter and perform operations through pre-bound repositories: + +```typescript +import { Backend } from '@quatrain/backend' +import { PostgresAdapter } from '@quatrain/backend-postgres' +import { Product } from './models/Product' + +async function bootstrap() { + // 1. Initialize and register the backend adapter + const postgres = new PostgresAdapter({ + config: { + host: process.env.PG_HOST || 'localhost', + port: 5432, + database: 'quatrain_db', + user: 'postgres', + password: process.env.PG_PASSWORD || 'secret' + } + }) + Backend.addBackend(postgres, 'postgres', true) + + // 2. Instantiate and persist through dynamic repository + const repo = Product.repository() + const item = await Product.factory({ + name: 'prod_900', + sku: 'SKU-QUATRAIN-01', + price: 49.99, + inStock: true + }) + await repo.create(item) + + // 3. Read by UID + const loaded = await repo.read('prod_900') + console.log(`Product loaded: ${loaded?.val('sku')}`) +} + +bootstrap() +``` --- -## 🛠️ 2. Development +## 📦 Ecosystem & Packages Map -During Development, you connect your business logic to services such as databases, authentication, AI, and message queues, using interchangeable adapters. +The framework is organized into 7 logical architectural layers across 71 packages: -### Backend & Service Ecosystem -- **Database Adapters**: `@quatrain/backend`, `@quatrain/backend-firestore`, `@quatrain/backend-postgres`, `@quatrain/backend-sqlite` -- **Authentication**: `@quatrain/auth`, `@quatrain/auth-firebase`, `@quatrain/auth-supabase`, `@quatrain/auth-oidc`, `@quatrain/auth-pocketbase` -- **Storage**: `@quatrain/storage`, `@quatrain/storage-firebase`, `@quatrain/storage-supabase`, `@quatrain/storage-local`, `@quatrain/storage-s3` -- **Queueing & Messaging**: `@quatrain/queue`, `@quatrain/queue-amqp`, `@quatrain/queue-aws`, `@quatrain/queue-gcp`, `@quatrain/messaging`, `@quatrain/messaging-firebase` -- **AI & Automation**: `@quatrain/ai`, `@quatrain/ai-gemini`, `@quatrain/app`, `@quatrain/code`, `@quatrain/code-github` -- **Testing**: `@quatrain/testing` +| Layer | Core Package | Ecosystem Adapters & Modules | +| :--- | :--- | :--- | +| **Domain & Entities** | [`@quatrain/core`](packages/core) | [`@quatrain/types`](packages/types) · [`@quatrain/state-machine`](packages/state-machine) · [`@quatrain/okf`](packages/okf) | +| **Databases & Persistence** | [`@quatrain/backend`](packages/backend) | [`backend-postgres`](packages/backend-postgres) · [`backend-sqlite`](packages/backend-sqlite) · [`backend-firestore`](packages/backend-firestore) · [`backend-restapi`](packages/backend-restapi) · [`backend-migrations`](packages/backend-migrations) | +| **Authentication & RBAC** | [`@quatrain/auth`](packages/auth) | [`auth-rbac`](packages/auth-rbac) · [`auth-supabase`](packages/auth-supabase) · [`auth-firebase`](packages/auth-firebase) · [`auth-oidc`](packages/auth-oidc) · [`auth-pocketbase`](packages/auth-pocketbase) · [`auth-http-basic`](packages/auth-http-basic) | +| **Object Storage** | [`@quatrain/storage`](packages/storage) | [`storage-s3`](packages/storage-s3) · [`storage-local`](packages/storage-local) · [`storage-supabase`](packages/storage-supabase) · [`storage-firebase`](packages/storage-firebase) · [`storage-git`](packages/storage-git) | +| **Queues & Messaging** | [`@quatrain/queue`](packages/queue) | [`queue-amqp`](packages/queue-amqp) · [`queue-mqtt`](packages/queue-mqtt) · [`queue-sqlite`](packages/queue-sqlite) · [`queue-aws`](packages/queue-aws) · [`queue-gcp`](packages/queue-gcp) · [`messaging`](packages/messaging) | +| **APIs & Gateways** | [`@quatrain/api`](packages/api) | [`api-client`](packages/api-client) · [`api-server`](packages/api-server) · [`api-server-express`](packages/api-server-express) · [`api-server-astro`](packages/api-server-astro) · [`api-xmlrpc`](packages/api-xmlrpc) | +| **AI, Chat & Cognitive** | [`@quatrain/ai`](packages/ai) | [`ai-gemini`](packages/ai-gemini) · [`chat`](packages/chat) · [`skills`](packages/skills) | +| **Platform & Tooling** | [`@quatrain/cli`](packages/cli) | [`cache`](packages/cache) · [`cache-redis`](packages/cache-redis) · [`log`](packages/log) · [`i18n`](packages/i18n) · [`mdm`](packages/mdm) · [`testing`](packages/testing) | -> [!TIP] -> For full code persistence examples, dependency injection setups, and service integrations, visit the **[Core Wiki](https://github.com/Quatrain/Core/wiki)**. +👉 **[Explore Full Interactive Packages Catalog](https://apps.quatrain.dev/packages)** --- -## 🚀 3. Deployment +## 📖 Documentation & API Reference -Deployment covers running your code, scaffolding new environments, configuring API gateways, and handling data migrations. +* 🌐 **Documentation Portal**: Complete guides, HOWTOs, and architecture standards: [apps.quatrain.dev](https://apps.quatrain.dev) +* 📦 **Full API Reference**: Automatically extracted TypeScript documentation (classes, interfaces, signatures): [apps.quatrain.dev/api-reference/modules.html](https://apps.quatrain.dev/api-reference/modules.html) +* 📑 **Package Guides**: Each package maintains an `Overview` (`README.md`) and practical recipes (`HOWTO.md`) inside its folder. -### Deployment & Infrastructure Ecosystem -- **CLI & Code Generation**: `@quatrain/cli` (Scaffolds projects, configurations, and migrations) -- **Migrations**: `@quatrain/backend-migrations` (Schema and data migration tooling) -- **Cloud Wrappers**: `@quatrain/cloudwrapper`, `@quatrain/cloudwrapper-firebase`, `@quatrain/cloudwrapper-supabase` (Serverless/Edge functions handling) +--- -### Ready-To-Use Applications & Containers +## 🧠 Open Knowledge Base (OKF v0.1) & Tycho Integration -All deployable applications, live modeling portals, gateway proxies, and pre-built deployment setups are organized in the dedicated companion repository: +Quatrain Core embeds an official knowledge base formatted according to the **Open Knowledge Format (OKF v0.1)** directly under [`okf/`](okf/index.md). -👉 **[CoreApps Repository](https://github.com/Quatrain/CoreApps)** +Designed specifically for **AI pair-programming agents** (Gemini, Claude, Antigravity, Cursor) and human engineers, it provides authoritative, hallucination-free guidance across 8 core architectural pillars: +* 🏛️ **Domain Modeling**: [`okf/domain-modeling/`](okf/domain-modeling/index.md) (Schemas, `.TYPE`, `._` proxy, FSM workflows) +* 💾 **Persistence**: [`okf/persistence-adapters/`](okf/persistence-adapters/index.md) (Repositories, PostgreSQL, SQLite, Migrations) +* 🔐 **Auth & Security**: [`okf/auth-and-security/`](okf/auth-and-security/index.md) (SSO, Supabase, RBAC, Field-Level Security) +* 🗄️ **Object Storage**: [`okf/storage-and-assets/`](okf/storage-and-assets/index.md) (Unified S3/MinIO & Local FS storage) +* 📬 **Queues & Streaming**: [`okf/queues-and-events/`](okf/queues-and-events/index.md) (RabbitMQ/AMQP, background workers) +* 🌐 **API Gateways**: [`okf/api-and-gateways/`](okf/api-and-gateways/index.md) (Isomorphic fetch client, CrudEndpoint) +* 🤖 **AI Agents**: [`okf/ai-and-agents/`](okf/ai-and-agents/index.md) (Gemini models, schema-guaranteed JSON generation) -Here you will find ready-to-use Docker/Podman container images and configurations: -- **`api-gateway`**: Ultra-lightweight Express-based reverse proxy routing requests to your upstream services. -- **`studio-image`**: Pre-configured environment hosting the Visual Developer Studio Dashboard. +### Annexing via Tycho CLI (`tycho knowledge`) + +You can directly annex this knowledge base into your personal or team agent configuration (such as `AGENTS.okf`) using **Tycho**: + +```bash +# 1. Register the Quatrain Core repository in Tycho +tycho repo add quatrain Quatrain/Core + +# 2. Install the knowledge package +tycho knowledge install quatrain/quatrain-core + +# 3. Check active knowledge packages +tycho knowledge list +``` + +The automated post-install hook (`.tycho/knowledge/quatrain-core/post-install.sh`) links the `okf/` directory into your active agent knowledge router and triggers an immediate router build (`bun run build && bun run sync:local`). + +--- + +## 🧰 Companion Projects + +* **[Quatrain CoreApps](https://github.com/Quatrain/CoreApps)**: Pre-packaged Docker / Podman containers, including: + * `api-gateway`: High-performance reverse proxy and routing gateway. + * `studio-image`: Web modeling studio for entity scaffolding. +* **[Quatrain CoreUX](https://github.com/Quatrain/CoreUX)**: Mantine-based UI design tokens, components, high-contrast mobile interfaces, and voice adapters. --- -## 🔮 Upcoming +## 💻 Monorepo Development + +### Prerequisites +* **Node.js**: `>= 22.0.0` +* **Package Manager**: Yarn v4 (`corepack enable`) + +### Setup & Verification Commands + +```bash +# 1. Install all monorepo dependencies +yarn install -The Core ecosystem is constantly evolving to empower developers and business users alike. Our roadmap includes: +# 2. Build all workspaces via Turborepo +yarn build -- **Studio**: A complete, visual interface to design and manage your entire application ecosystem. This studio will be driven by the user and seamlessly assisted by a Large Language Model (LLM) to accelerate scaffolding, modeling, and repetitive tasks. -- **BPM & State Machines**: A powerful Business Process Management (BPM) engine allowing you to manage complex business logic and entity lifecycles through robust, visual "State Machines". +# 3. Run full test suite across packages +yarn test + +# 4. Generate documentation & TypeDoc API reference +yarn ts-node scripts/build-docs.ts + +# 5. Start documentation development server +yarn --cwd docs dev +``` + +### Contribution & GitFlow Protocol +* Active integration branch: `develop` +* Topic branches: `feat/-` or `fix/-` branched strictly from `develop`. +* Commit standard: [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`). +* Pull Requests must target `--base develop`. --- ## ⚖️ License & Professional Services -Core is released under the **AGPL-3.0** (Affero General Public License). This ensures that any enhancements to the open-source core remain free and accessible to the community. If you build a SaaS or application using this framework, you must comply with the AGPL-3.0 terms. +Quatrain Core is licensed under the **AGPL-3.0** (Affero General Public License). Any enhancements to the open-source core remain free and accessible to the community. + +### Enterprise Services & Commercial Licensing +If your organization requires a commercial license (to embed Core into closed-source commercial offerings), or if you need enterprise consulting: -**Professional Services & Commercial Licensing** -If your organization requires a commercial license (to integrate Core without the AGPL-3.0 restrictions), or if you need expert assistance, the **Quatrain** team offers: -- **Commercial Licensing**: Tailored licenses for proprietary software and enterprise deployments. -- **Custom Development**: Expert engineers to help you build or migrate your backend architecture. -- **Premium Support**: Priority SLA, architectural consulting, and code reviews. +* 💼 **Commercial Licensing**: Custom terms without AGPL copyleft obligations. +* 🛠️ **Architecture Consulting & Migration**: Expert engineering assistance to scaffold and deploy sovereign backends. +* ⚡ **Enterprise Support**: Dedicated SLA, priority issue triage, and security reviews. -Contact us at **developers@quatrain.com** to discuss your project needs. +📧 Contact the Quatrain team at **[developers@quatrain.com](mailto:developers@quatrain.com)**. diff --git a/docs/ContainerFile b/docs/ContainerFile index fb4bd367..11709ff5 100644 --- a/docs/ContainerFile +++ b/docs/ContainerFile @@ -1,5 +1,5 @@ # Stage 1: Builder -FROM node:22-alpine AS builder +FROM --platform=$BUILDPLATFORM node:22-alpine AS builder WORKDIR /app RUN corepack enable @@ -36,7 +36,7 @@ RUN yarn exec next build --debug # Stage 2: Runner FROM nginx:alpine AS runner RUN rm -rf /usr/share/nginx/html/* -COPY --from=builder /app/docs/out /usr/share/nginx/html +COPY --from=builder /app/docs/out /usr/share/nginx/html/core COPY docs/nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] diff --git a/docs/components/CoreFeatureCard.jsx b/docs/components/CoreFeatureCard.jsx new file mode 100644 index 00000000..babc435e --- /dev/null +++ b/docs/components/CoreFeatureCard.jsx @@ -0,0 +1,74 @@ +import React from 'react' +import Link from 'next/link' +import { CoreStatusBadge } from './CoreStatusBadge' + +/** + * CoreFeatureCard + * Follows CoreUX principles: + * - Dual-Typeface (Space Grotesk title + Inter description). + * - Static CSS Hygiene (100% Tailwind class bindings, zero dynamic inline styles). + * - CSS-driven hover micro-interactions via compositor thread. + * - Contrast token badges. + */ +export function CoreFeatureCard({ + title, + description, + href, + icon, + badge, + badgeLevel = 'brand', + layer, + className = '' +}) { + return ( + + {/* Subtle top accent gradient line on hover */} +
+ +
+
+
+ {icon && ( + + {icon} + + )} + {layer && ( + + {layer} + + )} +
+ {badge && ( + + {badge} + + )} +
+ +

+ {title} +

+ +

+ {description} +

+
+ +
+ Learn more + + + +
+ + ) +} diff --git a/docs/components/CoreHero.jsx b/docs/components/CoreHero.jsx new file mode 100644 index 00000000..e200602c --- /dev/null +++ b/docs/components/CoreHero.jsx @@ -0,0 +1,115 @@ +import React from 'react' +import Link from 'next/link' +import { CoreStatusBadge } from './CoreStatusBadge' + +/** + * CoreHero + * The flagship landmark component designed with CoreUX standards: + * - Geometric Space Grotesk headline. + * - Saturated brand gradients. + * - Key framework metrics. + */ +export function CoreHero() { + return ( +
+ {/* Background ambient lighting */} +
+
+ +
+
+ + Framework v1.3 Production + + + Open Knowledge Architecture (OKF v0.1) + +
+ +

+ Quatrain{' '} + + Core + +

+ +

+ A Modular, Sovereign & Universal TypeScript Backend Framework +

+ +

+ "Business Logic outlives Infrastructure" +

+ +

+ An enterprise-grade, modular TypeScript framework designed to build resilient, cloud-agnostic applications. Built around the Adapter Pattern, it completely decouples domain modeling and business rules from the underlying infrastructure. +

+ + {/* Action Buttons */} +
+ + 📖 Explore OKF Knowledge Base + + + + + + + 📦 Browse 71 Packages + + + + ⚡ API Reference ↗ + +
+ + {/* Framework Stat Metrics Bar */} +
+
+
+ 71 +
+
+ Modular Packages +
+
+
+
+ 7 +
+
+ Architectural Layers +
+
+
+
+ 100% +
+
+ Sovereign & Portable +
+
+
+
+ AGPL-3.0 +
+
+ Open Source +
+
+
+
+
+ ) +} diff --git a/docs/components/CoreStatusBadge.jsx b/docs/components/CoreStatusBadge.jsx new file mode 100644 index 00000000..c6f666d2 --- /dev/null +++ b/docs/components/CoreStatusBadge.jsx @@ -0,0 +1,44 @@ +import React from 'react' + +/** + * CoreStatusBadge + * Complies with Quatrain CoreUX Contrast & Status Tokens specification: + * - Optimal (Level 1): Vivid green (#22c55e) with white text. + * - Nominal (Level 2): Bright yellow (#facc15) with STRICT dark navy text (#0f172a). + * - Warning (Level 3): Saturated orange (#f97316) with white text. + * - Danger (Level 4): Saturated red (#ef4444) with white text. + * - Brand (Default): Sky/Cyan badge. + */ +export function CoreStatusBadge({ level = 'brand', children, className = '' }) { + let badgeStyle = 'bg-sky-500/15 text-sky-700 dark:text-sky-300 border-sky-500/30' + + switch (level) { + case 'optimal': + case 'success': + badgeStyle = 'bg-emerald-500 text-white border-emerald-600' + break + case 'nominal': + case 'yellow': + // CRITICAL CoreUX Safeguard: Never use white text on yellow! + badgeStyle = 'bg-yellow-400 text-slate-900 font-bold border-yellow-500' + break + case 'warning': + case 'orange': + badgeStyle = 'bg-orange-500 text-white border-orange-600' + break + case 'danger': + case 'critical': + badgeStyle = 'bg-rose-500 text-white border-rose-600' + break + case 'brand': + default: + badgeStyle = 'bg-sky-500/15 text-sky-700 dark:text-sky-300 border-sky-500/30' + break + } + + return ( + + {children} + + ) +} diff --git a/docs/components/index.jsx b/docs/components/index.jsx new file mode 100644 index 00000000..4e907a01 --- /dev/null +++ b/docs/components/index.jsx @@ -0,0 +1,3 @@ +export { CoreHero } from './CoreHero' +export { CoreFeatureCard } from './CoreFeatureCard' +export { CoreStatusBadge } from './CoreStatusBadge' diff --git a/docs/next.config.mjs b/docs/next.config.mjs index 652ecb3c..263dab20 100644 --- a/docs/next.config.mjs +++ b/docs/next.config.mjs @@ -5,7 +5,10 @@ const withNextra = nextra({ themeConfig: './theme.config.jsx' }) +const basePath = process.env.BASE_PATH !== undefined ? process.env.BASE_PATH : '/core' + export default withNextra({ + basePath, output: 'export', images: { unoptimized: true diff --git a/docs/nginx.conf b/docs/nginx.conf index 42742cab..85ef38cf 100644 --- a/docs/nginx.conf +++ b/docs/nginx.conf @@ -4,20 +4,76 @@ server { root /usr/share/nginx/html; index index.html; - # Handle Next.js static routing (clean URLs without .html) - location / { - try_files $uri $uri.html $uri/ /index.html; + # Relative redirects to preserve https:// behind Traefik reverse proxy + absolute_redirect off; + port_in_redirect off; + + # Redirect root / to /core/ + location = / { + return 301 /core/; + } + + # Redirect /core to /core/ + location = /core { + return 301 /core/; + } + + # Handle accidental double prefix /core/core/ + location ~ ^/core/core/(.*)$ { + return 301 /core/$1; + } + + # Redirect requests missing /core prefix + location ~ ^/(packages|okf|api-reference)(/.*)?$ { + return 301 /core$request_uri; + } + + # Case-insensitive redirects for HOWTO (e.g. /core/packages/auth-supabase/HOWTO -> /core/packages/auth-supabase/howto) + location ~ ^/core/(.*)/HOWTO/?$ { + return 301 /core/$1/howto; + } + + # Case-insensitive redirects for README (e.g. /core/packages/auth-supabase/README -> /core/packages/auth-supabase/readme) + location ~ ^/core/(.*)/README/?$ { + return 301 /core/$1/readme; + } + + # Package directory root: redirect to overview (readme) + location ~ ^/core/packages/([^/]+)/?$ { + return 301 /core/packages/$1/readme; + } + + # Strip trailing slash from subpages to prevent directory index collisions (e.g. /core/okf/domain-modeling/ -> /core/okf/domain-modeling) + location ~ ^/core/(.+)/$ { + return 301 /core/$1; + } + + # Cache static Next.js assets + location ~* ^/core/_next/static/ { + expires 1y; + add_header Cache-Control "public, max-age=31536000, immutable"; } - # Cache static assets + # Cache static media/fonts location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, max-age=31536000, immutable"; } + # Handle API reference static files directly + location /core/api-reference/ { + try_files $uri $uri/ =404; + } + + # Handle Nextra static routing under /core/ + location /core/ { + try_files $uri $uri.html $uri/index.html =404; + } + # 404 Error handling - error_page 404 /404.html; - location = /404.html { + error_page 404 /core/404.html; + location = /core/404.html { internal; } } + diff --git a/docs/pages/_meta.js b/docs/pages/_meta.js new file mode 100644 index 00000000..531aa2c4 --- /dev/null +++ b/docs/pages/_meta.js @@ -0,0 +1,10 @@ +export default { + "index": "✨ Introduction", + "okf": "🏛️ Architecture (OKF)", + "packages": "📦 Packages (71)", + "api-reference": { + "title": "⚡ API Reference ↗", + "href": "/core/api-reference/modules.html", + "newWindow": true + } +} diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx index e4bdb8a1..e3ebd592 100644 --- a/docs/pages/index.mdx +++ b/docs/pages/index.mdx @@ -1,3 +1,209 @@ -# Quatrain Core Documentation +import { CoreHero, CoreFeatureCard, CoreStatusBadge } from '../components/index.jsx' +import { Tabs } from 'nextra/components' -Welcome to the Quatrain Core documentation! This site contains all the technical guidelines, API references, and package readmes. + + +--- + +## 🌟 At a Glance + +**Quatrain Core** is an enterprise-grade, modular TypeScript framework designed to build resilient, cloud-agnostic applications. Built around the **Adapter Pattern**, it completely decouples domain modeling and business rules from the underlying infrastructure. + +Write your domain logic once, then seamlessly swap or mix: +* **Databases**: PostgreSQL, SQLite, Firestore, or REST backends. +* **Authentication**: Supabase Auth, Firebase Auth, OIDC / OAuth2, PocketBase, or HTTP Basic. +* **Storage**: AWS S3, MinIO, Local Filesystem, Google Cloud Storage, or Git. +* **Queuing & Messaging**: RabbitMQ (AMQP), MQTT, SQLite queues, AWS SQS, or GCP Pub/Sub. + +Target **100% on-premise sovereign setups** or modern **Backend-as-a-Service (BaaS) cloud platforms** with the exact same codebase. + +--- + +## 🎯 Core Principles + +
+ + + + +
+ +--- + +## 🚀 Quick Start + +### 1. Install Dependencies + +Install the core modeling engine and the backend adapter of your choice: + + + + ```bash + yarn add @quatrain/core @quatrain/backend @quatrain/backend-postgres + ``` + + + ```bash + npm install @quatrain/core @quatrain/backend @quatrain/backend-postgres + ``` + + + ```bash + bun add @quatrain/core @quatrain/backend @quatrain/backend-postgres + ``` + + + ```bash + # Annex OKF v0.1 knowledge base directly into your AI coding agent + tycho knowledge install quatrain/quatrain-core + ``` + + + +### 2. Define a Domain Model + +Define entity attributes, types, and validation rules declaratively: + +```typescript +import { PersistedBaseObject } from '@quatrain/backend' +import { StringProperty, NumberProperty, BooleanProperty } from '@quatrain/core' + +export class Product extends PersistedBaseObject { + static COLLECTION = 'products' + + static PROPS_DEFINITION = [ + { name: 'name', type: StringProperty.TYPE, required: true }, + { name: 'sku', type: StringProperty.TYPE, required: true }, + { name: 'price', type: NumberProperty.TYPE, required: true }, + { name: 'inStock', type: BooleanProperty.TYPE, default: true } + ] +} +``` + +### 3. Connect Adapter & Persist Data + +Configure the backend adapter and perform operations through pre-bound repositories: + +```typescript +import { Backend } from '@quatrain/backend' +import { PostgresAdapter } from '@quatrain/backend-postgres' +import { Product } from './models/Product' + +async function bootstrap() { + // 1. Initialize and register the backend adapter + const postgres = new PostgresAdapter({ + config: { + host: process.env.PG_HOST || 'localhost', + port: 5432, + database: 'quatrain_db', + user: 'postgres', + password: process.env.PG_PASSWORD || 'secret' + } + }) + Backend.addBackend(postgres, 'postgres', true) + + // 2. Instantiate and persist through dynamic repository + const repo = Product.repository() + const item = await Product.factory({ + name: 'prod_900', + sku: 'SKU-QUATRAIN-01', + price: 49.99, + inStock: true + }) + await repo.create(item) + + // 3. Read by UID + const loaded = await repo.read('prod_900') + console.log(`Product loaded: ${loaded?.val('sku')}`) +} + +bootstrap() +``` + +--- + +## 📦 Ecosystem & Packages Map + +The framework is organized into 7 logical architectural layers across 71 packages: + +| Layer | Core Package | Ecosystem Adapters & Modules | +| :--- | :--- | :--- | +| **Domain & Entities** | [`@quatrain/core`](/packages/core/readme) | [`@quatrain/types`](/packages/types/readme) · [`@quatrain/state-machine`](/packages/state-machine/readme) · [`@quatrain/okf`](/packages/okf/readme) | +| **Databases & Persistence** | [`@quatrain/backend`](/packages/backend/readme) | [`backend-postgres`](/packages/backend-postgres/readme) · [`backend-sqlite`](/packages/backend-sqlite/readme) · [`backend-firestore`](/packages/backend-firestore/readme) · [`backend-restapi`](/packages/backend-restapi/readme) · [`backend-migrations`](/packages/backend-migrations/readme) | +| **Authentication & RBAC** | [`@quatrain/auth`](/packages/auth/readme) | [`auth-rbac`](/packages/auth-rbac/readme) · [`auth-supabase`](/packages/auth-supabase/readme) · [`auth-firebase`](/packages/auth-firebase/readme) · [`auth-oidc`](/packages/auth-oidc/readme) · [`auth-pocketbase`](/packages/auth-pocketbase/readme) · [`auth-http-basic`](/packages/auth-http-basic/readme) | +| **Object Storage** | [`@quatrain/storage`](/packages/storage/readme) | [`storage-s3`](/packages/storage-s3/readme) · [`storage-local`](/packages/storage-local/readme) · [`storage-supabase`](/packages/storage-supabase/readme) · [`storage-firebase`](/packages/storage-firebase/readme) · [`storage-git`](/packages/storage-git/readme) | +| **Queues & Messaging** | [`@quatrain/queue`](/packages/queue/readme) | [`queue-amqp`](/packages/queue-amqp/readme) · [`queue-mqtt`](/packages/queue-mqtt/readme) · [`queue-sqlite`](/packages/queue-sqlite/readme) · [`queue-aws`](/packages/queue-aws/readme) · [`queue-gcp`](/packages/queue-gcp/readme) · [`messaging`](/packages/messaging/readme) | +| **APIs & Gateways** | [`@quatrain/api`](/packages/api/readme) | [`api-client`](/packages/api-client/readme) · [`api-server`](/packages/api-server/readme) · [`api-server-express`](/packages/api-server-express/readme) · [`api-server-astro`](/packages/api-server-astro/readme) · [`api-xmlrpc`](/packages/api-xmlrpc/readme) | +| **AI, Chat & Cognitive** | [`@quatrain/ai`](/packages/ai/readme) | [`ai-gemini`](/packages/ai-gemini/readme) · [`chat`](/packages/chat/readme) · [`skills`](/packages/skills/readme) | +| **Platform & Tooling** | [`@quatrain/cli`](/packages/cli/readme) | [`cache`](/packages/cache/readme) · [`cache-redis`](/packages/cache-redis/readme) · [`log`](/packages/log/readme) · [`i18n`](/packages/i18n/readme) · [`mdm`](/packages/mdm/readme) · [`testing`](/packages/testing/readme) | + +👉 **[Explore Full Interactive Packages Catalog](/packages)** + +--- + +## 🧠 Open Knowledge Base (OKF v0.1) & Tycho Integration + +Quatrain Core embeds an official knowledge base formatted according to the **Open Knowledge Format (OKF v0.1)** under [`okf/`](/okf). + +Designed specifically for **AI pair-programming agents** (Gemini, Claude, Antigravity, Cursor) and human engineers, it provides authoritative, hallucination-free guidance across core architectural areas: +* 🏛️ **Domain Modeling**: [okf/domain-modeling](/okf/domain-modeling) (Schemas, `.TYPE`, FSM workflows) +* 💾 **Persistence**: [okf/persistence-adapters](/okf/persistence-adapters) (Repositories, PostgreSQL, SQLite, Migrations) +* 🔐 **Auth & Security**: [okf/auth-and-security](/okf/auth-and-security) (SSO, Supabase, RBAC, Field-Level Security) +* 🗄️ **Object Storage**: [okf/storage-and-assets](/okf/storage-and-assets) (Unified S3/MinIO & Local FS storage) +* 📬 **Queues & Streaming**: [okf/queues-and-events](/okf/queues-and-events) (RabbitMQ/AMQP, background workers) +* 🌐 **API Gateways**: [okf/api-and-gateways](/okf/api-and-gateways) (Isomorphic fetch client, CrudEndpoint) +* 🤖 **AI Agents**: [okf/ai-and-agents](/okf/ai-and-agents) (Gemini models, schema-guaranteed JSON generation) + +### Annexing via Tycho CLI (`tycho knowledge`) + +```bash +# 1. Register the Quatrain Core repository in Tycho +tycho repo add quatrain Quatrain/Core + +# 2. Install the knowledge package +tycho knowledge install quatrain/quatrain-core + +# 3. Check active knowledge packages +tycho knowledge list +``` + +--- + +## 🧰 Companion Projects + +* **[Quatrain CoreApps](https://github.com/Quatrain/CoreApps)**: Pre-packaged Docker / Podman containers, including: + * `api-gateway`: High-performance reverse proxy and routing gateway. + * `studio-image`: Web modeling studio for entity scaffolding. +* **[Quatrain CoreUX](https://github.com/Quatrain/CoreUX)**: Mantine-based UI design tokens, components, high-contrast mobile interfaces, and voice adapters. diff --git a/docs/pages/okf/_meta.js b/docs/pages/okf/_meta.js new file mode 100644 index 00000000..549975fd --- /dev/null +++ b/docs/pages/okf/_meta.js @@ -0,0 +1,10 @@ +export default { + "index": "Overview", + "ai-and-agents": "AI Agents & LLM Integration", + "api-and-gateways": "API Clients & Gateways", + "auth-and-security": "Authentication & Access Control", + "domain-modeling": "Domain Modeling & Entities", + "persistence-adapters": "Persistence & Database Adapters", + "queues-and-events": "Queues & Event Streaming", + "storage-and-assets": "Storage & Object Assets" +} diff --git a/docs/pages/okf/ai-and-agents/_meta.js b/docs/pages/okf/ai-and-agents/_meta.js new file mode 100644 index 00000000..2536e03d --- /dev/null +++ b/docs/pages/okf/ai-and-agents/_meta.js @@ -0,0 +1,4 @@ +export default { + "index": "Category Overview", + "ai-gemini-and-skills": "AI Gemini & Skills" +} diff --git a/docs/pages/okf/ai-and-agents/ai-gemini-and-skills.md b/docs/pages/okf/ai-and-agents/ai-gemini-and-skills.md new file mode 100644 index 00000000..f2b7344c --- /dev/null +++ b/docs/pages/okf/ai-and-agents/ai-gemini-and-skills.md @@ -0,0 +1,94 @@ +--- +type: pattern +title: AI Gemini & Skills +description: Interfacing with Google Gemini models for text and structured JSON synthesis using GeminiAdapter from @quatrain/ai-gemini. +tags: + - quatrain + - ai + - gemini + - llm + - json-schema +timestamp: 2026-09-17T00:00:00.000Z +category: ai-and-agents +status: active +--- + +# AI Gemini & Skills + +Quatrain interfaces with Google's official Gemini AI models via `@quatrain/ai-gemini`. The adapter (`GeminiAdapter`) extends `AbstractAiAdapter` from `@quatrain/ai` and supports text synthesis, streaming, and schema-guaranteed JSON generation. + +--- + +## 🎯 Architectural Principles + +1. **Schema-Guaranteed Generation**: Use `generateStructured(prompt, schema, options)` when extracting domain objects or synthesizing structured fiches. +2. **Streaming for Interactive UI**: Use `generateTextStream(prompt, options)` for real-time token streaming to frontend clients. +3. **Fail-Fast Configuration**: Validate `GEMINI_API_KEY` before model instantiation. + +--- + +## ⚖️ Implementation Patterns + +### 1. Initializing GeminiAdapter +```typescript +import { GeminiAdapter } from "@quatrain/ai-gemini"; + +const apiKey = process.env.GEMINI_API_KEY; +if (!apiKey) { + throw new Error("Missing GEMINI_API_KEY environment variable."); +} + +export const aiAdapter = new GeminiAdapter(apiKey); +``` + +--- + +### 2. Schema-Constrained Extraction (`generateStructured`) +```typescript +import { aiAdapter } from "./ai"; + +interface SoilAnalysisResult { + soilCategory: string; + recommendedCoverCrop: string; + waterRetentionScore: number; +} + +// JSON Schema definition +const soilSchema = { + type: "object", + properties: { + soilCategory: { type: "string" }, + recommendedCoverCrop: { type: "string" }, + waterRetentionScore: { type: "number" }, + }, + required: ["soilCategory", "recommendedCoverCrop", "waterRetentionScore"], +}; + +export async function extractSoilInsights(textReport: string): Promise { + // Model guarantees response conforms to the provided schema + const result = await aiAdapter.generateStructured( + `Analyze the agronomy report and extract parameters:\n\n${textReport}`, + soilSchema, + { model: "gemini-2.5-flash" } + ); + + return result as SoilAnalysisResult; +} +``` + +--- + +### 3. Streaming Text Generation (`generateTextStream`) +```typescript +import { aiAdapter } from "./ai"; + +export async function streamSummary(prompt: string, onChunk: (text: string) => void): Promise { + const stream = await aiAdapter.generateTextStream(prompt, { + model: "gemini-2.5-flash", + }); + + for await (const chunk of stream) { + onChunk(chunk); + } +} +``` diff --git a/docs/pages/okf/ai-and-agents/index.md b/docs/pages/okf/ai-and-agents/index.md new file mode 100644 index 00000000..39374f6b --- /dev/null +++ b/docs/pages/okf/ai-and-agents/index.md @@ -0,0 +1,22 @@ +--- +type: index +title: AI Agents & LLM Integration +description: Google Gemini model adapters, structured generation, conversational history, and agent skills in Quatrain Core. +tags: + - quatrain + - ai + - gemini + - llm + - agents +timestamp: 2026-09-17T00:00:00.000Z +category: ai-and-agents +status: active +--- + +# AI Agents & LLM Integration + +Category index for artificial intelligence integrations, Gemini LLM adapters (`@quatrain/ai-gemini`), structured JSON output generation, and conversation orchestration (`@quatrain/chat`). + +## Concept Fiches + +- [AI Gemini & Skills](ai-gemini-and-skills.md) — Configuring `GeminiAdapter`, generating structured data matching JSON schemas, and agent orchestration. diff --git a/docs/pages/okf/api-and-gateways/_meta.js b/docs/pages/okf/api-and-gateways/_meta.js new file mode 100644 index 00000000..8a5d11be --- /dev/null +++ b/docs/pages/okf/api-and-gateways/_meta.js @@ -0,0 +1,5 @@ +export default { + "index": "Category Overview", + "api-server-and-endpoints": "API Server & Endpoints", + "isomorphic-api-client": "Isomorphic API Client" +} diff --git a/docs/pages/okf/api-and-gateways/api-server-and-endpoints.md b/docs/pages/okf/api-and-gateways/api-server-and-endpoints.md new file mode 100644 index 00000000..9ae8ad2e --- /dev/null +++ b/docs/pages/okf/api-and-gateways/api-server-and-endpoints.md @@ -0,0 +1,48 @@ +--- +type: pattern +title: API Server & Endpoints +description: Standardized REST endpoint handlers and controllers with CrudEndpoint and ListEndpoint from @quatrain/api-server. +tags: + - quatrain + - api-server + - endpoints + - rest + - controllers +timestamp: 2026-09-17T00:00:00.000Z +category: api-and-gateways +status: active +--- + +# API Server & Endpoints + +`@quatrain/api-server` provides reusable endpoint handlers that bind Quatrain models and repositories directly to HTTP web servers (implementing `ServerAdapter` from `@quatrain/api`), automating CRUD operations and input validation. + +--- + +## 🎯 Architectural Principles + +1. **Higher-Order Endpoints**: Controllers like `CrudEndpoint(ModelClass)` return an `EndpointHandler` that attaches standardized REST routes to any `ServerAdapter`. +2. **Unified Route Registration**: Routes are mounted via `server.addEndpoint(CrudEndpoint(Model), path, options)`. +3. **Repository Integration**: Automatically invokes `Model.factory()`, `.save()`, and `.fromBackend()` under the hood. + +--- + +## ⚖️ Implementation Patterns + +### ✅ Registering CrudEndpoint on ServerAdapter +```typescript +import { CrudEndpoint } from "@quatrain/api-server"; +import type { ServerAdapter } from "@quatrain/api"; +import { Article } from "./models/Article"; + +export function registerArticleRoutes(server: ServerAdapter): void { + // CrudEndpoint(Model) creates an EndpointHandler mapping GET, POST, PUT, DELETE + server.addEndpoint( + CrudEndpoint(Article), + "/api/articles", + { + methods: ["CREATE", "READ", "UPDATE", "DELETE"], + } + ); +} +``` diff --git a/docs/pages/okf/api-and-gateways/index.md b/docs/pages/okf/api-and-gateways/index.md new file mode 100644 index 00000000..c3a83441 --- /dev/null +++ b/docs/pages/okf/api-and-gateways/index.md @@ -0,0 +1,23 @@ +--- +type: index +title: API Clients & Gateways +description: Isomorphic HTTP client and headless CRUD endpoints for Express and Astro backends in Quatrain Core. +tags: + - quatrain + - api-client + - api-server + - endpoints + - http +timestamp: 2026-09-17T00:00:00.000Z +category: api-and-gateways +status: active +--- + +# API Clients & Gateways + +Category index for isomorphic fetch-based API communication (`@quatrain/api-client`) and reusable REST endpoint controllers (`@quatrain/api-server`). + +## Concept Fiches + +- [Isomorphic API Client](isomorphic-api-client.md) — Typed HTTP requests, bearer token injection, backoff retries, and error handling. +- [API Server & Endpoints](api-server-and-endpoints.md) — Exposing standardized `CrudEndpoint`, `ListEndpoint`, and `ValuesEndpoint` across web server frameworks. diff --git a/docs/pages/okf/api-and-gateways/isomorphic-api-client.md b/docs/pages/okf/api-and-gateways/isomorphic-api-client.md new file mode 100644 index 00000000..842d31b3 --- /dev/null +++ b/docs/pages/okf/api-and-gateways/isomorphic-api-client.md @@ -0,0 +1,61 @@ +--- +type: pattern +title: Isomorphic API Client +description: Type-safe, fetch-based isomorphic HTTP client with AuthProvider integration via @quatrain/api-client. +tags: + - quatrain + - api-client + - http + - fetch + - isomorphic +timestamp: 2026-09-17T00:00:00.000Z +category: api-and-gateways +status: active +--- + +# Isomorphic API Client + +Quatrain uses `@quatrain/api-client` as its canonical HTTP communication library, replacing Axios. It is strictly isomorphic, executing identically across browser environments, Node.js SSR, React Native/Expo, and Bun. + +--- + +## 🎯 Architectural Principles + +1. **Native Fetch Foundation**: Built directly on top of native `fetch`, eliminating legacy request libraries. +2. **Pluggable AuthProvider**: Injects credentials and bearer tokens automatically prior to request dispatch via `client.setAuthProvider()`. +3. **Structured Response Envelope**: Standardizes all query results into `{ status, data, meta }`. + +--- + +## ⚖️ Implementation Patterns + +### ✅ Standard ApiClient Usage +```typescript +import { ApiClient } from "@quatrain/api-client"; + +interface UserProfile { + id: string; + name: string; + email: string; +} + +// Instantiate client with base URL +const client = new ApiClient("https://api.example.com/v1"); + +// Type-safe HTTP GET with pagination options +export async function fetchUsers(pageOffset: number = 0): Promise { + const response = await client.get("users", { + batch: 25, + offset: pageOffset, + }); + + console.log(`HTTP Status: ${response.status}`); + return response.data as UserProfile[]; +} + +// Type-safe HTTP POST +export async function createUser(userData: { name: string; email: string }): Promise { + const response = await client.post("users", userData); + return response.data as UserProfile; +} +``` diff --git a/docs/pages/okf/auth-and-security/_meta.js b/docs/pages/okf/auth-and-security/_meta.js new file mode 100644 index 00000000..644fcfcc --- /dev/null +++ b/docs/pages/okf/auth-and-security/_meta.js @@ -0,0 +1,5 @@ +export default { + "index": "Category Overview", + "auth-providers-and-sso": "Auth Providers & SSO", + "rbac-and-field-level-security": "RBAC & Field-Level Security" +} diff --git a/docs/pages/okf/auth-and-security/auth-providers-and-sso.md b/docs/pages/okf/auth-and-security/auth-providers-and-sso.md new file mode 100644 index 00000000..e8cbf3b5 --- /dev/null +++ b/docs/pages/okf/auth-and-security/auth-providers-and-sso.md @@ -0,0 +1,64 @@ +--- +type: pattern +title: Auth Providers & SSO +description: Managing authentication adapters, session validation, and bearer token middlewares with @quatrain/auth. +tags: + - quatrain + - auth + - sso + - oauth + - supabase +timestamp: 2026-09-17T00:00:00.000Z +category: auth-and-security +status: active +--- + +# Auth Providers & SSO + +Quatrain abstracts identity providers and user authentication behind `@quatrain/auth`. The core application consumes `Auth.getProvider()`, while concrete adapters (Supabase, Firebase, Mock, Basic Auth) handle token extraction and user resolution. + +--- + +## 🎯 Architectural Principles + +1. **Provider Registration**: Adapters are registered into the global registry via `Auth.addProvider(adapter, alias, setDefault)`. +2. **Standardized Bearer Token Resolution**: Adapters implement `getAuthToken(bearer)` to parse JWTs and return the authenticated `User` model. +3. **Built-in Middleware**: Concrete adapters supply `.middleware()` returning an API middleware that automatically intercepts the `Authorization: Bearer ` header. + +--- + +## ⚖️ Implementation Patterns + +### 1. Registering an Auth Provider +```typescript +import { Auth } from "@quatrain/auth"; +import { MockAuthAdapter } from "@quatrain/auth"; + +// Concrete adapter instance (e.g. SupabaseAuthAdapter, MockAuthAdapter) +const authAdapter = new MockAuthAdapter({ + alias: "default", +}); + +// Register into the global Auth registry +Auth.addProvider(authAdapter, "default", true); +``` + +--- + +### 2. Manual Token Verification +```typescript +import { Auth } from "@quatrain/auth"; +import { User } from "@quatrain/backend"; + +export async function authenticateBearer(bearerToken: string): Promise { + const provider = Auth.getProvider(); // Default provider + + try { + const user = await provider.getAuthToken(bearerToken); + return user; + } catch (err) { + Auth.error(`Token authentication failed: ${(err as Error).message}`); + return null; + } +} +``` diff --git a/docs/pages/okf/auth-and-security/index.md b/docs/pages/okf/auth-and-security/index.md new file mode 100644 index 00000000..19c6ebed --- /dev/null +++ b/docs/pages/okf/auth-and-security/index.md @@ -0,0 +1,23 @@ +--- +type: index +title: Authentication & Access Control +description: Identity management, OAuth/OIDC adapters, and Role-Based Access Control (RBAC) with Field-Level Security in Quatrain Core. +tags: + - quatrain + - auth + - rbac + - security + - sso +timestamp: 2026-09-17T00:00:00.000Z +category: auth-and-security +status: active +--- + +# Authentication & Access Control + +Category index for authentication adapters (Supabase, Firebase, PocketBase, Basic Auth) and granular role-based permissions via `@quatrain/auth-rbac`. + +## Concept Fiches + +- [Auth Providers & SSO](auth-providers-and-sso.md) — Configuring authentication adapters, OAuth PKCE flows, and JWT session validation. +- [RBAC & Field-Level Security](rbac-and-field-level-security.md) — Enforcing roles, policies, sanitizeWrite guards, and HTTP middlewares (`ExpressRbacMiddleware`, `AstroRbacMiddleware`). diff --git a/docs/pages/okf/auth-and-security/rbac-and-field-level-security.md b/docs/pages/okf/auth-and-security/rbac-and-field-level-security.md new file mode 100644 index 00000000..d015233e --- /dev/null +++ b/docs/pages/okf/auth-and-security/rbac-and-field-level-security.md @@ -0,0 +1,110 @@ +--- +type: pattern +title: RBAC & Field-Level Security +description: Role-Based Access Control and Field-Level Security (FLS) using RbacPolicyEngine and ExpressRbacMiddleware from @quatrain/auth-rbac. +tags: + - quatrain + - rbac + - security + - fls + - authorization +timestamp: 2026-09-17T00:00:00.000Z +category: auth-and-security +status: active +--- + +# RBAC & Field-Level Security + +Quatrain enforces granular authorization and field-level permissions using `@quatrain/auth-rbac`. Beyond coarse route guards, the engine provides Field-Level Security (FLS) to strip unauthorized properties on write (`sanitizeWrite`) and evaluate role hierarchies. + +--- + +## 🎯 Architectural Principles + +1. **Deny by Default**: Any unmapped route or action is denied unless an explicit permission or route rule grants access. +2. **Field-Level Sanitization**: Never trust client payloads directly; always pass mutations through `engine.sanitizeWrite(user, entity, payload)` to protect sensitive lineage properties (`soa`, `revision`, `role`). +3. **Framework Middleware**: Seamlessly attach route and tarpit guards to Express servers via `new ExpressRbacMiddleware(engine).handler()`. + +--- + +## ⚖️ Implementation Patterns + +### 1. Initializing RbacPolicyEngine +```typescript +import { RbacPolicyEngine } from "@quatrain/auth-rbac"; +import type { RoleDefinition, RbacUserContext } from "@quatrain/auth-rbac"; + +const roles: RoleDefinition[] = [ + { + id: "admin", + name: "Administrator", + inherits: ["editor"], + permissions: ["*"], + }, + { + id: "editor", + name: "Editor", + inherits: ["viewer"], + permissions: ["document:create", "document:update"], + entities: { + document: { + defaultMode: "readwrite", + fields: { + soa: "readonly", // Protected lineage field + revision: "readonly", // Protected revision stamp + internalNotes: "hidden", + }, + }, + }, + }, + { + id: "viewer", + name: "Viewer", + permissions: ["document:read"], + }, +]; + +export const rbac = new RbacPolicyEngine(roles); +``` + +--- + +### 2. Field-Level Sanitization on Mutations +```typescript +import { rbac } from "./rbac"; +import type { RbacUserContext } from "@quatrain/auth-rbac"; + +interface DocumentPayload { + title: string; + soa?: string; + content: string; +} + +export function sanitizeDocumentUpdate( + user: RbacUserContext, + rawPayload: DocumentPayload +): Partial { + // Strips any field marked as 'readonly' or 'hidden' for the user's active roles + const safeData = rbac.sanitizeWrite(user, "document", rawPayload); + return safeData; +} +``` + +--- + +### 3. Attaching Express Middleware +```typescript +import express from "express"; +import { ExpressRbacMiddleware } from "@quatrain/auth-rbac"; +import { rbac } from "./rbac"; + +const app = express(); +app.use(express.json()); + +const rbacMiddleware = new ExpressRbacMiddleware(rbac, { + userResolver: (req) => req.user, // User context populated by auth middleware + enableTarpitSleep: true, +}); + +app.use(rbacMiddleware.handler()); +``` diff --git a/docs/pages/okf/domain-modeling/_meta.js b/docs/pages/okf/domain-modeling/_meta.js new file mode 100644 index 00000000..a5f6a1c9 --- /dev/null +++ b/docs/pages/okf/domain-modeling/_meta.js @@ -0,0 +1,5 @@ +export default { + "index": "Category Overview", + "core-base-object-and-properties": "Core Base Object & Properties", + "state-machines-and-workflows": "State Machines & Workflows" +} diff --git a/docs/pages/okf/domain-modeling/core-base-object-and-properties.md b/docs/pages/okf/domain-modeling/core-base-object-and-properties.md new file mode 100644 index 00000000..d74da4cf --- /dev/null +++ b/docs/pages/okf/domain-modeling/core-base-object-and-properties.md @@ -0,0 +1,121 @@ +--- +type: pattern +title: Core Base Object & Properties +description: Declarative schema definitions, property registration, StringProperty.TYPE constants, and proxy property access in Quatrain Core. +tags: + - quatrain + - core + - domain-modeling + - schema + - typescript +timestamp: 2026-09-17T00:00:00.000Z +category: domain-modeling +status: active +--- + +# Core Base Object & Properties + +Quatrain models business domain entities using class definitions extending `BaseObject` (from `@quatrain/core`) and registered into the reflection registry via `Core.addClass()`. + +--- + +## 🎯 Architectural Principles + +1. **Explicit Schema Declaration**: Entities declare their static properties in `PROPS_DEFINITION` array using property type constants (`StringProperty.TYPE`, `NumberProperty.TYPE`, `BooleanProperty.TYPE`, etc.). +2. **Access via Methods and Proxy (`._`)**: Properties can be accessed using `.get('key')`, `.val('key')`, mutated using `.set('key', value)`, or directly via the `._` proxy accessor. +3. **Factory Hydration**: Instances are constructed asynchronously using `await ModelClass.factory(data)` or synchronously via `ModelClass.fromObject(data)`. + +--- + +## ⚖️ Implementation Patterns + +### ❌ Anti-Pattern: Untyped Dynamic Properties +```typescript +// ❌ BAD: No schema definition, untyped runtime properties, impossible persistence mapping +export class User { + id: string; + name: string; + + constructor(data: any) { + this.id = data.id; + this.name = data.name; + (this as any).extra = "untracked"; // ❌ Bypasses schema & breaks persistence + } +} +``` + +### ✅ Standard Pattern: Quatrain Declarative BaseObject +```typescript +// ✅ GOOD: Registered schema with Quatrain properties, typed proxy, and factory hydration +import { + BaseObject, + StringProperty, + BooleanProperty, + Core, +} from "@quatrain/core"; +import type { DataObjectClass } from "@quatrain/core"; + +export interface UserProxy { + email: string; + fullName: string; + isActive: boolean; +} + +export class User extends BaseObject { + static COLLECTION = "users"; + + static PROPS_DEFINITION = [ + { + name: "email", + type: StringProperty.TYPE, + required: true, + }, + { + name: "fullName", + type: StringProperty.TYPE, + required: true, + default: "", + }, + { + name: "isActive", + type: BooleanProperty.TYPE, + default: true, + }, + ]; + + declare _: UserProxy; + + constructor(dao: DataObjectClass) { + super(dao); + } +} + +// Register class in Quatrain Core reflection registry +Core.addClass("User", User); +``` + +--- + +## 💡 Instantiation & Access Example + +```typescript +// Asynchronous hydration via factory +const user = await User.factory({ + name: "usr_1029", + email: "developer@quatrain.dev", + fullName: "Alice Vance", + isActive: true, +}); + +// Property value access via .val() or proxy ._ +console.log(user.val("fullName")); // "Alice Vance" +console.log(user._.fullName); // "Alice Vance" + +// Mutation via .set() or proxy +user.set("fullName", "Alice Smith"); +user._.isActive = false; + +// Canonical URI and JSON serialization +console.log(user.path); // "users/usr_1029" +const payload = user.toJSON(); +``` diff --git a/docs/pages/okf/domain-modeling/index.md b/docs/pages/okf/domain-modeling/index.md new file mode 100644 index 00000000..75bb2857 --- /dev/null +++ b/docs/pages/okf/domain-modeling/index.md @@ -0,0 +1,22 @@ +--- +type: index +title: Domain Modeling & Entities +description: Quatrain Core entity declaration, schema typing, property proxies, and finite state machines. +tags: + - quatrain + - domain-modeling + - schema + - fsm +timestamp: 2026-09-17T00:00:00.000Z +category: domain-modeling +status: active +--- + +# Domain Modeling & Entities + +Category index for declarative entity modeling, typed property definition, and state machine workflows in Quatrain Core. + +## Concept Fiches + +- [Core Base Object & Properties](core-base-object-and-properties.md) — Declaring schemas via `Core.addClass`, validating property definitions with `.TYPE`, and property access via `._`. +- [State Machines & Workflows](state-machines-and-workflows.md) — Defining deterministic states, transition guards, and lifecycle hooks with `@quatrain/state-machine`. diff --git a/docs/pages/okf/domain-modeling/state-machines-and-workflows.md b/docs/pages/okf/domain-modeling/state-machines-and-workflows.md new file mode 100644 index 00000000..f82dee25 --- /dev/null +++ b/docs/pages/okf/domain-modeling/state-machines-and-workflows.md @@ -0,0 +1,101 @@ +--- +type: pattern +title: State Machines & Workflows +description: Deterministic lifecycle state management using WorkflowStateMachine from @quatrain/state-machine. +tags: + - quatrain + - state-machine + - workflows + - fsm + - domain-modeling +timestamp: 2026-09-17T00:00:00.000Z +category: domain-modeling +status: active +--- + +# State Machines & Workflows + +Quatrain provides deterministic finite state machine abstractions via `@quatrain/state-machine`. Rather than managing status mutations through loose string manipulation, entities use `WorkflowStateMachine` with typed states, events, guards, and transition actions. + +--- + +## 🎯 Architectural Principles + +1. **Explicit States & Events**: States and triggering events are declared as strict union types. +2. **Transition Rules & Guards**: Transitions are registered via `addTransition(from, event, to, guard?, action?)`. If the guard predicate fails, the state does not change. +3. **Traceability**: `fsm.getHistory()` preserves the full chronological trajectory of state changes. + +--- + +## ⚖️ Implementation Patterns + +### ❌ Anti-Pattern: Ad-Hoc String Checks & Direct Mutation +```typescript +// ❌ BAD: Fragile conditional logic scattered throughout controllers without history or guards +function approveOrder(order: any) { + if (order.status === "draft") { + order.status = "approved"; // ❌ No guard, no history, no transition check + } else if (order.status === "cancelled") { + throw new Error("Cannot approve cancelled order"); + } +} +``` + +### ✅ Standard Pattern: Quatrain WorkflowStateMachine +```typescript +// ✅ GOOD: Strong state & event typing, explicit transition table with guards and actions +import { WorkflowStateMachine } from "@quatrain/state-machine"; + +type OrderState = "draft" | "submitted" | "approved" | "rejected"; +type OrderEvent = "SUBMIT" | "APPROVE" | "REJECT"; + +interface OrderContext { + orderId: string; + totalAmount: number; + approverEmail?: string; +} + +const context: OrderContext = { + orderId: "ord_9901", + totalAmount: 450, +}; + +// Initialize workflow state machine in 'draft' state +const fsm = new WorkflowStateMachine("draft", context); + +// 1. Transition: draft -> submitted +fsm.addTransition( + "draft", + "SUBMIT", + "submitted", + (ctx) => ctx.totalAmount > 0 // Guard: must have positive amount +); + +// 2. Transition: submitted -> approved +fsm.addTransition( + "submitted", + "APPROVE", + "approved", + (ctx) => ctx.approverEmail !== undefined, // Guard: approver must be set + async (ctx) => { + // Action callback executed upon successful transition + console.log(`Order ${ctx.orderId} approved by ${ctx.approverEmail}`); + } +); + +// Execute transitions: +const submitted = await fsm.transition("SUBMIT"); +console.log(submitted); // true +console.log(fsm.currentState); // "submitted" + +// Attempt approval without approver set (guard fails) +const approvedFail = await fsm.transition("APPROVE"); +console.log(approvedFail); // false (guard prevented transition) + +// Set approver and retry +context.approverEmail = "manager@quatrain.dev"; +const approvedSuccess = await fsm.transition("APPROVE"); +console.log(approvedSuccess); // true +console.log(fsm.currentState); // "approved" +console.log(fsm.getHistory()); // ["draft", "submitted", "approved"] +``` diff --git a/docs/pages/okf/index.md b/docs/pages/okf/index.md new file mode 100644 index 00000000..638aa3cb --- /dev/null +++ b/docs/pages/okf/index.md @@ -0,0 +1,68 @@ +--- +type: index +title: Quatrain Core — OKF Knowledge Base & Architecture Standards +description: Open Knowledge Format v0.1 knowledge base for Quatrain Core framework, domain modeling patterns, and backend adapters. +tags: + - quatrain + - architecture + - okf + - guidelines + - tycho +timestamp: 2026-09-17T00:00:00.000Z +category: root +status: active +--- + +# Quatrain Core — OKF Knowledge Base & Architecture Standards + +> **Format**: Open Knowledge Format (OKF v0.1) | **License**: AGPL-v3 +> **Source Repository**: `https://github.com/Quatrain/Core` +> **Target Audience**: AI Coding Agents (Gemini, Claude, Antigravity, Cursor) & Human Engineers + +--- + +## 🧭 1. Progressive Disclosure & Navigation + +To maintain high agent velocity while preserving context tokens, do not load all fiches simultaneously. Navigate hierarchically starting from the categories below: + +| Thematic Category | Coverage & Scope | Category Index | +| :--- | :--- | :--- | +| **Domain Modeling & Entities** | Declarative schemas, typed properties, proxy access (`._`), FSM workflows | [domain-modeling/index.md](domain-modeling/index.md) | +| **Persistence & Database Adapters** | Active Record, repository pattern, PostgreSQL, SQLite, Firestore, migrations | [persistence-adapters/index.md](persistence-adapters/index.md) | +| **Authentication & Access Control** | Multi-provider auth (Supabase, Firebase, OIDC), RBAC & Field-Level Security | [auth-and-security/index.md](auth-and-security/index.md) | +| **Storage & Object Assets** | Unified storage abstraction (S3/MinIO, Local FS, Firebase Storage) | [storage-and-assets/index.md](storage-and-assets/index.md) | +| **Queues & Event Streaming** | Asynchronous workers, AMQP/RabbitMQ, MQTT, SQLite queue, AWS SQS | [queues-and-events/index.md](queues-and-events/index.md) | +| **API Clients & Server Endpoints** | Isomorphic fetch client, retry backoff, Express/Astro server controllers | [api-and-gateways/index.md](api-and-gateways/index.md) | +| **AI Agents & LLM Integration** | Gemini engine adapter, conversational memory, skill execution | [ai-and-agents/index.md](ai-and-agents/index.md) | + +--- + +## ⚡ 2. Tycho Annexation Protocol (`tycho knowledge`) + +This knowledge base is packaged as an official **Tycho Knowledge Package**. It can be directly installed and annexed to your active AI agent environment (`AGENTS.okf`, `.gemini/config`, or project-level rules) using the **Tycho CLI**. + +### Step 1: Register Repository (if not already present) +```bash +tycho repo add quatrain Quatrain/Core +``` + +### Step 2: Install Knowledge Package +```bash +tycho knowledge install quatrain/quatrain-core +``` +*(Or `tycho knowledge install quatrain-core` if auto-search is enabled across registered repos).* + +### Step 3: Verify Active Installation +```bash +tycho knowledge list +``` + +The post-install hook automatically links `okf/` into your active knowledge base (e.g. `~/.tycho/knowledge/agents-okf/content/quatrain-core` or local workspace `AGENTS.okf`) and rebuilds LLM agent routers. + +--- + +## 🛑 3. Mandatory Framework Coding Rules + +1. **Zero `as any` Type Assertions**: Never use `as any`, `@ts-ignore`, or loose type assertions. Use explicit interfaces and Quatrain type constants. +2. **Schema Authority**: Entities must declare properties via `Core.addClass()` with `.TYPE` definitions from `@quatrain/core`. +3. **Repository Decoupling**: Business domain objects must never directly query raw SQL or drivers; always route queries through the registered repository adapter. diff --git a/docs/pages/okf/persistence-adapters/_meta.js b/docs/pages/okf/persistence-adapters/_meta.js new file mode 100644 index 00000000..e7e4b99c --- /dev/null +++ b/docs/pages/okf/persistence-adapters/_meta.js @@ -0,0 +1,6 @@ +export default { + "index": "Category Overview", + "database-adapters-setup": "Database Adapters Setup", + "quatrain-repository-pattern": "Quatrain Repository Pattern", + "schema-and-data-migrations": "Schema & Data Migrations" +} diff --git a/docs/pages/okf/persistence-adapters/database-adapters-setup.md b/docs/pages/okf/persistence-adapters/database-adapters-setup.md new file mode 100644 index 00000000..b5c2fd75 --- /dev/null +++ b/docs/pages/okf/persistence-adapters/database-adapters-setup.md @@ -0,0 +1,85 @@ +--- +type: pattern +title: Database Adapters Setup +description: Setting up and configuring persistence adapters for PostgreSQL and SQLite using Backend.addBackend() in Quatrain Core. +tags: + - quatrain + - backend + - database + - postgres + - sqlite +timestamp: 2026-09-17T00:00:00.000Z +category: persistence-adapters +status: active +--- + +# Database Adapters Setup + +Quatrain uses an adapter-driven persistence architecture managed by `Backend.addBackend()`. Domain models and repositories interact with abstract interfaces, allowing identical application code to run against PostgreSQL, SQLite, or in-memory stores. + +--- + +## 🎯 Architectural Principles + +1. **Global Adapter Registration**: Backend adapters are registered during application bootstrap via `Backend.addBackend(adapter, alias, setDefault)`. +2. **Configuration Validation**: Always validate connection parameters (host, port, credentials) prior to starting servers. +3. **Multi-Backend Support**: Multiple backends can coexist under distinct aliases, enabling different models to target different databases. + +--- + +## ⚖️ Implementation Patterns + +### 1. PostgreSQL Adapter (`@quatrain/backend-postgres`) + +Standard relational adapter with connection pooling via `pg`: + +```typescript +import { Backend } from "@quatrain/backend"; +import { PostgresAdapter } from "@quatrain/backend-postgres"; + +const host = process.env.PG_HOST || "localhost"; +const port = parseInt(process.env.PG_PORT || "5432", 10); +const database = process.env.PG_DATABASE || "quatrain_db"; +const user = process.env.PG_USER || "postgres"; +const password = process.env.PG_PASSWORD; + +if (!password) { + throw new Error("Missing PG_PASSWORD environment variable."); +} + +const pgAdapter = new PostgresAdapter({ + config: { + host, + port, + database, + user, + password, + max: 20, // Pool client limit + }, +}); + +// Register as the default backend +Backend.addBackend(pgAdapter, "postgres", true); +``` + +--- + +### 2. SQLite Adapter (`@quatrain/backend-sqlite`) + +Lightweight SQL adapter ideal for local development, edge computing, and unit tests: + +```typescript +import { Backend } from "@quatrain/backend"; +import { SQLiteAdapter } from "@quatrain/backend-sqlite"; + +const sqlitePath = process.env.SQLITE_DATABASE || "./data/app.sqlite"; + +const sqliteAdapter = new SQLiteAdapter({ + config: { + database: sqlitePath, // Or ':memory:' for transient test suites + }, +}); + +// Register as the default backend +Backend.addBackend(sqliteAdapter, "sqlite", true); +``` diff --git a/docs/pages/okf/persistence-adapters/index.md b/docs/pages/okf/persistence-adapters/index.md new file mode 100644 index 00000000..5df3f8d4 --- /dev/null +++ b/docs/pages/okf/persistence-adapters/index.md @@ -0,0 +1,25 @@ +--- +type: index +title: Persistence & Database Adapters +description: Quatrain Core database abstraction layer, repository pattern, SQL/NoSQL drivers, and declarative schema migrations. +tags: + - quatrain + - persistence + - repository + - postgres + - sqlite + - migrations +timestamp: 2026-09-17T00:00:00.000Z +category: persistence-adapters +status: active +--- + +# Persistence & Database Adapters + +Category index for database connectivity, Active Record abstraction, typed queries, and schema migrations across PostgreSQL, SQLite, and Firestore. + +## Concept Fiches + +- [Quatrain Repository Pattern](quatrain-repository-pattern.md) — BaseRepository, `.repository()` dynamic binding, query construction, and transactions. +- [Database Adapters Setup](database-adapters-setup.md) — Configuring PostgreSQL (`@quatrain/backend-postgres`), SQLite (`@quatrain/backend-sqlite`), and Firestore (`@quatrain/backend-firestore`). +- [Schema & Data Migrations](schema-and-data-migrations.md) — Declarative migrations and version control with `@quatrain/backend-migrations`. diff --git a/docs/pages/okf/persistence-adapters/quatrain-repository-pattern.md b/docs/pages/okf/persistence-adapters/quatrain-repository-pattern.md new file mode 100644 index 00000000..86c7b43d --- /dev/null +++ b/docs/pages/okf/persistence-adapters/quatrain-repository-pattern.md @@ -0,0 +1,167 @@ +--- +type: pattern +title: Quatrain Repository Pattern +description: Database access using PersistedBaseObject, Model.repository() dynamic binding, and typed queries with BaseRepository. +tags: + - quatrain + - backend + - repository + - active-record + - queries +timestamp: 2026-09-17T00:00:00.000Z +category: persistence-adapters +status: active +--- + +# Quatrain Repository Pattern + +In Quatrain, persistent domain entities inherit from `PersistedBaseObject` (from `@quatrain/backend`). Every persistent class automatically provides a pre-bound, strongly-typed `BaseRepository` via the static `.repository()` method. + +--- + +## 🎯 Architectural Principles + +1. **Zero-Boilerplate Default**: Standard CRUD operations do not require declaring custom repository classes; calling `MyModel.repository()` dynamically instantiates and caches a pre-bound `BaseRepository`. +2. **Domain Encapsulation**: Domain-specific query helpers or aggregation routines are encapsulated in custom repository classes extending `BaseRepository`. +3. **Decoupled Backend Engine**: Repositories operate against the registered backend adapter (`PostgresAdapter`, `SQLiteAdapter`, etc.) without raw database coupling. + +--- + +## ⚖️ Implementation Patterns + +### ❌ Anti-Pattern: Leaking Raw Database Queries in Controllers +```typescript +// ❌ BAD: Leaking SQL client and raw strings directly in controllers +import { pool } from "../database"; + +async function findActiveUsers() { + const result = await pool.query("SELECT * FROM users WHERE is_active = true"); + return (result.rows as any); // ❌ Untyped, unvalidated, database tightly coupled +} +``` + +### ✅ Standard Pattern: PersistedBaseObject & BaseRepository +```typescript +// ✅ GOOD: Declarative schema, typed properties, zero-boilerplate repository access +import { + PersistedBaseObject, + BaseRepository, + Query, +} from "@quatrain/backend"; +import { + StringProperty, + BooleanProperty, + NumberProperty, + Core, +} from "@quatrain/core"; +import type { DataObjectClass } from "@quatrain/core"; + +export class Article extends PersistedBaseObject { + static COLLECTION = "articles"; + + static PROPS_DEFINITION = [ + { + name: "title", + type: StringProperty.TYPE, + required: true, + }, + { + name: "published", + type: BooleanProperty.TYPE, + default: false, + }, + { + name: "viewCount", + type: NumberProperty.TYPE, + default: 0, + }, + ]; + + constructor(dao: DataObjectClass) { + super(dao); + } +} + +// Register class with Quatrain Core registry +Core.addClass("Article", Article); + +// --- Standard CRUD Operations --- +async function manageArticle() { + const repo = Article.repository(); + + // 1. Create + const article = await Article.factory({ + name: "art_101", + title: "Understanding OKF v0.1", + published: true, + viewCount: 120, + }); + const saved = await repo.create(article); + + // 2. Read by UID + const loaded = await repo.read("art_101"); + + // 3. Update + if (loaded) { + loaded.set("viewCount", 125); + await repo.update(loaded); + } + + // 4. Delete + await repo.delete("art_101"); +} +``` + +--- + +## 💡 Advanced Querying with Query Builder + +For filtered searches and pagination, use `Query` executed via `repo.query()`: + +```typescript +import { Article } from "./Article"; +import { Query } from "@quatrain/backend"; + +export async function searchPublishedArticles(): Promise { + const repo = Article.repository(); + + const query = new Query(Article); + query + .where("published", true) + .sortBy("viewCount", "desc") + .batch(20); + + // Executes query against current backend adapter + const result = await repo.query(query); + + console.log(`Found ${result.meta.count} articles`); + return result.items; +} +``` + +--- + +## 💡 Custom Repository Extension + +If a model requires custom domain queries, extend `BaseRepository` and attach it to the model via `REPOSITORY_CLASS`: + +```typescript +import { BaseRepository, Query } from "@quatrain/backend"; +import { Article } from "./Article"; + +export class ArticleRepository extends BaseRepository
{ + async findTrendingArticles(minViews: number): Promise { + const query = new Query(Article); + query + .where("published", true) + .where("viewCount", minViews, ">=") + .sortBy("viewCount", "desc"); + + const result = await this.query(query); + return result.items; + } +} + +// Bind custom repository class to the model +Article.REPOSITORY_CLASS = ArticleRepository; +``` diff --git a/docs/pages/okf/persistence-adapters/schema-and-data-migrations.md b/docs/pages/okf/persistence-adapters/schema-and-data-migrations.md new file mode 100644 index 00000000..8a4204b5 --- /dev/null +++ b/docs/pages/okf/persistence-adapters/schema-and-data-migrations.md @@ -0,0 +1,54 @@ +--- +type: pattern +title: Schema & Data Migrations +description: Versioned schema evolution and data migrations using MigrationManager from @quatrain/backend-migrations. +tags: + - quatrain + - backend + - migrations + - ddl + - schema +timestamp: 2026-09-17T00:00:00.000Z +category: persistence-adapters +status: active +--- + +# Schema & Data Migrations + +Quatrain applications manage database schema evolution and migrations using `MigrationManager` from `@quatrain/backend-migrations`. Powered by Umzug, migrations are executed against the active backend adapter with automatic tracking in `QuatrainMigrationStorage`. + +--- + +## 🎯 Architectural Principles + +1. **Adapter-Bound Migrations**: `MigrationManager` accepts an instantiated `AbstractBackendAdapter` (e.g. from `Backend.getBackend()`). +2. **Directory Isolation**: Migrations are scoped per backend alias under `data/migrations//` or an explicit `migrationsPath`. +3. **Automated Verification**: Migration status can be audited via `getPendingMigrations()` prior to deployment. + +--- + +## ⚖️ Implementation Patterns + +### ✅ Running Pending Migrations +```typescript +import { MigrationManager } from "@quatrain/backend-migrations"; +import { Backend } from "@quatrain/backend"; + +export async function runDatabaseMigrations(): Promise { + const adapter = Backend.getBackend(); // Get active default adapter + + const manager = new MigrationManager(adapter, { + migrationsPath: "./data/migrations/default", + }); + + // Check pending migrations + const pending = await manager.getPendingMigrations(); + console.log(`Discovered ${pending.length} pending migration(s)`); + + if (pending.length > 0) { + // Execute all pending migrations + await manager.executeMigrations(); + console.log("All migrations executed successfully."); + } +} +``` diff --git a/docs/pages/okf/queues-and-events/_meta.js b/docs/pages/okf/queues-and-events/_meta.js new file mode 100644 index 00000000..cb55f06f --- /dev/null +++ b/docs/pages/okf/queues-and-events/_meta.js @@ -0,0 +1,4 @@ +export default { + "index": "Category Overview", + "asynchronous-event-streaming": "Asynchronous Event Streaming" +} diff --git a/docs/pages/okf/queues-and-events/asynchronous-event-streaming.md b/docs/pages/okf/queues-and-events/asynchronous-event-streaming.md new file mode 100644 index 00000000..7cb80c68 --- /dev/null +++ b/docs/pages/okf/queues-and-events/asynchronous-event-streaming.md @@ -0,0 +1,84 @@ +--- +type: pattern +title: Asynchronous Event Streaming +description: Asynchronous task distribution, background queue workers, and event streaming with Queue.addQueue() from @quatrain/queue. +tags: + - quatrain + - queue + - workers + - amqp + - rabbitmq + - sqlite +timestamp: 2026-09-17T00:00:00.000Z +category: queues-and-events +status: active +--- + +# Asynchronous Event Streaming + +Quatrain applications offload long-running operations (PDF generation, telemetry ingestion, email dispatch, AI embeddings) to background workers using `@quatrain/queue`. + +--- + +## 🎯 Architectural Principles + +1. **Queue Registry**: Message queues are configured and registered via `Queue.addQueue(adapter, alias, setDefault)`. +2. **Unified Dispatch**: Code dispatches messages using `adapter.send(payload, topic)`, returning the unique message identifier. +3. **Controlled Concurrency**: Workers listen to messages with `adapter.listen(topic, handler, { concurrency })`. + +--- + +## ⚖️ Implementation Patterns + +### 1. Registering an AMQP / RabbitMQ Adapter +```typescript +import { Queue } from "@quatrain/queue"; +import { AmqpQueueAdapter } from "@quatrain/queue-amqp"; + +const amqpAdapter = new AmqpQueueAdapter({ + alias: "rabbit-default", + config: { + host: process.env.RABBITMQ_HOST || "localhost", + port: parseInt(process.env.RABBITMQ_PORT || "5672", 10), + user: process.env.RABBITMQ_USER || "guest", + password: process.env.RABBITMQ_PASSWORD || "guest", + }, +}); + +// Register as the default queue backend +Queue.addQueue(amqpAdapter, "amqp", true); +``` + +--- + +### 2. Dispatching Tasks & Consuming Messages +```typescript +import { Queue } from "@quatrain/queue"; + +interface IngestionTask { + documentId: string; + sourceUrl: string; +} + +// Producer: Dispatch task to queue topic +export async function enqueueDocument(task: IngestionTask): Promise { + const queue = Queue.getQueue(); // Default queue adapter + const messageId = await queue.send(task, "document_tasks"); + return messageId; +} + +// Consumer: Background worker listener +export async function startWorker(): Promise { + const queue = Queue.getQueue(); + + await queue.listen( + "document_tasks", + async (rawPayload: string) => { + const task: IngestionTask = JSON.parse(rawPayload); + console.log(`Processing document ${task.documentId} from ${task.sourceUrl}...`); + // Perform background work... + }, + { concurrency: 5 } // Concurrency limit + ); +} +``` diff --git a/docs/pages/okf/queues-and-events/index.md b/docs/pages/okf/queues-and-events/index.md new file mode 100644 index 00000000..7b3c63b1 --- /dev/null +++ b/docs/pages/okf/queues-and-events/index.md @@ -0,0 +1,23 @@ +--- +type: index +title: Queues & Event Streaming +description: Asynchronous message queuing, background workers, and distributed event streaming in Quatrain Core. +tags: + - quatrain + - queues + - events + - streaming + - amqp + - mqtt +timestamp: 2026-09-17T00:00:00.000Z +category: queues-and-events +status: active +--- + +# Queues & Event Streaming + +Category index for asynchronous background task processing, event dispatch, and pub/sub message brokers via `@quatrain/queue`. + +## Concept Fiches + +- [Asynchronous Event Streaming](asynchronous-event-streaming.md) — Configuring queue adapters (RabbitMQ/AMQP, MQTT, SQLite queue, AWS SQS), publishing typed messages, and building resilient consumer workers. diff --git a/docs/pages/okf/storage-and-assets/_meta.js b/docs/pages/okf/storage-and-assets/_meta.js new file mode 100644 index 00000000..bb3418e0 --- /dev/null +++ b/docs/pages/okf/storage-and-assets/_meta.js @@ -0,0 +1,4 @@ +export default { + "index": "Category Overview", + "unified-object-storage": "Unified Object Storage" +} diff --git a/docs/pages/okf/storage-and-assets/index.md b/docs/pages/okf/storage-and-assets/index.md new file mode 100644 index 00000000..db8d11f7 --- /dev/null +++ b/docs/pages/okf/storage-and-assets/index.md @@ -0,0 +1,22 @@ +--- +type: index +title: Storage & Object Assets +description: Unified object storage abstraction layer across S3/MinIO, Local Filesystem, and Google Cloud Storage. +tags: + - quatrain + - storage + - s3 + - minio + - assets +timestamp: 2026-09-17T00:00:00.000Z +category: storage-and-assets +status: active +--- + +# Storage & Object Assets + +Category index for file uploads, asset management, and cloud object storage adapters via `@quatrain/storage`. + +## Concept Fiches + +- [Unified Object Storage](unified-object-storage.md) — Configuring storage adapters (S3/MinIO, Local FS, Firebase Storage), stream uploads, and signed URLs. diff --git a/docs/pages/okf/storage-and-assets/unified-object-storage.md b/docs/pages/okf/storage-and-assets/unified-object-storage.md new file mode 100644 index 00000000..058ce0f3 --- /dev/null +++ b/docs/pages/okf/storage-and-assets/unified-object-storage.md @@ -0,0 +1,84 @@ +--- +type: pattern +title: Unified Object Storage +description: Abstract object storage interface for S3, MinIO, and local filesystems using Storage.addStorage() from @quatrain/storage. +tags: + - quatrain + - storage + - s3 + - minio + - files +timestamp: 2026-09-17T00:00:00.000Z +category: storage-and-assets +status: active +--- + +# Unified Object Storage + +Quatrain provides a uniform API for file and object storage across cloud environments using `@quatrain/storage`. The application interacts with `Storage.getStorage()`, decoupling business logic from S3 SDKs, local filesystem paths, or MinIO clusters. + +--- + +## 🎯 Architectural Principles + +1. **Storage Registry**: Storage backends are registered via `Storage.addStorage(adapter, alias, setDefault)`. +2. **Stream-First Uploads**: Files are uploaded by passing a `FileType` descriptor and a `Readable` stream to `adapter.create(file, stream)`. +3. **Presigned URLs**: Secure, temporary access URLs are generated through `adapter.getUrl(file, expiresIn, 'read')`. + +--- + +## ⚖️ Implementation Patterns + +### 1. Registering an S3/MinIO Storage Backend +```typescript +import { Storage } from "@quatrain/storage"; +import { S3StorageAdapter } from "@quatrain/storage-s3"; + +const s3Adapter = new S3StorageAdapter({ + alias: "s3-main", + config: { + bucket: process.env.S3_BUCKET || "app-assets", + region: process.env.S3_REGION || "eu-west-1", + endpoint: process.env.S3_ENDPOINT, // Optional custom MinIO endpoint + accesskey: process.env.S3_ACCESS_KEY || "", + secret: process.env.S3_SECRET_KEY || "", + }, +}); + +// Register as the default storage backend +Storage.addStorage(s3Adapter, "s3", true); +``` + +--- + +### 2. Uploading a File & Generating a Presigned URL +```typescript +import { Storage } from "@quatrain/storage"; +import type { FileType } from "@quatrain/storage"; +import { Readable } from "node:stream"; + +export async function uploadUserAsset( + userId: string, + buffer: Buffer, + fileName: string, + contentType: string +): Promise { + const storage = Storage.getStorage(); // Get default storage adapter + + const fileMeta: FileType = { + bucket: "app-assets", + ref: `users/${userId}/${fileName}`, + contentType, + size: buffer.length, + }; + + const stream = Readable.from(buffer); + + // Upload stream + await storage.create(fileMeta, stream); + + // Generate a presigned download URL valid for 3600 seconds (1 hour) + const downloadUrl = await storage.getUrl(fileMeta, 3600, "read"); + return downloadUrl; +} +``` diff --git a/docs/pages/packages/_meta.js b/docs/pages/packages/_meta.js new file mode 100644 index 00000000..10a5fcaf --- /dev/null +++ b/docs/pages/packages/_meta.js @@ -0,0 +1,74 @@ +export default { + "index": "Overview & Catalog", + "ai": "Ai", + "ai-gemini": "Ai Gemini", + "api": "Api", + "api-client": "Api Client", + "api-server": "Api Server", + "api-server-astro": "Api Server Astro", + "api-server-express": "Api Server Express", + "api-xmlrpc": "Api Xmlrpc", + "app": "App", + "auth": "Auth", + "auth-firebase": "Auth Firebase", + "auth-github": "Auth Github", + "auth-http-basic": "Auth Http Basic", + "auth-oidc": "Auth Oidc", + "auth-pocketbase": "Auth Pocketbase", + "auth-rbac": "Auth Rbac", + "auth-supabase": "Auth Supabase", + "backend": "Backend", + "backend-firestore": "Backend Firestore", + "backend-migrations": "Backend Migrations", + "backend-postgres": "Backend Postgres", + "backend-restapi": "Backend Restapi", + "backend-restapi-recipes": "Backend Restapi Recipes", + "backend-sqlite": "Backend Sqlite", + "cache": "Cache", + "cache-redis": "Cache Redis", + "chat": "Chat", + "cli": "Cli", + "cloudwrapper": "Cloudwrapper", + "cloudwrapper-firebase": "Cloudwrapper Firebase", + "cloudwrapper-supabase": "Cloudwrapper Supabase", + "code": "Code", + "code-github": "Code Github", + "core": "Core", + "gateway-upstream-express": "Gateway Upstream Express", + "git-client": "Git Client", + "http": "Http", + "i18n": "I18n", + "i18n-en": "I18n En", + "i18n-es": "I18n Es", + "i18n-fr": "I18n Fr", + "ingestion": "Ingestion", + "ingestion-audio": "Ingestion Audio", + "ingestion-ocr": "Ingestion Ocr", + "ingestion-video": "Ingestion Video", + "ingestion-web": "Ingestion Web", + "log": "Log", + "mdm": "Mdm", + "messaging": "Messaging", + "messaging-firebase": "Messaging Firebase", + "okf": "Okf", + "queue": "Queue", + "queue-amqp": "Queue Amqp", + "queue-aws": "Queue Aws", + "queue-gcp": "Queue Gcp", + "queue-mqtt": "Queue Mqtt", + "queue-sqlite": "Queue Sqlite", + "searchengine": "Searchengine", + "searchengine-qmd": "Searchengine Qmd", + "skills": "Skills", + "state-machine": "State Machine", + "storage": "Storage", + "storage-firebase": "Storage Firebase", + "storage-git": "Storage Git", + "storage-local": "Storage Local", + "storage-s3": "Storage S3", + "storage-supabase": "Storage Supabase", + "studio": "Studio", + "testing": "Testing", + "types": "Types", + "worker": "Worker" +} \ No newline at end of file diff --git a/docs/pages/packages/ai-gemini/_meta.js b/docs/pages/packages/ai-gemini/_meta.js new file mode 100644 index 00000000..6754513a --- /dev/null +++ b/docs/pages/packages/ai-gemini/_meta.js @@ -0,0 +1,8 @@ +export default { + "readme": "Overview", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_ai-gemini.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/ai-gemini/readme.md b/docs/pages/packages/ai-gemini/readme.md index f5a76199..8b307371 100644 --- a/docs/pages/packages/ai-gemini/readme.md +++ b/docs/pages/packages/ai-gemini/readme.md @@ -1,5 +1,7 @@ # @quatrain/ai-gemini +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/ai-gemini ↗](/core/api-reference/modules/_quatrain_ai-gemini.html). + AI adapter for Google Gemini. Integrates the Gemini API into the Quatrain AI ecosystem. ## Purpose diff --git a/docs/pages/packages/ai/_meta.js b/docs/pages/packages/ai/_meta.js new file mode 100644 index 00000000..267e5773 --- /dev/null +++ b/docs/pages/packages/ai/_meta.js @@ -0,0 +1,8 @@ +export default { + "readme": "Overview", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_ai.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/ai/readme.md b/docs/pages/packages/ai/readme.md index 4c7a359f..6e61a7e6 100644 --- a/docs/pages/packages/ai/readme.md +++ b/docs/pages/packages/ai/readme.md @@ -1,5 +1,7 @@ # @quatrain/ai +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/ai ↗](/core/api-reference/modules/_quatrain_ai.html). + AI adapters commons. Provides an abstraction layer for various Artificial Intelligence providers. ## Purpose diff --git a/docs/pages/packages/api-client/_meta.js b/docs/pages/packages/api-client/_meta.js new file mode 100644 index 00000000..2c568df4 --- /dev/null +++ b/docs/pages/packages/api-client/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_api-client.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/api-client/readme.md b/docs/pages/packages/api-client/readme.md index d8b71c57..c1839e85 100644 --- a/docs/pages/packages/api-client/readme.md +++ b/docs/pages/packages/api-client/readme.md @@ -1,5 +1,7 @@ # @quatrain/api-client +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/api-client ↗](/core/api-reference/modules/_quatrain_api-client.html). + The `@quatrain/api-client` package provides an isomorphic, lightweight HTTP client designed specifically for Quatrain APIs. It works seamlessly in both Node.js and Browser environments. ## Features diff --git a/docs/pages/packages/api-server-astro/_meta.js b/docs/pages/packages/api-server-astro/_meta.js new file mode 100644 index 00000000..731052af --- /dev/null +++ b/docs/pages/packages/api-server-astro/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_api-server-astro.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/api-server-astro/readme.md b/docs/pages/packages/api-server-astro/readme.md index 410e5938..59872b87 100644 --- a/docs/pages/packages/api-server-astro/readme.md +++ b/docs/pages/packages/api-server-astro/readme.md @@ -1,5 +1,7 @@ # @quatrain/api-server-astro +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/api-server-astro ↗](/core/api-reference/modules/_quatrain_api-server-astro.html). + Astro Adapter for the Quatrain API Server. It bridges the Quatrain API server interface with the web standard Request/Response API used natively by Astro endpoints. ## Features diff --git a/docs/pages/packages/api-server-express/_meta.js b/docs/pages/packages/api-server-express/_meta.js new file mode 100644 index 00000000..d479cfc6 --- /dev/null +++ b/docs/pages/packages/api-server-express/_meta.js @@ -0,0 +1,9 @@ +export default { + "howto": "HOWTO", + "readme": "Overview", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_api-server-express.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/api-server-express/readme.md b/docs/pages/packages/api-server-express/readme.md new file mode 100644 index 00000000..d61a3639 --- /dev/null +++ b/docs/pages/packages/api-server-express/readme.md @@ -0,0 +1,5 @@ +# @quatrain/api-server-express + +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/api-server-express ↗](/core/api-reference/modules/_quatrain_api-server-express.html). + +Express Adapter for Quatrain API Server diff --git a/docs/pages/packages/api-server/_meta.js b/docs/pages/packages/api-server/_meta.js new file mode 100644 index 00000000..b293b375 --- /dev/null +++ b/docs/pages/packages/api-server/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_api-server.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/api-server/readme.md b/docs/pages/packages/api-server/readme.md index e36eda66..6265965a 100644 --- a/docs/pages/packages/api-server/readme.md +++ b/docs/pages/packages/api-server/readme.md @@ -1,5 +1,7 @@ # @quatrain/api-server-express +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/api-server ↗](/core/api-reference/modules/_quatrain_api-server.html). + The `@quatrain/api-server-express` package provides the backend REST layer for Quatrain, exposing the underlying DataObjects and Backend engines through HTTP endpoints. ## Features diff --git a/docs/pages/packages/api-xmlrpc/_meta.js b/docs/pages/packages/api-xmlrpc/_meta.js new file mode 100644 index 00000000..01db415a --- /dev/null +++ b/docs/pages/packages/api-xmlrpc/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_api-xmlrpc.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/api-xmlrpc/readme.md b/docs/pages/packages/api-xmlrpc/readme.md index 54b896e2..60c8ca5f 100644 --- a/docs/pages/packages/api-xmlrpc/readme.md +++ b/docs/pages/packages/api-xmlrpc/readme.md @@ -1,5 +1,7 @@ # @quatrain/api-xmlrpc +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/api-xmlrpc ↗](/core/api-reference/modules/_quatrain_api-xmlrpc.html). + An XML-RPC client package designed for the Quatrain Core framework. It provides a simple, Promise-based wrapper around the XML-RPC protocol. ## Features diff --git a/docs/pages/packages/api/_meta.js b/docs/pages/packages/api/_meta.js new file mode 100644 index 00000000..1fe0e919 --- /dev/null +++ b/docs/pages/packages/api/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_api.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/api/readme.md b/docs/pages/packages/api/readme.md index ef1518c2..fa4dec5c 100644 --- a/docs/pages/packages/api/readme.md +++ b/docs/pages/packages/api/readme.md @@ -1,5 +1,7 @@ # @quatrain/api +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/api ↗](/core/api-reference/modules/_quatrain_api.html). + The `@quatrain/api` package defines the core types, interfaces, and shared logic for Quatrain's API ecosystem. It acts as the contract between the server-side implementations (like `@quatrain/api-server`) and the client-side consumers (like `@quatrain/api-client`). ## Features diff --git a/docs/pages/packages/app/_meta.js b/docs/pages/packages/app/_meta.js new file mode 100644 index 00000000..13b3e073 --- /dev/null +++ b/docs/pages/packages/app/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_app.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/app/readme.md b/docs/pages/packages/app/readme.md index 1743d349..c566a0e1 100644 --- a/docs/pages/packages/app/readme.md +++ b/docs/pages/packages/app/readme.md @@ -1,5 +1,7 @@ # @quatrain/app +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/app ↗](/core/api-reference/modules/_quatrain_app.html). + Application infrastructure builder for Quatrain. Provides utilities to generate code, scaffold projects and handle core application lifecycle. ## Purpose diff --git a/docs/pages/packages/auth-firebase/_meta.js b/docs/pages/packages/auth-firebase/_meta.js new file mode 100644 index 00000000..59dd0602 --- /dev/null +++ b/docs/pages/packages/auth-firebase/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_auth-firebase.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/auth-firebase/readme.md b/docs/pages/packages/auth-firebase/readme.md index 33046377..589a251e 100644 --- a/docs/pages/packages/auth-firebase/readme.md +++ b/docs/pages/packages/auth-firebase/readme.md @@ -1,5 +1,7 @@ # @quatrain/auth-firebase +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/auth-firebase ↗](/core/api-reference/modules/_quatrain_auth-firebase.html). + The Firebase Authentication adapter for `@quatrain/auth`. ## Introduction diff --git a/docs/pages/packages/auth-github/_meta.js b/docs/pages/packages/auth-github/_meta.js new file mode 100644 index 00000000..d0b7c2d2 --- /dev/null +++ b/docs/pages/packages/auth-github/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_auth-github.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/auth-github/readme.md b/docs/pages/packages/auth-github/readme.md index b65edbca..9fd28d2f 100644 --- a/docs/pages/packages/auth-github/readme.md +++ b/docs/pages/packages/auth-github/readme.md @@ -1,5 +1,7 @@ # @quatrain/auth-github +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/auth-github ↗](/core/api-reference/modules/_quatrain_auth-github.html). + Authentication adapter and pluggable endpoints for GitHub OAuth 2.0 Web Application Flow. ## Installation diff --git a/docs/pages/packages/auth-http-basic/_meta.js b/docs/pages/packages/auth-http-basic/_meta.js new file mode 100644 index 00000000..f1113261 --- /dev/null +++ b/docs/pages/packages/auth-http-basic/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_auth-http-basic.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/auth-http-basic/readme.md b/docs/pages/packages/auth-http-basic/readme.md index 5f52cb02..0d265d08 100644 --- a/docs/pages/packages/auth-http-basic/readme.md +++ b/docs/pages/packages/auth-http-basic/readme.md @@ -1,5 +1,7 @@ # @quatrain/auth-http-basic +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/auth-http-basic ↗](/core/api-reference/modules/_quatrain_auth-http-basic.html). + Basic HTTP Authentication Adapter (RFC 7617) for the Quatrain API Server. ## Features diff --git a/docs/pages/packages/auth-oidc/_meta.js b/docs/pages/packages/auth-oidc/_meta.js new file mode 100644 index 00000000..5a6054db --- /dev/null +++ b/docs/pages/packages/auth-oidc/_meta.js @@ -0,0 +1,8 @@ +export default { + "readme": "Overview", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_auth-oidc.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/auth-oidc/readme.md b/docs/pages/packages/auth-oidc/readme.md index d176d0d0..5eece9cf 100644 --- a/docs/pages/packages/auth-oidc/readme.md +++ b/docs/pages/packages/auth-oidc/readme.md @@ -1,5 +1,7 @@ # @quatrain/auth-oidc +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/auth-oidc ↗](/core/api-reference/modules/_quatrain_auth-oidc.html). + OIDC Authentication provider for Quatrain. ## Purpose diff --git a/docs/pages/packages/auth-pocketbase/_meta.js b/docs/pages/packages/auth-pocketbase/_meta.js new file mode 100644 index 00000000..162805d7 --- /dev/null +++ b/docs/pages/packages/auth-pocketbase/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_auth-pocketbase.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/auth-pocketbase/readme.md b/docs/pages/packages/auth-pocketbase/readme.md index 8b3763e3..f1472575 100644 --- a/docs/pages/packages/auth-pocketbase/readme.md +++ b/docs/pages/packages/auth-pocketbase/readme.md @@ -1,5 +1,7 @@ # @quatrain/auth-pocketbase +> 📦 **API Reference**: Detailed TypeScript documentation, classes, interfaces, and methods are available in the [TypeDoc API Reference for @quatrain/auth-pocketbase ↗](/core/api-reference/modules/_quatrain_auth-pocketbase.html). + PocketBase Authentication adapter for Quatrain. ## Purpose diff --git a/docs/pages/packages/auth-rbac/_meta.js b/docs/pages/packages/auth-rbac/_meta.js new file mode 100644 index 00000000..be29e698 --- /dev/null +++ b/docs/pages/packages/auth-rbac/_meta.js @@ -0,0 +1,9 @@ +export default { + "readme": "Overview", + "howto": "HOWTO", + "api": { + "title": "API Reference ↗", + "href": "/core/api-reference/modules/_quatrain_auth-rbac.html", + "newWindow": true + } +} \ No newline at end of file diff --git a/docs/pages/packages/auth-rbac/howto.md b/docs/pages/packages/auth-rbac/howto.md index f1d98d41..63adb7db 100644 --- a/docs/pages/packages/auth-rbac/howto.md +++ b/docs/pages/packages/auth-rbac/howto.md @@ -1,67 +1,121 @@ -# How-To & Integration Guide : @quatrain/auth-rbac +# Hands-On Workshop : Unified Auth & Fine-Grained RBAC with Quatrain -This guide demonstrates common integration scenarios using `@quatrain/auth-rbac` across Astro, Express, and headless controllers. +Welcome to the end-to-end integration workshop for **`@quatrain/auth-rbac`** and **`@quatrain/auth`**. + +In this step-by-step tutorial, you will learn how to design a complete, production-grade authorization and authentication architecture that decouples identity providers from business permission rules. + +```mermaid +flowchart LR + subgraph "1. Authentication (@quatrain/auth)" + OAuth["OAuth / Supabase / OIDC"] + LDAP["LDAP / Active Directory"] + Basic["HTTP Basic / htpasswd"] + Key["API Key (M2M Agent)"] + end + + subgraph "2. Identity Resolution" + Identity["RbacUserContext
• id
• roles
• subjectType
• attributes"] + end + + subgraph "3. Governance (@quatrain/auth-rbac)" + Engine["RbacPolicyEngine
• Actions CRUD (READ, WRITE, ...)
• Tarpit & M2M Anti-Abuse
• Field-Level Security (FLS)"] + end + + OAuth --> Identity + LDAP --> Identity + Basic --> Identity + Key --> Identity + Identity --> Engine + Engine --> App["Controllers & Web Pages (Astro / Express / React)"] +``` + +--- + +## 🎯 Workshop Overview + +1. **Step 1:** Declare Roles, Semantic Actions, and Field-Level Security (FLS) +2. **Step 2:** Choose & Configure an Authentication Adapter (OAuth/Supabase, LDAP, or htpasswd) +3. **Step 3:** Chain Multiple Authentication Methods (Composite Auth) +4. **Step 4:** Secure Astro SSR & Express API Routes with Automated Tarpitting +5. **Step 5:** Enforce Micro-Security on Data Payloads (`sanitizeRead` & `sanitizeWrite`) +6. **Step 6:** Implement Visual UI Component Guards in Frontend Views --- -## 1. Defining Roles & Tarpit Policies +## 🛠️ Step 1: Declare Roles, Semantic Actions & FLS -Declare role hierarchies, entity field rules, and M2M agent tarpit limits: +Create `src/security/roles.ts` to define your application's security policies: ```typescript import { RbacPolicyEngine, type RoleDefinition } from '@quatrain/auth-rbac' export const appRoles: RoleDefinition[] = [ + // 1. Anonymous Public Visitor + { + id: 'anonymous', + name: 'Anonymous Visitor', + routes: [ + { pattern: '/public/**', actions: ['READ'], access: 'allow' }, + { pattern: '/login', actions: ['*'], access: 'allow' }, + { pattern: '/**', actions: ['*'], access: 'deny' } + ] + }, + + // 2. Authenticated Reader { id: 'reader', - name: 'Reader', + name: 'Standard Reader', + inherits: ['anonymous'], routes: [ - { pattern: '/api/curate', methods: ['GET'], access: 'allow' }, - { pattern: '/public/**', methods: ['*'], access: 'allow' }, - { pattern: '/**', methods: ['*'], access: 'deny' } + { pattern: '/api/documents/**', actions: ['READ'], access: 'allow' }, + { pattern: '/dashboard/**', actions: ['READ'], access: 'allow' } ], entities: { - 'okf-document': { + 'document': { defaultMode: 'readonly', fields: { - internalNotes: 'hidden', - rawLogs: 'hidden' + internalReviewerNotes: 'hidden', // Field stripped on read + draftHistory: 'hidden' } } } }, + + // 3. Curator { id: 'curator', - name: 'Curator', + name: 'Content Curator', inherits: ['reader'], routes: [ - { pattern: '/api/curate', methods: ['POST', 'PUT'], access: 'allow' }, - { pattern: '/api/upload', methods: ['POST'], access: 'allow' } + { pattern: '/api/documents/**', actions: ['READ', 'WRITE', 'UPDATE'], access: 'allow' }, + { pattern: '/api/upload', actions: ['WRITE'], access: 'allow' } ], entities: { - 'okf-document': { + 'document': { defaultMode: 'readwrite', fields: { - soa: 'readonly', - revision: 'readonly', - internalNotes: 'hidden' + soa: 'readonly', // Cannot be overwritten by Curator + publishedAt: 'readonly', + internalReviewerNotes: 'readwrite' } } } }, + + // 4. Autonomous AI Agent / M2M Service { id: 'ai-agent', - name: 'AI Agent Service', + name: 'Autonomous AI Crawler', subjectTypes: ['agent', 'service'], routes: [ - { pattern: '/api/agent/**', methods: ['POST'], access: 'allow' } + { pattern: '/api/ingest/**', actions: ['WRITE', 'EXECUTE'], access: 'allow' } ], tarpit: { enabled: true, burst: 5, maxRequestsPerMinute: 30, - delayMs: 500, - blockDurationMs: 60000 // 1 minute temporary lock on abuse + delayMs: 500, // Injected delay per consecutive violation + blockDurationMs: 60000 // 1-minute lockout on abusive polling } } ] @@ -71,69 +125,208 @@ export const rbacEngine = new RbacPolicyEngine(appRoles) --- -## 2. Using with Astro (SSR & API Middlewares) +## 🔐 Step 2: Connect an Authentication Adapter + +Authentication adapters answer *"Who is the subject?"*, while `@quatrain/auth-rbac` evaluates *"What is this subject allowed to do?"*. + +Choose the adapter that matches your infrastructure: + +### Option A: Supabase / OAuth 2.0 / OpenID Connect + +```typescript +import { SupabaseAuthAdapter } from '@quatrain/auth-supabase' +import type { RbacUserContext } from '@quatrain/auth-rbac' + +export const authAdapter = new SupabaseAuthAdapter({ + config: { + supabaseUrl: process.env.SUPABASE_URL, + supabaseKey: process.env.SUPABASE_ANON_KEY + } +}) + +// Custom identity resolver bridging Supabase token to RbacUserContext +export async function resolveSupabaseUser(req: any): Promise { + const token = req.headers?.authorization?.replace('Bearer ', '') || req.cookies?.['sb-access-token'] + if (!token) return null + + try { + const { data } = await authAdapter.client.auth.getUser(token) + if (!data?.user) return null + + return { + id: data.user.id, + roles: data.user.app_metadata?.roles || [data.user.app_metadata?.role || 'reader'], + subjectType: data.user.app_metadata?.subjectType || 'human', + attributes: { + email: data.user.email, + name: data.user.user_metadata?.full_name + } + } + } catch { + return null + } +} +``` + +### Option B: HTTP Basic / .htpasswd (Legacy or Edge systems) + +```typescript +import { HttpBasicAuthAdapter } from '@quatrain/auth-http-basic' +import type { RbacUserContext } from '@quatrain/auth-rbac' + +export const basicAuth = new HttpBasicAuthAdapter({ + config: { htpasswdPath: '/etc/nginx/.htpasswd' } +}) + +export async function resolveBasicUser(req: any): Promise { + const authHeader = req.headers?.authorization + if (!authHeader?.startsWith('Basic ')) return null + + const user = await basicAuth.authenticateHeader(authHeader) + if (!user) return null + + return { + id: user.username, + roles: user.roles || ['reader'], + subjectType: 'human' + } +} +``` + +--- + +## 🔗 Step 3: Chain Multi-Provider Authentication (Composite Auth) + +For architectures requiring dual-stack authentication (e.g. Bearer OAuth for humans + API Key for autonomous M2M AI Agents): + +```typescript +import type { RbacUserContext } from '@quatrain/auth-rbac' + +export async function compositeUserResolver(req: any): Promise { + // 1. Try M2M API Key header first + const apiKey = req.headers?.['x-api-key'] + if (apiKey) { + if (apiKey === process.env.AGENT_SECRET_KEY) { + return { + id: 'gemini-agent-worker-01', + roles: ['ai-agent'], + subjectType: 'agent', + attributes: { model: 'gemini-2.5-pro' } + } + } + } + + // 2. Fallback to Supabase OAuth Session + return await resolveSupabaseUser(req) +} +``` + +--- + +## 🚀 Step 4: Secure Astro SSR & Express API Routes -In `src/middleware.ts` of your Astro application: +### In Astro SSR (`src/middleware.ts`): ```typescript import { sequence } from 'astro:middleware' import { AstroRbacMiddleware } from '@quatrain/auth-rbac' -import { rbacEngine } from './lib/rbac' +import { rbacEngine } from './security/roles' +import { compositeUserResolver } from './security/auth' const rbacMiddleware = new AstroRbacMiddleware(rbacEngine, { + userResolver: compositeUserResolver, loginRedirectPath: '/login', forbiddenRedirectPath: '/403', - enableTarpitSleep: true + enableTarpitSleep: true // Injects progressive latency on abusive subjects }) -export const onRequest = sequence( - // Your auth session middleware setting context.locals.user ... - rbacMiddleware.handler() -) +export const onRequest = sequence(rbacMiddleware.handler()) ``` -Inside an Astro API endpoint (`src/pages/api/curate.ts`): +--- + +## 🛡️ Step 5: Enforce Micro-Security on Data Payloads (FLS) + +Inside an API Endpoint (`src/pages/api/documents/[id].ts`): ```typescript import type { APIRoute } from 'astro' -export const POST: APIRoute = async ({ request, locals }) => { - const rbac = locals.rbac // Injected automatically - const body = await request.json() +export const GET: APIRoute = async ({ params, locals }) => { + const rbac = locals.rbac // Injected automatically by AstroRbacMiddleware - // 1. Sanitize incoming write payload against curator role - const safeData = rbac.sanitizeWrite('okf-document', body) + // Fetch full document from DB + const rawDocument = await db.documents.findUnique({ where: { id: params.id } }) - // 2. Persist to storage / database - const savedItem = await documentService.save(safeData) + // Sanitize outgoing read payload: automatically strips 'hidden' fields + const safeData = rbac.sanitizeRead('document', rawDocument) - // 3. Sanitize outgoing read payload - const clientResponse = rbac.sanitizeRead('okf-document', savedItem) - - return new Response(JSON.stringify(clientResponse), { + return new Response(JSON.stringify(safeData), { headers: { 'Content-Type': 'application/json' } }) } + +export const PUT: APIRoute = async ({ request, locals }) => { + const rbac = locals.rbac + const incomingPayload = await request.json() + + // Sanitize incoming write payload: automatically strips 'readonly' & 'hidden' fields + const validatedData = rbac.sanitizeWrite('document', incomingPayload) + + const updated = await db.documents.update({ data: validatedData }) + return new Response(JSON.stringify(updated)) +} ``` --- -## 3. Using with Express +## 🎨 Step 6: Visual UI Component Guards in React -```typescript -import express from 'express' -import { ExpressRbacMiddleware } from '@quatrain/auth-rbac' -import { rbacEngine } from './lib/rbac' +In your React / Mantine UI components: -const app = express() -const rbacMiddleware = new ExpressRbacMiddleware(rbacEngine) +```tsx +import React from 'react' -app.use(express.json()) -app.use(rbacMiddleware.handler()) +interface DocumentEditorProps { + document: any + rbacContext: { + isFieldEditable: (entity: string, prop: string) => boolean + isFieldVisible: (entity: string, prop: string) => boolean + } +} -app.post('/api/curate', (req, res) => { - const safeInput = req.rbac.sanitizeWrite('okf-document', req.body) - // ... process safeInput - res.json(req.rbac.sanitizeRead('okf-document', safeInput)) -}) +export function DocumentEditor({ document, rbacContext }: DocumentEditorProps) { + return ( +
+ + + {/* Field visible only to authorized roles */} + {rbacContext.isFieldVisible('document', 'internalReviewerNotes') && ( +