docs
GitHubEN
Zelf hosten

Docker Compose

Appsweet plus een persistente Postgres in één Compose-bestand, voor wie al Zitadel draait.

Compose is de ondersteunde manier om Appsweet te draaien. Het bestand hieronder is het minimale voorbeeld: het geeft je Appsweet plus een persistente Postgres, en verder niets.

LET OP

Dit voorbeeld is geen complete deployment waarop iemand kan inloggen. Het definieert twee services, en geen van beide is een identity provider — APPSWEET_OIDC_ISSUER hieronder wijst naar een placeholder die je moet vervangen door een Zitadel-instantie die je zelf al draait. Vul een echte issuer in en de backend start; laat de placeholder staan en hij start ook, maar niemand kan inloggen. Draai je er nog geen, lees dan eerst "Je hebt nog steeds Zitadel nodig" verderop.

Het Compose-bestand

Zet dit in een docker-compose.yml en draai docker compose up -d. Images worden gekozen op exacte versie plus digest, overgenomen uit het gevalideerde release-manifest voor die versie — er is geen latest-tag, en geen enkele veranderlijke tag geldt als bron van waarheid.

docker-compose.yml
services:
  appsweet:
    image: ghcr.io/blendable-dev/appsweet-backend:0.1.0-beta.1@sha256:<digest-from-the-release-manifest>
    ports: ["3000:3000"]
    # Long form, not `depends_on: [db]` — see "Waiting for Postgres" below.
    depends_on:
      db:
        condition: service_healthy
    environment:
      APPSWEET_DATABASE_URL: postgres://appsweet:secret@db:5432/appsweet
      # The default 127.0.0.1 would not be reachable through the port mapping.
      APPSWEET_BIND_ADDR: 0.0.0.0:3000
      APPSWEET_PUBLIC_BASE_URL: http://localhost:3000
      # Read during startup, not on the first sign-in. Without the pair the
      # container exits before it binds a port. Point both at your issuer.
      APPSWEET_OIDC_ISSUER: https://auth.example.com
      APPSWEET_OIDC_CLIENT_ID: your-client-id

  db:
    # Not plain postgres:16 — the first migration runs
    # CREATE EXTENSION IF NOT EXISTS vector, which the stock image cannot do.
    image: pgvector/pgvector:pg16
    environment:
      POSTGRES_USER: appsweet
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appsweet
    volumes: [pgdata:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appsweet -d appsweet"]
      interval: 5s
      timeout: 5s
      retries: 12

volumes: { pgdata: {} }

Appsweet bewaart zelf geen state op zijn bestandssysteem, dus het heeft geen eigen volume nodig: werkplekdata staat in Postgres en geüploade bestanden in S3-compatibele objectopslag.

Je hebt nog steeds Zitadel nodig

Appsweet beheert geen wachtwoorden, dus de twee services hierboven kunnen niemand inloggen. https://auth.example.com is een placeholder: vervang die door de issuer-URL en client-ID van een Zitadel-instantie die je zelf draait of afneemt, en registreer $APPSWEET_PUBLIC_BASE_URL/auth/callback daar als redirect-URI.

LET OP

Zitadel is vandaag de enige identity provider die Appsweet ondersteunt. Standaard OIDC-discovery spreken is niet genoeg. De backend vraagt elke issuer om de Zitadel-specifieke scope urn:zitadel:iam:user:resourceowner, en bepaalt de werkplek van de ingelogde gebruiker uit drie claims die het onder hun Zitadel-namen opzoekt: urn:zitadel:iam:user:resourceowner:id, …:name en …:primary_domain. Ontbreken die claims, dan wordt de sessie geweigerd: de terugkeer vanaf de provider lijkt te lukken, waarna /v1/me antwoordt met 403 workspace_claims_required en er nooit een werkplek laadt. Precies zover komt een standaardinstallatie van Keycloak, Authentik, Auth0 of Entra ID. Er is geen instelling om claims om te zetten die dat gat dicht — die is nog niet gebouwd.

Heb je er geen, dan levert de Appsweet-repository een stack die Zitadel opstart naast Appsweet, Postgres en Garage-objectopslag, al aan elkaar geknoopt en vastgezet op versies die wij testen: infra/docker-compose.yml. Gebruik die in plaats van het bestand hierboven.

LET OP

Die stack staat hier niet, en losse fragmenten eruit kopiëren werkt niet: hij bouwt de backend en zijn bootstrap-containers uit de build-contexten van de repository zelf, en een Zitadel-instantie heeft een adminaccount, een project, een applicatie en een gebootstrapt client-ID nodig voordat hij ook maar één token uitgeeft. Elk Zitadel-fragment dat kort genoeg is voor deze pagina, zou een fragment zijn dat je niet aan de praat krijgt. De repository is privé tijdens de gesloten bèta, dus vraag om toegang als je de stack nodig hebt en niet hebt.

Wachten op Postgres

De depends_on hierboven staat bewust in zijn lange vorm met condition: service_healthy, gekoppeld aan een healthcheck op db. De korte vorm — depends_on: [db] — wacht alleen tot de database-container start, niet tot PostgreSQL daarbinnen verbindingen accepteert. Op een vers volume duurt dat gat seconden, omdat de image eerst de datadirectory moet initialiseren voordat hij luistert.

Appsweet verbindt één keer met de database tijdens het opstarten en probeert het niet opnieuw, en de service hierboven kent geen restart-policy. Met de korte vorm kan de eerste docker compose up -d op een nieuwe machine de backend dus definitief gestopt achterlaten terwijl Postgres nog initialiseert, en antwoordt curl localhost:3000/ready helemaal niets. Bij de tweede poging lijkt het meestal in orde, en juist daardoor is het makkelijk om dit voor een flake aan te zien en de lange vorm "op te schonen" — doe dat alsjeblieft niet.

pg_isready is de gebruikelijke probe, en is wat de stack van Appsweet zelf gebruikt: hij sluit alleen met nul af zodra de server verbindingen accepteert voor die gebruiker en database.

Waarom pgvector en niet gewoon Postgres

De semantische zoekfunctie van Appsweet bewaart embeddings in dezelfde database als de data, dus de allereerste migratie is CREATE EXTENSION IF NOT EXISTS vector. Op een standaard postgres-image mislukt die opdracht, breken de migraties af en bereikt de backend nooit zijn gereed-status.

pgvector/pgvector:pg16 is maar één manier om daaraan te voldoen. Zet je je eigen Postgres in — een managed dienst, een bestaand cluster, een andere hoofdversie — behandel "pgvector is geïnstalleerd en aan te maken" dan als een harde eis, niet als een detail van de image die hier toevallig gekozen is. De meeste managed providers leveren het als een extensie die je per database aanzet.

Het register is privé tijdens de bèta

Het pakket appsweet-backend is privé zolang de gesloten bèta loopt, dus docker compose pull heeft een ghcr.io-credential nodig met leesrechten op packages. Zonder credential mislukt de pull alsof de image niet bestaat.

LET OP

Dit is het minimum dat opstart, niet het minimum dat bruikbaar is. Er ontbreken nog twee dingen: een Zitadel-issuer, zonder welke niemand inlogt, en een S3-compatibel endpoint voor uploads, zonder welk bestanden helemaal uitstaan. Allebei zijn een ontwikkelsluiproute en geen ondersteunde deployment — zie Configuratie.

Terug naar appsweet.appBewerk deze pagina op GitHub