Files
multica/deploy/helm/multica/values.yaml
Bohan Jiang 90ddfb04e2 feat(self-host): DISABLE_WORKSPACE_CREATION env var (MUL-2777) (#3441)
* feat(self-host): DISABLE_WORKSPACE_CREATION env var (MUL-2777, #3433)

When self-hosters set DISABLE_WORKSPACE_CREATION=true, POST /api/workspaces
returns 403 for every caller and the UI hides every "Create workspace"
affordance (sidebar, modal, /workspaces/new page, onboarding Step 2). This
closes the gap where ALLOW_SIGNUP=false still let any signed-in user open
an isolated workspace the platform admin couldn't see.

- server: new Config.DisableWorkspaceCreation, gate in CreateWorkspace,
  workspace_creation_disabled in /api/config, Go tests.
- frontend: new workspaceCreationDisabled in configStore, hide sidebar
  entry, swap NewWorkspacePage / CreateWorkspaceModal / onboarding
  StepWorkspace to a "creation disabled, ask for invite" state when the
  flag is on, EN + zh-Hans locale strings.
- ops: .env.example, docker-compose.selfhost, helm values + configmap,
  SELF_HOSTING.md, SELF_HOSTING_ADVANCED.md, environment-variables docs
  (EN + zh).

Co-authored-by: multica-agent <github@multica.ai>

* fix(onboarding): drive create path off workspaceCreationAllowed (#3433)

PR #3441 review: when DISABLE_WORKSPACE_CREATION=true and the user already
has a workspace, StepWorkspace still walked the resume copy (`headline_resume`
/ `lede_resume` mentioning "or start another") and `creatingActive` ignored
the flag, leaving a stale clickable create CTA possible if /api/config
arrived late.

Refactor StepWorkspace to derive a single `workspaceCreationAllowed`
boolean from the config store. It now drives:

- Initial `mode` state (defaults to "existing" when disabled + reusing so
  the CTA is pre-armed for the only valid action).
- `creatingActive` so the footer CTA cannot fall back into the create
  branch even mid-render.
- Eyebrow / headline / lede strings — adds
  `creation_disabled_{eyebrow,headline,lede}_resume` (EN + zh-Hans) for
  the disabled + reusing variant.

Tests: cover the three reachable shapes — flag off + no existing, flag on
+ no existing, flag on + existing.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: J <j@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
2026-05-28 16:42:08 +08:00

135 lines
4.6 KiB
YAML

# -----------------------------------------------------------------------------
# Container images
# -----------------------------------------------------------------------------
images:
backend:
repository: ghcr.io/multica-ai/multica-backend
# Empty defaults to Chart.appVersion. Released OCI charts set appVersion to
# the Git tag (for example v0.3.5), so installs use matching app images.
tag: ""
pullPolicy: IfNotPresent
frontend:
repository: ghcr.io/multica-ai/multica-web
# Empty defaults to Chart.appVersion. Set explicitly to override.
tag: ""
pullPolicy: IfNotPresent
postgres:
repository: pgvector/pgvector
tag: pg17
pullPolicy: IfNotPresent
# -----------------------------------------------------------------------------
# Pre-created Secret with sensitive values. Create it before `helm install`:
#
# kubectl -n <namespace> create secret generic multica-secrets \
# --from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
# --from-literal=POSTGRES_PASSWORD="$(openssl rand -hex 16)" \
# --from-literal=RESEND_API_KEY="" \
# --from-literal=GOOGLE_CLIENT_SECRET="" \
# --from-literal=CLOUDFRONT_PRIVATE_KEY="" \
# --from-literal=MULTICA_DEV_VERIFICATION_CODE=""
#
# The chart references this Secret by name; it does not template it, so real
# values never need to land in git.
# -----------------------------------------------------------------------------
existingSecret: multica-secrets
# -----------------------------------------------------------------------------
# PostgreSQL (pgvector)
# -----------------------------------------------------------------------------
postgres:
database: multica
user: multica
persistence:
size: 10Gi
# Leave empty to use the cluster's default StorageClass.
storageClass: ""
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# -----------------------------------------------------------------------------
# Backend (Go API + WS server)
# -----------------------------------------------------------------------------
backend:
replicas: 1
uploads:
persistence:
size: 5Gi
storageClass: ""
# All non-secret backend env. Secret values come from `existingSecret`.
config:
appEnv: production
appUrl: http://multica.dev.lan
frontendOrigin: http://multica.dev.lan
corsAllowedOrigins: ""
cookieDomain: ""
resendFromEmail: noreply@multica.ai
allowSignup: true
allowedEmails: ""
allowedEmailDomains: ""
# Self-host gate (#3433): set true to make POST /api/workspaces 403 for
# every caller. Bootstrap the workspace with this false, then flip to
# true so users can only join via invitation.
disableWorkspaceCreation: false
googleClientId: ""
googleRedirectUri: http://multica.dev.lan/auth/callback
s3Bucket: ""
s3Region: us-west-2
cloudfrontDomain: ""
cloudfrontKeyPairId: ""
localUploadBaseUrl: http://api.multica.dev.lan
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# -----------------------------------------------------------------------------
# Frontend (Next.js standalone)
#
# The multica-web image bakes REMOTE_API_URL=http://backend:8080 at build time;
# the chart ships an ExternalName Service named "backend" so that bare host
# resolves to the in-cluster backend Service.
# -----------------------------------------------------------------------------
frontend:
replicas: 1
# Compatibility shim for the prebuilt multica-web image.
compatibility:
# When true (default) the chart creates an ExternalName Service literally
# named "backend" so the REMOTE_API_URL=http://backend:8080 baked into the
# web image resolves in-cluster. Because that name is unprefixed, only ONE
# release of this chart can run per namespace, and it will collide with any
# pre-existing Service/backend (helm install then fails without
# --take-ownership). Set to false if you run a web image built with a
# patched REMOTE_API_URL and don't need the alias.
backendAlias: true
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# -----------------------------------------------------------------------------
# Ingress
# -----------------------------------------------------------------------------
ingress:
enabled: true
className: traefik
annotations: {}
frontend:
host: multica.dev.lan
backend:
host: api.multica.dev.lan
# tls:
# - hosts: [multica.dev.lan, api.multica.dev.lan]
# secretName: multica-tls