Summary
Introduce a workspace admin settings surface and its first two settings: who can create channels (split public/private) and default channels new members auto-join.
Today teams has only name/slug/is_personal — no settings columns. TeamController@update (and SaveTeamRequest) handle only name. ChannelPolicy@create currently lets any team member create.
Locked decisions (from grilling)
Who can create channels — split public/private
- Two enum-cast string columns on
teams: public_channel_creation_policy and private_channel_creation_policy.
- New enum
ChannelCreationPolicy: Members (default — preserves today's behavior) | Admins.
ChannelPolicy@create gates on the requested visibility against the matching column.
Default channels
is_default boolean on channels, toggled by admins (no pivot).
#general is always a default in code (no row needed / not removable).
- Only public channels can be defaults.
- Applied on joining the workspace — both invite-acceptance and SSO/directory provisioning route through the same "add to default channels" step.
- Non-retroactive — adding a default does not sweep existing members in.
Storage / surface
- Columns live on
teams (typed/queryable, matches the role-on-pivot idiom) — no JSON blob, no team_settings table.
- Settings rendered on the existing workspace admin page (
teams/Edit.vue), Admin+ only, extending SaveTeamRequest + TeamController@update.
Acceptance criteria
Out of scope
- Message retention — carved into its own issue; it will add one more setting into this same surface.
Summary
Introduce a workspace admin settings surface and its first two settings: who can create channels (split public/private) and default channels new members auto-join.
Today
teamshas onlyname/slug/is_personal— no settings columns.TeamController@update(andSaveTeamRequest) handle onlyname.ChannelPolicy@createcurrently lets any team member create.Locked decisions (from grilling)
Who can create channels — split public/private
teams:public_channel_creation_policyandprivate_channel_creation_policy.ChannelCreationPolicy:Members(default — preserves today's behavior) |Admins.ChannelPolicy@creategates on the requested visibility against the matching column.Default channels
is_defaultboolean onchannels, toggled by admins (no pivot).#generalis always a default in code (no row needed / not removable).Storage / surface
teams(typed/queryable, matches therole-on-pivot idiom) — no JSON blob, noteam_settingstable.teams/Edit.vue), Admin+ only, extendingSaveTeamRequest+TeamController@update.Acceptance criteria
public_channel_creation_policy,private_channel_creation_policytoteamsandis_defaulttochannels.ChannelCreationPolicyenum added (+ TypeScript transform).ChannelPolicy@createenforces the policy by visibility; existing "member can create" behavior preserved when set toMembers.is_defaultper public channel; UI reflects it.#general+ allis_defaultpublic channels; existing members untouched.teams/Edit.vue, Admin+ gated;SaveTeamRequestvalidates the new fields.lang/fr.json).docs/self-hosting/reference if these become operator-facing toggles.Out of scope