mirror of
https://github.com/Dvorinka/Primora.git
synced 2026-10-28 07:41:23 +00:00
feat: instance administration, bootstrap admin, and managed-tier OAuth gate
Self-hosted instances are now email/password only — OAuth providers (GitHub/Google/Discord/Microsoft) activate solely when PRIMORA_MANAGED=true, reserved for the future hosted tier. Sign-up lifecycle: the first public sign-up becomes the instance admin; after bootstrap, sign-up closes by default. A better-auth databaseHook gates only /sign-up/email, so admin-created users and OAuth flows bypass it. The login page reads GET /instance/public to hide the sign-up tab, show the bootstrap notice, and render only the providers the instance offers. Instance settings live in core.settings (migration 00010) and resolve in-app > env > built-in default, cached 15s. Platform admins (better-auth user.role) manage sign-up, mail transport, and rate limits via GET/PUT/DELETE /instance/settings or the new Settings → Instance tab. Secret values are AES-256-GCM encrypted at rest with PRIMORA_ENCRYPTION_KEY, never returned by the API, and decrypted by the auth service at send time. Auth service reads the same settings table for the sign-up gate and mail config, so in-app changes take effect without a restart. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
1214108d6b
commit
c6166de886
36 files changed
+1729
-109
No files matched your search
@@ -17,6 +17,7 @@ tags:
|
||||
- name: Integrations
|
||||
- name: Webhooks
|
||||
- name: Automation
|
||||
- name: Instance
|
||||
paths:
|
||||
/health/liveness:
|
||||
get:
|
||||
@@ -67,6 +68,87 @@ paths:
|
||||
$ref: "#/components/schemas/MeResponse"
|
||||
"401":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
/instance/public:
|
||||
get:
|
||||
tags: [Instance]
|
||||
operationId: getInstancePublic
|
||||
summary: Public instance state for the login page — no auth required
|
||||
responses:
|
||||
"200":
|
||||
description: Public instance configuration
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InstancePublicConfig"
|
||||
/instance/settings:
|
||||
get:
|
||||
tags: [Instance]
|
||||
operationId: listInstanceSettings
|
||||
summary: List instance settings (platform admin only)
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Resolved instance settings
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InstanceSettingsResponse"
|
||||
"401":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
"403":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
/instance/settings/{key}:
|
||||
put:
|
||||
tags: [Instance]
|
||||
operationId: updateInstanceSetting
|
||||
summary: Set an instance setting override (platform admin only)
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: key
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UpdateInstanceSettingRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Setting stored
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InstanceSetting"
|
||||
"400":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
"403":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
"404":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
delete:
|
||||
tags: [Instance]
|
||||
operationId: deleteInstanceSetting
|
||||
summary: Revert a setting to its env/default value (platform admin only)
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: key
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"204":
|
||||
description: Setting reverted
|
||||
"403":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
"404":
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
/bootstrap:
|
||||
post:
|
||||
tags: [Platform]
|
||||
@@ -1952,6 +2034,54 @@ components:
|
||||
type: string
|
||||
required: [code, message]
|
||||
required: [status, error]
|
||||
InstancePublicConfig:
|
||||
type: object
|
||||
properties:
|
||||
signup_enabled:
|
||||
type: boolean
|
||||
description: Whether public sign-up is open (bootstrap always allowed)
|
||||
bootstrap_required:
|
||||
type: boolean
|
||||
description: True when no user exists yet — first sign-up becomes instance admin
|
||||
social_providers:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Enabled OAuth providers — empty on self-hosted
|
||||
required: [signup_enabled, bootstrap_required, social_providers]
|
||||
InstanceSetting:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum: [bool, int, string]
|
||||
secret:
|
||||
type: boolean
|
||||
is_set:
|
||||
type: boolean
|
||||
description: True when an in-app override exists
|
||||
source:
|
||||
type: string
|
||||
enum: [app, env, default]
|
||||
value:
|
||||
description: Effective value — never returned for secret keys
|
||||
required: [key, type, secret, is_set, source]
|
||||
InstanceSettingsResponse:
|
||||
type: object
|
||||
properties:
|
||||
settings:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/InstanceSetting"
|
||||
required: [settings]
|
||||
UpdateInstanceSettingRequest:
|
||||
type: object
|
||||
properties:
|
||||
value:
|
||||
description: JSON value matching the key's declared type
|
||||
required: [value]
|
||||
BootstrapRequest:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in new issue
Block a user