Up and running
in minutes.

Pull pre-built images and try Cannelle in three commands. Or check out the source, run it locally, and bake your own images for deployment.

Live demo

Not ready to install anything yet? There is a fully working demo you can explore right now — no sign-up, no email address of your own required. It comes pre-loaded with sample data and resets every day, so you can click around freely without worrying about breaking anything.

// how to log in

email demo@cannelle.io

Enter demo@cannelle.io on the login page and click Send me my magic link. No password, no inbox of your own needed — the link is handled automatically.

→ Read the full walkthrough on the blog

Try it with Docker

The fastest way to see Cannelle running. Pre-built images include everything — the database, both apps, and automatic migrations. No Node.js or PostgreSQL required on your machine.

// you need

Docker 24+Docker Compose v2

// configure docker/.env

The docker/ folder ships with an .env.example. Copy it and set these values before starting:

variable
BASE_URL
JWT_SECRET
HASHID_SALT
ENCRYPTION_KEY
ENCRYPTION_SALT
COMMUNITY_TAG / ATELIER_TAG

For the full variable reference see the configuration docs →

// start the stack

1. go to the docker folder and configure

bash
cd docker
cp .env.example .env
# Edit .env — set your domain, secrets, and SMTP config

2. pull images and start

bash
docker compose up -d

3. open the app

bash
# Community app → http://localhost:3000
# Atelier portal → http://localhost:3001

// what's included

servicedescription
dbPostgreSQL 17 — data persisted in a named volume
migrateRuns prisma migrate deploy once on startup, then exits
communityInternal staff app on port 3000
atelierExternal user portal on port 3001

// useful commands

docker compose up -dStart all services in the background
docker compose downStop all services
docker compose logs -f communityTail logs for the Community app
docker compose restart communityRestart a single service
docker compose pullPull the latest images

Development Setup

Check out the source, run both apps locally with hot reload, and make changes. When you're ready, build your own Docker images and deploy them to your own container repository.

// you need

Node.js 22+npm 10+PostgreSQL 17+Git

// get started

1. clone the repository

bash
git clone https://github.com/cannelleio/community.git
cd cannelle-sveltekit

2. install dependencies

bash
npm install

3. configure environment

bash
cp .env.example .env
# Edit .env — at minimum set DATABASE_URL and the four secret variables

4. generate secrets

bash
openssl rand -hex 32   # JWT_SECRET
openssl rand -hex 16   # HASHID_SALT
openssl rand -hex 32   # ENCRYPTION_KEY
openssl rand -hex 16   # ENCRYPTION_SALT

5. generate the Prisma client and run migrations

bash
npm run db:generate
npm run db:migrate

6. start dev servers

bash
npm run dev
# Community app → http://localhost:5173
# Atelier portal  → http://localhost:5174

// tip

Email in development: SMTP is optional. Magic links are printed to the server console if SMTP is not configured.

For the full variable reference — required fields, SMTP, S3, Atelier, and more — see the configuration docs →

// useful dev commands

npm run devStart dev servers for all workspaces
npm run dev --workspace=@cannelle/communityDev server for Community only
npm run checkTypeScript validation across the monorepo
npm run svelte-checkSvelte syntax and type checking
npm run lintESLint
npm run formatPrettier auto-format
npm run testRun all tests
npm run buildProduction build for all packages and apps

// build your own docker images

Once you're happy with your changes, build production images and push them to your registry. Use the same Docker Compose setup to deploy.

bash
npm run build

# Build and tag images
docker build -f docker/community.Dockerfile -t your-registry/cannelle-community:latest .
docker build -f docker/atelier.Dockerfile   -t your-registry/cannelle-atelier:latest .

# Push and deploy
docker push your-registry/cannelle-community:latest
docker push your-registry/cannelle-atelier:latest

// code conventions

Svelte 5 runes ($state, $derived, $effect) — no legacy $: or stores
TypeScript strict mode throughout
Prettier with tabs, single quotes, no trailing commas
Tailwind CSS 4 for styling
Use +page.server.ts for data loading (direct Prisma via @cannelle/core)
Use +server.ts API routes for client-side mutations only
Validate all API inputs with Joi at boundaries
Shared business logic → packages/core; shared UI → packages/ui

Database

Cannelle requires PostgreSQL 17. The schema is managed with Prisma. When using Docker Compose, migrations run automatically on startup. For an external or managed database, run them once manually before your first deploy.

// run migrations against an external database

bash
DATABASE_URL="postgresql://user:password@your-host:5432/cannelle?schema=public" \
  npx prisma migrate deploy --schema=packages/core/prisma/schema.prisma

// useful database commands

npm run db:generateRegenerate the Prisma client after schema changes
npm run db:migrateApply pending migrations to the database
npm run db:pushPush schema directly (dev only — skips migration history)
npm run db:studioOpen Prisma Studio to browse data in a browser UI

Production Deployment

We recommend Docker Compose with a reverse proxy. It handles TLS termination, restarts on failure, and keeps the database isolated behind the compose network. The checklist below covers everything to address before going live.

// recommended: docker compose + reverse proxy

bash
docker compose -f docker-compose.yml -f docker-compose.proxy.yml up -d

The proxy compose file adds Nginx with automatic Let's Encrypt certificates. Point your domain to the server, set BASE_URL in your .env, and you're done.

// go-live checklist

Domain and DNS — Point your domain (e.g. app.example.com) to your server's IP address before starting.

TLS / HTTPS — Run behind Nginx, Caddy, or Traefik for HTTPS. The proxy compose file includes a Let's Encrypt config.

Secrets management — Use Docker secrets or a secrets manager — never commit your .env to version control.

Database backups — Schedule automated pg_dump or use your cloud provider's managed backup feature.

Upload persistence — Always mount the uploads volume. Files are lost on container restart without it.

S3 for file storage — Consider S3 over local storage for durability and scalability in production.

Resource allocation — Puppeteer (PDF generation) requires ~512 MB RAM. Allocate at least 1 GB to each app container.

WebSocket support — Ensure your reverse proxy forwards upgrade headers for the Community app WebSocket connection.

// minimal nginx config

nginx
server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate     /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

// alternative: manual node.js

If you prefer not to use Docker in production, build the apps and run them directly with Node under PM2 or systemd.

bash
npm install
npm run db:generate
npm run db:migrate
npm run build

# Start Community app
node apps/community/build/index.js

# Start Atelier portal (separate process / PM2 / systemd)
node apps/atelier/build/index.js
// need more detail?

The full documentation covers architecture, API reference, configuration, and advanced deployment options.