Add DEPLOYMENT-MODES.md with canonical mode taxonomy. Update CLI.md, DEVELOPING.md, PRODUCT.md, and SPEC-implementation.md with local_trusted/ authenticated nomenclature. Revise humans-and-permissions plan with Better Auth choice, bootstrap flow, unified invite semantics, and expanded criteria. Add implementation guide and additional plan documents for cursor cloud adapter and deployment auth mode consolidation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.9 KiB
Deployment/Auth Mode Consolidation Plan
Status: Proposal
Owner: Server + CLI + UI
Date: 2026-02-23
Goal
Keep Paperclip low-friction while making the mode model simpler and safer:
local_trustedremains the default and easiest path.- one authenticated runtime mode supports both private-network local use and public cloud use.
- onboarding/configure/doctor stay primarily interactive and flagless.
- Board identity is represented by a real user row in the database, with explicit role/membership integration points.
Product Constraints (From Review)
onboarddefault flow is interactive (no flags required).- first mode choice defaults to
local_trusted, with clear UX copy. - authenticated flow gives guidance for private vs public exposure.
doctorshould also be flagless by default (read config and evaluate the selected mode/profile).- do not add backward-compatibility alias layers for abandoned mode names.
- plan must explicitly cover how users/Board are represented in DB and how that affects task assignment and permissions.
Current Implementation Audit (As Of 2026-02-23)
Runtime/Auth
- Runtime deployment modes are currently
local_trusted | cloud_hosted(packages/shared/src/constants.ts). local_trustedactor is currently synthetic:req.actor = { type: "board", userId: "local-board", source: "local_implicit" }(server/src/middleware/auth.ts).- this is not a real auth user row by default.
cloud_hosteduses Better Auth sessions andauthUsersrows (server/src/auth/better-auth.ts,packages/db/src/schema/auth.ts).
Bootstrap/Admin
cloud_hostedrequiresBETTER_AUTH_SECRETand reports bootstrap status frominstance_user_roles(server/src/index.ts,server/src/routes/health.ts).- bootstrap invite acceptance promotes the signed-in user to
instance_admin(server/src/routes/access.ts,server/src/services/access.ts).
Membership/Assignment Integration
- User task assignment requires active
company_membershipsentry for that user (server/src/services/issues.ts). - Local implicit board identity is not automatically a real membership principal; this is a gap for “board as assignable user” semantics.
Proposed Runtime Model
Modes
local_trusted
- no login required
- localhost/loopback only
- optimized for single-operator local setup
authenticated
- login required for human actions
- same auth stack for both private and public deployments
Exposure Policy (Within authenticated)
private
- private-network deployments (LAN, VPN, Tailscale)
- low-friction URL handling (
autobase URL) - strict host allow policy for private targets
public
- internet-facing deployments
- explicit public base URL required
- stricter deployment checks in doctor
This is one authenticated mode with two safety policies, not two different auth systems.
UX Contract
Onboard (Primary Path: Interactive)
Default command remains:
pnpm paperclip onboard
Interactive server step:
- ask mode with default selection
local_trusted - copy for options:
local_trusted: "Easiest for local setup (no login, localhost-only)"authenticated: "Login required; use for private network or public hosting"
- if
authenticated, ask exposure:
private: "Private network access (for example Tailscale), lower setup friction"public: "Internet-facing deployment, stricter security requirements"
- only if
authenticated + public, ask for explicit public URL
Flags are optional power-user overrides, not required for normal setup.
Configure
Default command remains interactive:
pnpm paperclip configure --section server
Same mode/exposure questions and defaults as onboarding.
Doctor
Default command remains flagless:
pnpm paperclip 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/User Data Model Integration (Required)
Requirement
Board must be a real DB user principal so user-centric features (task assignment, membership, audit identity) work consistently.
Target Behavior
local_trusted
- seed/ensure a deterministic local board user row in
authUsersduring setup/startup. - actor middleware uses that real user id instead of synthetic-only identity.
- ensure:
instance_user_rolesincludesinstance_adminfor this user.- company membership can be created/maintained for this user where needed.
authenticated
- Better Auth sign-up creates user row.
- bootstrap/admin flow promotes that real user to
instance_admin. - first company creation flow should ensure creator membership is active.
Why This Matters
assigneeUserIdvalidation checks company membership.- without a real board user + membership path, assigning tasks to board user is inconsistent.
Configuration Contract (Target)
server.mode:local_trusted | authenticatedserver.exposure:private | public(required when mode isauthenticated)auth.baseUrlMode:auto | explicitauth.publicBaseUrl: required whenauthenticated + public
No compatibility aliases for discarded naming variants.
No Backward-Compatibility Layer
This change is a clean cut:
- remove use of old split terminology in code and prompts.
- config schema uses only canonical fields/values above.
- existing dev instances can rerun onboarding or update config once.
Implementation Phases
Phase 1: Shared Schema + Config Surface
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.tsand CLI config types: consume canonical fields only.
Phase 2: CLI Interactive UX
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.
Phase 3: Runtime/Auth Policy
server/src/index.ts: enforce mode-specific startup constraints.server/src/auth/better-auth.ts: implementautovsexplicitbase URL behavior.- host/origin trust helper for
authenticated + private.
Phase 4: Board Principal Integration
- add ensure-board-user startup/setup step:
- real local board user row
- instance admin role row
- ensure first-company creation path grants creator membership.
- remove synthetic-only assumptions where they break user assignment/membership semantics.
Phase 5: UI + Docs
- update UI labels/help text around mode and exposure guidance.
- update docs:
doc/DEPLOYMENT-MODES.mddoc/DEVELOPING.mddoc/CLI.mddoc/SPEC-implementation.md
Test Plan
- config schema tests for canonical mode/exposure/auth fields.
- CLI prompt tests for default interactive selections and copy.
- doctor tests by mode/exposure.
- runtime tests:
- authenticated/private works without explicit URL
- authenticated/public requires explicit URL
- private host policy rejects untrusted hosts
- Board principal tests:
- local_trusted board user exists as real DB user
- board can be assigned tasks via
assigneeUserIdafter membership setup - creator membership behavior for authenticated flows
Acceptance Criteria
pnpm paperclip onboardis interactive-first and defaults tolocal_trusted.- authenticated mode is one runtime mode with
private/publicexposure guidance. pnpm paperclip doctorworks flagless with mode-aware checks.- no extra compatibility aliases for dropped naming variants.
- Board identity is represented by real DB user/role/membership integration points, enabling consistent task assignment and permission behavior.
Verification Gate
Before merge:
pnpm -r typecheck
pnpm test:run
pnpm build