feat: add FRANCIS_HOST to connect to a standalone Francis runtime

FRANCIS_HOST decides where the Francis actor runtime lives. When it is
empty or set to "embedded" (the default) nothing changes: Pocket ID starts
the runtime inside its own process, backed by its own database. Any other
value is the address, or a comma-separated list of addresses, of a
standalone Francis runtime; Pocket ID then connects to it as a remote actor
host and starts no embedded runtime.

Connecting to a standalone runtime also needs FRANCIS_HOST_PSK, the host
bootstrap pre-shared key the runtime is configured with, and optionally
FRANCIS_CA, the PEM-encoded cluster CA to pin before the first connection.
Without a pinned CA Francis trusts the certificate it is served on first
use, and warns about it.

The actor host is now held as the topology-agnostic francis host.Host
interface, since the concrete type depends on the configuration. The
commands that reach the actor data through Pocket ID's own database
(export, import, and one-time-access-token) fail with an explicit error
when a standalone runtime owns that data instead, rather than silently
operating on the wrong store.
This commit is contained in:
Alessandro (Ale) Segala
2026-08-31 05:26:59 +00:00
parent 7c79a9e14b
commit 600ca3f31f
23 changed files with 458 additions and 84 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/italypaleale/francis/host/local"
francishost "github.com/italypaleale/francis/host"
"gorm.io/gorm"
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
@@ -43,7 +43,7 @@ type ScimSyncScheduler interface {
type Dependencies struct {
DB *gorm.DB
Actors *local.Host
Actors francishost.Host
HTTPClient *http.Client
FileStorage storage.FileStorage