Files
paperclip/doc/plans/deployment-auth-mode-consolidation.md
Forgotten 21c506dcae docs: add deployment modes documentation and update plans
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>
2026-02-23 14:41:35 -06:00

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:

  1. local_trusted remains the default and easiest path.
  2. one authenticated runtime mode supports both private-network local use and public cloud use.
  3. onboarding/configure/doctor stay primarily interactive and flagless.
  4. Board identity is represented by a real user row in the database, with explicit role/membership integration points.

Product Constraints (From Review)

  1. onboard default flow is interactive (no flags required).
  2. first mode choice defaults to local_trusted, with clear UX copy.
  3. authenticated flow gives guidance for private vs public exposure.
  4. doctor should also be flagless by default (read config and evaluate the selected mode/profile).
  5. do not add backward-compatibility alias layers for abandoned mode names.
  6. 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_trusted actor 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_hosted uses Better Auth sessions and authUsers rows (server/src/auth/better-auth.ts, packages/db/src/schema/auth.ts).

Bootstrap/Admin

  • cloud_hosted requires BETTER_AUTH_SECRET and reports bootstrap status from instance_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_memberships entry 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

  1. local_trusted
  • no login required
  • localhost/loopback only
  • optimized for single-operator local setup
  1. authenticated
  • login required for human actions
  • same auth stack for both private and public deployments

Exposure Policy (Within authenticated)

  1. private
  • private-network deployments (LAN, VPN, Tailscale)
  • low-friction URL handling (auto base URL)
  • strict host allow policy for private targets
  1. 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:

  1. ask mode with default selection local_trusted
  2. copy for options:
  • local_trusted: "Easiest for local setup (no login, localhost-only)"
  • authenticated: "Login required; use for private network or public hosting"
  1. if authenticated, ask exposure:
  • private: "Private network access (for example Tailscale), lower setup friction"
  • public: "Internet-facing deployment, stricter security requirements"
  1. 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

  1. local_trusted
  • seed/ensure a deterministic local board user row in authUsers during setup/startup.
  • actor middleware uses that real user id instead of synthetic-only identity.
  • ensure:
    • instance_user_roles includes instance_admin for this user.
    • company membership can be created/maintained for this user where needed.
  1. 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

  • assigneeUserId validation checks company membership.
  • without a real board user + membership path, assigning tasks to board user is inconsistent.

Configuration Contract (Target)

  • server.mode: local_trusted | authenticated
  • server.exposure: private | public (required when mode is authenticated)
  • auth.baseUrlMode: auto | explicit
  • auth.publicBaseUrl: required when authenticated + 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.ts and 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: implement auto vs explicit base 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.md
    • doc/DEVELOPING.md
    • doc/CLI.md
    • doc/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 assigneeUserId after membership setup
    • creator membership behavior for authenticated flows

Acceptance Criteria

  1. pnpm paperclip onboard is interactive-first and defaults to local_trusted.
  2. authenticated mode is one runtime mode with private/public exposure guidance.
  3. pnpm paperclip doctor works flagless with mode-aware checks.
  4. no extra compatibility aliases for dropped naming variants.
  5. 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