doc/plans/2026-02-23-deployment-auth-mode-consolidation.md
Status: Proposal
Owner: Server + CLI + UI
Date: 2026-02-23
Keep Paperclip low-friction while making the mode model simpler and safer:
local_trusted remains the default and easiest path.onboard default flow is interactive (no flags required).local_trusted, with clear UX copy.doctor should also be flagless by default (read config and evaluate the selected mode/profile).local_trusted | cloud_hosted (packages/shared/src/constants.ts).local_trusted actor is currently synthetic:
req.actor = { type: "board", userId: "local-board", source: "local_implicit" } (server/src/middleware/auth.ts).cloud_hosted uses Better Auth sessions and authUsers rows (server/src/auth/better-auth.ts, packages/db/src/schema/auth.ts).cloud_hosted requires BETTER_AUTH_SECRET and reports bootstrap status from instance_user_roles (server/src/index.ts, server/src/routes/health.ts).instance_admin (server/src/routes/access.ts, server/src/services/access.ts).company_memberships entry for that user (server/src/services/issues.ts).local_trustedauthenticatedauthenticated)privateauto base URL)publicThis is one authenticated mode with two safety policies, not two different auth systems.
Default command remains:
pnpm paperclipai onboard
Interactive server step:
local_trustedlocal_trusted: "Easiest for local setup (no login, localhost-only)"authenticated: "Login required; use for private network or public hosting"authenticated, ask exposure:private: "Private network access (for example Tailscale), lower setup friction"public: "Internet-facing deployment, stricter security requirements"authenticated + public, ask for explicit public URLFlags are optional power-user overrides, not required for normal setup.
Default command remains interactive:
pnpm paperclipai configure --section server
Same mode/exposure questions and defaults as onboarding.
Default command remains flagless:
pnpm paperclipai doctor
Doctor reads configured mode/exposure and applies relevant checks. Optional flags may exist for override/testing, but are not required for normal operation.
Board must be a real DB user principal so user-centric features (task assignment, membership, audit identity) work consistently.
local_trustedauthUsers during setup/startup.instance_user_roles includes instance_admin for this user.authenticatedinstance_admin.assigneeUserId validation checks company membership.server.mode: local_trusted | authenticatedserver.exposure: private | public (required when mode is authenticated)auth.baseUrlMode: auto | explicitauth.publicBaseUrl: required when authenticated + publicNo compatibility aliases for discarded naming variants.
This change is a clean cut:
packages/shared/src/constants.ts: define canonical mode/exposure constants.packages/shared/src/config-schema.ts: add mode/exposure/auth URL fields.server/src/config.ts and CLI config types: consume canonical fields only.cli/src/prompts/server.ts: implement defaulted mode prompt and authenticated exposure guidance copy.cli/src/commands/onboard.ts: keep interactive-first flow; optional overrides only.cli/src/commands/configure.ts: same behavior for server section.cli/src/commands/doctor.ts: mode-aware checks from config, flagless default flow.server/src/index.ts: enforce mode-specific startup constraints.server/src/auth/better-auth.ts: implement auto vs explicit base URL behavior.authenticated + private.doc/DEPLOYMENT-MODES.mddoc/DEVELOPING.mddoc/CLI.mddoc/SPEC-implementation.mdassigneeUserId after membership setuppnpm paperclipai onboard is interactive-first and defaults to local_trusted.private/public exposure guidance.pnpm paperclipai doctor works flagless with mode-aware checks.Before merge:
pnpm -r typecheck
pnpm test:run
pnpm build