cufflink-cli 0.11.6

CLI for the Cufflink CRUD microservice platform — deploy, init, and manage services
cufflink-cli-0.11.6 is not a library.

Cufflink

Deploy CRUD microservices in seconds. Define your data model in Rust, run cufflink deploy, and get a full REST API with PostgreSQL persistence, automatic schema migrations, NATS events, and multi-tenant isolation.

Architecture

┌─────────────┐     ┌──────────────┐     ┌───────────┐
│  Cufflink   │────>│   Platform   │────>│ PostgreSQL│
│  CLI        │     │   (Axum)     │     │           │
└─────────────┘     └──────┬───────┘     └───────────┘
                           │
┌─────────────┐     ┌──────┴───────┐     ┌───────────┐
│  Web Admin  │────>│  Dynamic     │────>│   NATS    │
│  (Next.js)  │     │  CRUD Router │     │ JetStream │
└─────────────┘     └──────────────┘     └───────────┘

SDK#[derive(Table)] proc macros generate JSON manifests from Rust structs CLIcufflink deploy captures the manifest and POSTs it to the platform Platform — Applies schema migrations, registers CRUD routes, publishes events Web Admin — Dashboard for browsing services, data, schemas, and deployments

Quick Start

Prerequisites

  • Rust 1.70+
  • Docker & Docker Compose

1. Start the platform

docker compose up -d

This starts PostgreSQL, NATS, Keycloak, the Cufflink platform, and the web admin.

  • Platform API: http://localhost:8080
  • Web Admin: http://localhost:3000
  • NATS Monitoring: http://localhost:8222

2. Define a service

// examples/todo-service/src/main.rs
use cufflink::prelude::*;

#[derive(Table, Serialize, Deserialize, Clone)]
#[table(name = "todos")]
pub struct Todo {
    #[key] pub id: Uuid,
    pub title: String,
    pub completed: bool,
    #[timestamp] pub created_at: DateTime<Utc>,
    #[timestamp] pub updated_at: DateTime<Utc>,
}

cufflink::service! {
    name: "todo-service",
    tables: [Todo],
}

For services with authentication and permissions:

#[derive(Table, Serialize, Deserialize, Clone)]
#[table(name = "todos", auth_required, permission_area = "todos")]
pub struct Todo { /* ... */ }

cufflink::service! {
    name: "todo-service",
    tables: [Todo],
    authorization: [
        areas: [("todos", ["create", "view", "edit", "delete"])],
        default_roles: [
            ("admin", "Full access", ["todos:*"]),
            ("viewer", "Read-only", ["todos:view"]),
        ],
    ],
}

3. Deploy

cd examples/todo-service
cargo run -p cufflink -- deploy

4. Use the API

# Create
curl -X POST http://localhost:8080/svc/default/todo-service/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Buy groceries", "completed": false}'

# List (with filtering, sorting, search, pagination)
curl "http://localhost:8080/svc/default/todo-service/todos?sort=-created_at&per_page=10"

# Search
curl "http://localhost:8080/svc/default/todo-service/todos?search=groceries"

# Filter
curl --get http://localhost:8080/svc/default/todo-service/todos \
  --data-urlencode 'filter=[{"n":"completed","f":"=","v":"false"}]'

# Get by ID
curl http://localhost:8080/svc/default/todo-service/todos/{id}

# Update
curl -X PUT http://localhost:8080/svc/default/todo-service/todos/{id} \
  -H "Content-Type: application/json" \
  -d '{"completed": true}'

# Delete
curl -X DELETE http://localhost:8080/svc/default/todo-service/todos/{id}

SDK Reference

Table Attributes

Attribute Description
#[table(name = "...")] SQL table name (required)
#[table(auth_required)] Require authentication for CRUD access
#[table(permission_area = "...")] Enable CRUD permission enforcement (e.g. "staff" checks staff:view, staff:create, etc.)
#[key] Primary key (auto-generated UUID)
#[timestamp] Auto-generated timestamp (DEFAULT now())
#[default("value")] Default value
#[references("table.column")] Foreign key reference
#[on_delete("cascade")] FK delete action: cascade, set_null, restrict, no_action
#[hooks(before_create = "...")] CRUD lifecycle hooks — call WASM handlers before/after operations

Supported Types

Rust Type SQL Type
Uuid UUID
String TEXT
bool BOOLEAN
i32 INTEGER
i64 BIGINT
f32 REAL
f64 DOUBLE PRECISION
DateTime<Utc> TIMESTAMPTZ
NaiveDate DATE
Value JSONB
Option<T> Nullable version of T

Foreign Keys

#[derive(Table, Serialize, Deserialize, Clone)]
#[table(name = "comments")]
pub struct Comment {
    #[key] pub id: Uuid,
    #[references("posts.id")]
    #[on_delete("cascade")]
    pub post_id: Uuid,
    pub body: String,
}

CLI Reference

