dev: add Kratos + Mailpit local-dev stack
Backend CI / Test (push) Has been cancelled
Backend CI / Contract Tests (push) Has been cancelled
Backend CI / Lint (push) Has been cancelled
Backend CI / Secret Scanning (push) Has been cancelled
Backend CI / Build (push) Has been cancelled

docker-compose.dev.yml gains a Kratos identity service (public :4433 / admin
:4434) and a Mailpit SMTP catcher for local onboarding email codes, plus a
postgres-init mount. deploy/local/kratos/ holds the local Kratos config +
identity schema (placeholder dev cookie secret only). Supports the local
backend the XCUITest suite seeds against.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-06-09 00:11:06 -05:00
parent b54493f785
commit 225fb1306b
3 changed files with 200 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
{
"$id": "https://honeydue.app/identity.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "honeyDue user",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"title": "Email",
"minLength": 3,
"maxLength": 320,
"ory.sh/kratos": {
"credentials": {
"password": { "identifier": true },
"code": { "identifier": true, "via": "email" },
"totp": { "account_name": true }
},
"verification": { "via": "email" },
"recovery": { "via": "email" }
}
},
"name": {
"type": "object",
"title": "Name",
"properties": {
"first": { "type": "string", "title": "First name", "maxLength": 100 },
"last": { "type": "string", "title": "Last name", "maxLength": 100 }
}
}
},
"required": ["email"],
"additionalProperties": false
}
}
}
+101
View File
@@ -0,0 +1,101 @@
version: v1.3.0
serve:
public:
base_url: http://localhost:4433/
cors:
enabled: true
allowed_origins:
- http://localhost
- http://localhost:3000
- http://localhost:8000
- http://127.0.0.1
allowed_methods: [GET, POST, PUT, PATCH, DELETE, OPTIONS]
allowed_headers: [Authorization, Content-Type, X-Session-Token, Cookie]
exposed_headers: [Content-Type, Set-Cookie]
allow_credentials: true
admin:
base_url: http://kratos:4434/
selfservice:
default_browser_return_url: http://localhost:8000/
allowed_return_urls:
- http://localhost:8000
- honeydue://callback
methods:
password:
enabled: true
config:
min_password_length: 8
identifier_similarity_check_enabled: false
code:
enabled: true
oidc:
enabled: false
flows:
error:
ui_url: http://localhost:8000/auth/error
login:
ui_url: http://localhost:8000/auth/login
lifespan: 10m
registration:
ui_url: http://localhost:8000/auth/registration
lifespan: 10m
after:
password:
hooks:
- hook: session
verification:
enabled: true
ui_url: http://localhost:8000/auth/verification
use: code
after:
default_browser_return_url: http://localhost:8000/
recovery:
enabled: true
ui_url: http://localhost:8000/auth/recovery
use: code
settings:
ui_url: http://localhost:8000/auth/settings
privileged_session_max_age: 15m
logout:
after:
default_browser_return_url: http://localhost:8000/
log:
level: debug
format: text
leak_sensitive_values: true
secrets:
cookie:
- local-dev-cookie-secret-please-change-this-32chars
cipher:
- 0123456789abcdef0123456789abcdef
ciphers:
algorithm: xchacha20-poly1305
hashers:
algorithm: bcrypt
bcrypt:
cost: 8
identity:
default_schema_id: honeydue
schemas:
- id: honeydue
url: file:///etc/config/kratos/identity.schema.json
courier:
smtp:
connection_uri: smtp://mailpit:1025/?disable_starttls=true
from_address: noreply@localhost
from_name: honeyDue Local
session:
lifespan: 720h
cookie:
same_site: Lax
+60
View File
@@ -14,6 +14,7 @@ services:
POSTGRES_DB: ${POSTGRES_DB:-honeydue} POSTGRES_DB: ${POSTGRES_DB:-honeydue}
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
- ./deploy/local/postgres-init:/docker-entrypoint-initdb.d:ro
ports: ports:
- "${DB_PORT:-5433}:5432" # 5433 externally to avoid conflicts with local postgres - "${DB_PORT:-5433}:5432" # 5433 externally to avoid conflicts with local postgres
healthcheck: healthcheck:
@@ -91,6 +92,10 @@ services:
# Storage encryption # Storage encryption
STORAGE_ENCRYPTION_KEY: ${STORAGE_ENCRYPTION_KEY} STORAGE_ENCRYPTION_KEY: ${STORAGE_ENCRYPTION_KEY}
# Kratos (identity service)
KRATOS_PUBLIC_URL: "http://kratos:4433"
KRATOS_ADMIN_URL: "http://kratos:4434"
volumes: volumes:
- ./push_certs:/certs:ro - ./push_certs:/certs:ro
- ./uploads:/app/uploads - ./uploads:/app/uploads
@@ -99,6 +104,8 @@ services:
condition: service_healthy condition: service_healthy
redis: redis:
condition: service_healthy condition: service_healthy
kratos:
condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8000/api/health/"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8000/api/health/"]
interval: 30s interval: 30s
@@ -184,6 +191,59 @@ services:
networks: networks:
- honeydue-network - honeydue-network
# Mailpit — local SMTP catcher (for Kratos email codes during onboarding)
mailpit:
image: axllent/mailpit:latest
container_name: honeydue-mailpit
restart: unless-stopped
ports:
- "${MAILPIT_SMTP_PORT:-1025}:1025"
- "${MAILPIT_HTTP_PORT:-8025}:8025"
networks:
- honeydue-network
# Kratos schema migration (one-shot, runs before kratos starts)
kratos-migrate:
image: oryd/kratos:v1.3.0
container_name: honeydue-kratos-migrate
command: ["migrate", "sql", "-e", "--yes"]
environment:
DSN: "postgres://${POSTGRES_USER:-honeydue}:${POSTGRES_PASSWORD:-honeydue_dev_password}@db:5432/kratos?sslmode=disable"
depends_on:
db:
condition: service_healthy
networks:
- honeydue-network
restart: "no"
# Ory Kratos — identity service
kratos:
image: oryd/kratos:v1.3.0
container_name: honeydue-kratos
restart: unless-stopped
command: ["serve", "--config", "/etc/config/kratos/kratos.yml", "--watch-courier", "--dev"]
ports:
- "${KRATOS_PUBLIC_PORT:-4433}:4433"
- "${KRATOS_ADMIN_PORT:-4434}:4434"
environment:
DSN: "postgres://${POSTGRES_USER:-honeydue}:${POSTGRES_PASSWORD:-honeydue_dev_password}@db:5432/kratos?sslmode=disable"
LOG_LEVEL: "debug"
volumes:
- ./deploy/local/kratos:/etc/config/kratos:ro
depends_on:
kratos-migrate:
condition: service_completed_successfully
mailpit:
condition: service_started
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:4434/health/ready"]
interval: 10s
timeout: 5s
retries: 10
start_period: 10s
networks:
- honeydue-network
# Dozzle — lightweight real-time log viewer # Dozzle — lightweight real-time log viewer
dozzle: dozzle:
image: amir20/dozzle:latest image: amir20/dozzle:latest