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>
227 lines
7.9 KiB
Markdown
227 lines
7.9 KiB
Markdown
# 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
|
|
|
|
2. `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
|
|
|
|
2. `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:
|
|
|
|
```sh
|
|
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"
|
|
3. if `authenticated`, ask exposure:
|
|
- `private`: "Private network access (for example Tailscale), lower setup friction"
|
|
- `public`: "Internet-facing deployment, stricter security requirements"
|
|
4. 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:
|
|
|
|
```sh
|
|
pnpm paperclip configure --section server
|
|
```
|
|
|
|
Same mode/exposure questions and defaults as onboarding.
|
|
|
|
## Doctor
|
|
|
|
Default command remains flagless:
|
|
|
|
```sh
|
|
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.
|
|
|
|
2. `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:
|
|
|
|
```sh
|
|
pnpm -r typecheck
|
|
pnpm test:run
|
|
pnpm build
|
|
```
|