Rename all workspace packages from @paperclip/* to @paperclipai/* and the CLI binary from `paperclip` to `paperclipai` in preparation for npm publishing. Bump CLI version to 0.1.0 and add package metadata (description, keywords, license, repository, files). Update all imports, documentation, user-facing messages, and tests accordingly. 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 paperclipai 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 paperclipai configure --section server
Same mode/exposure questions and defaults as onboarding.
Doctor
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/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 paperclipai onboardis interactive-first and defaults tolocal_trusted.- authenticated mode is one runtime mode with
private/publicexposure guidance. pnpm paperclipai 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