Command Description
cufflink init <name> Scaffold a new service project
cufflink deploy Deploy the service in the current directory
cufflink deploy --tenant <slug> Deploy to a specific tenant
cufflink rollback Rollback to previous version
cufflink status Show service status and endpoints
cufflink services List all deployed services
cufflink login Authenticate with the platform
cufflink test Run tests (hash-based, only changed)
cufflink seed Seed data from a JSON file
cufflink config list List service config values
cufflink backup schema Show tables, columns, FK dependencies
cufflink backup export Export service data to S3-backed NDJSON
cufflink backup restore <file> Restore from a backup file
cufflink backup list List completed backups
cufflink backup jobs List all backup/restore jobs
cufflink install <source> Install a cufflink package
cufflink workspace deploy Deploy all workspace services
cufflink workspace deploy --parallel Deploy all services concurrently
cufflink workspace test Run tests for all workspace services
cufflink workspace status Show status of all workspace services
cufflink workspace preview create Create a preview environment
cufflink workspace preview destroy Destroy a preview environment
cufflink tenants create Create a new tenant (platform admin)
cufflink tenants create-api-key Create platform admin API key
cufflink openapi Print OpenAPI spec
cufflink generate-client Generate TypeScript client

See docs/ for detailed guides on workspace, backup, packages, observability, authentication, and more.

Configuration

Env Var Default Description
CUFFLINK_API_URL http://localhost:8080 Platform API URL
CUFFLINK_TENANT default Tenant slug
CUFFLINK_KEYCLOAK_URL http://localhost:8180 Keycloak URL
CUFFLINK_CLIENT_ID cufflink-cli Keycloak client ID

API Endpoints

Management API

Method Path Description
GET /health Health check
POST /api/auth/bootstrap Create first API key (no auth)
POST /api/auth/api-keys Create API key (requires auth)
GET /api/auth/me Get authenticated user info
GET /api/services List all services
GET /api/services/{id} Get service details
DELETE /api/services/{id} Delete a service
POST /api/services/deploy Deploy a service
GET /api/services/{id}/deployments Deployment history
POST /api/services/{id}/rollback Rollback deployment
GET /api/services/{id}/openapi.json Auto-generated OpenAPI spec
POST /api/services/{id}/wasm Upload WASM module
GET /api/services/{id}/wasm/status WASM runtime status
GET /api/services/{id}/schema Table schema and FK info
POST /api/services/{id}/backup/export Start backup export job
POST /api/services/{id}/backup/restore Start backup restore job
GET /api/services/{id}/backup/jobs List backup jobs
GET /api/services/{id}/backup/jobs/{jid} Get job status
POST /api/services/{id}/backup/jobs/{jid}/cancel Cancel job
GET /api/services/{id}/backup/jobs/{jid}/download Download export
POST /api/platform/api-keys Create platform admin API key
GET /api/platform/api-keys List platform admin API keys
DELETE /api/platform/api-keys/{id} Revoke platform admin API key

Dynamic CRUD Routes

Method Path Description
GET /svc/{tenant}/{service}/{table} List records
POST /svc/{tenant}/{service}/{table} Create record
GET /svc/{tenant}/{service}/{table}/{id} Get record
PUT /svc/{tenant}/{service}/{table}/{id} Update record
DELETE /svc/{tenant}/{service}/{table}/{id} Delete record

Query Parameters

Parameter Example Description
page ?page=2 Page number
per_page ?per_page=25 Items per page (max 200)
sort ?sort=-created_at,title Sort (prefix - for DESC)
search ?search=hello Full-text search across text columns
filter ?filter=[{"n":"status","f":"=","v":"active"}] JSON filter array
select ?select=id,title Column selection

Filter Operators

=, !=, >, <, >=, <=, LIKE, ILIKE, IN, IS NULL, IS NOT NULL

Authentication

Bootstrap (first-time setup)

curl -X POST http://localhost:8080/api/auth/bootstrap \
  -H "Content-Type: application/json" \
  -d '{"tenant_name": "My Org", "tenant_slug": "my-org"}'

Using API Keys

curl -H "Authorization: ApiKey ck_..." http://localhost:8080/api/auth/me

CLI Login

cufflink login

Project Structure

cufflink/
├── platform/          # Axum-based platform server
├── worker/            # WASM worker process (scales independently)
├── cli/               # CLI tool (cufflink binary)
├── sdk/               # User-facing SDK crate
├── sdk-macros/        # Proc macros (#[derive(Table)], service!{})
├── types/             # Shared types (ServiceManifest, etc.)
├── web/               # Next.js web admin dashboard
├── examples/
│   ├── todo-service/  # Simple single-table example
│   └── blog-service/  # Multi-table example with FK
├── docker-compose.yml
├── Dockerfile.platform
└── Dockerfile.worker

Development

# Build everything
cargo build --workspace

# Run tests
cargo test --workspace

# Run platform locally (requires Docker services)
docker compose up -d postgres nats keycloak
cargo run -p cufflink-platform

# Run web admin locally
cd web && npm install && npm run dev

License

MIT