## Problem
The ESLint rule `graphql-resolvers-should-be-guarded` introduced in
#15392 was failing on main because the guard `SettingsPermissionsGuard`
had inconsistent naming.
## Root Cause
The guard was named `SettingsPermissionsGuard` (with an 's') which was
inconsistent with other permission guards:
- ✅ `CustomPermissionGuard`
- ✅ `NoPermissionGuard`
- ✅ `ImpersonatePermissionGuard`
- ❌ `SettingsPermissionsGuard` (inconsistent!)
The ESLint rule checks if guard names end with `PermissionGuard`, but
`SettingsPermissionsGuard` ends with `sGuard`, so it wasn't recognized
as a permission guard.
## Solution
Renamed the guard to be consistent with the naming convention:
1. ✅ Renamed file: `settings-permissions.guard.ts` →
`settings-permission.guard.ts`
2. ✅ Renamed export: `SettingsPermissionsGuard` →
`SettingsPermissionGuard`
3. ✅ Renamed internal class: `SettingsPermissionsMixin` →
`SettingsPermissionMixin`
4. ✅ Updated all 122 references across 44 files in the codebase
5. ✅ Renamed test file: `settings-permissions.guard.spec.ts` →
`settings-permission.guard.spec.ts`
## Testing
- ✅ `npx nx run twenty-server:lint` passes
- ✅ `npx nx run twenty-server:typecheck` passes
- ✅ No references to the old name remain in the codebase
- ✅ All previously failing resolver files now pass ESLint validation
## Related
Fixes issues introduced in #15392
## Overview
This PR strengthens our permission system by introducing more granular
role-based access control across the platform.
## Changes
### New Permissions Added
- **Applications** - Control who can install and manage applications
- **Layouts** - Control who can customize page layouts and UI structure
- **AI** - Control access to AI features and agents
- **Upload File** - Separate permission for file uploads
- **Download File** - Separate permission for file downloads (frontend
visibility)
### Security Enhancements
- Implemented whitelist-based validation for workspace field updates
- Added explicit permission guards to core entity resolvers
- Enhanced ESLint rule to enforce permission checks on all mutations
- Created `CustomPermissionGuard` and `NoPermissionGuard` for better
code documentation
### Affected Components
- Core entity resolvers: webhooks, files, domains, applications,
layouts, postgres credentials
- Workspace update mutations now use whitelist validation
- Settings UI updated with new permission controls
### Developer Experience
- ESLint now catches missing permission guards during development
- Explicit guard markers make permission requirements clear in code
review
- Comprehensive test coverage for new permission logic
## Testing
- ✅ All TypeScript type checks pass
- ✅ ESLint validation passes
- ✅ New permission guards properly enforced
- ✅ Frontend UI displays new permissions correctly
## Migration Notes
Existing workspaces will need to assign the new permissions to roles as
needed. By default, all new permissions are set to `false` for non-admin
roles.
Until this is done: [Make workspaceMembers
non-system](https://github.com/twentyhq/twenty/issues/15688)
Let's make that update to allow us to have workspaces with
workspaceMember not being system object, to allow user to customize
their data model.
**Before**
- any user with workpace_members permission was able to remove a user
from their workspace. This triggered the deletion of workspaceMember +
of userWorkspace, but did not delete the user (even if they had no
workspace left) nor the roleTarget (acts as junction between role and
userWorkspace) which was left with a userWorkspaceId pointing to
nothing. This is because roleTarget points to userWorkspaceId but the
foreign key constraint was not implemented
- any user could delete their own account. This triggered the deletion
of all their workspaceMembers, but not of their userWorkspace nor their
user nor the roleTarget --> we have orphaned userWorkspace, not
technically but product wise - a userWorkspace without a workspaceMember
does not make sense
So the problems are
- we have some roleTargets pointing to non-existing userWorkspaceId
(which caused https://github.com/twentyhq/twenty/issues/14608 )
- we have userWorkspaces that should not exist and that have no
workspaceMember counterpart
- it is not possible for a user to leave a workspace by themselves, they
can only leave all workspaces at once, except if they are being removed
from the workspace by another user
**Now**
- if a user has multiple workspaces, they are given the possibility to
leave one workspace while remaining in the others (we show two buttons:
Leave workspace and Delete account buttons). if a user has just one
workspace, they only see Delete account
- when a user leaves a workspace, we delete their workspaceMember,
userWorkspace and roleTarget. If they don't belong to any other
workspace we also soft-delete their user
- soft-deleted users get hard deleted after 30 days thanks to a cron
- we have two commands to clean the orphans roleTarget and userWorkspace
(TODO: query db to see how many must be run)
**Next**
- once the commands have been run, we can implement and introduce the
foreign key constraint on roleTarget
Fixes https://github.com/twentyhq/twenty/issues/14608
Resolves [Dependabot Alert
224](https://github.com/twentyhq/twenty/security/dependabot/224) -
formidable relies on hexoid to prevent guessing of filenames for
untrusted executable content.
Used `yarn up formidable --recursive` to upgrade the version from 2.1.2
to 2.1.5.
Fixes https://github.com/twentyhq/private-issues/issues/361
There's room for more improvement here -
triggerInitialRecordTableDataLoad does a lot of things, should not be
triggered so much. actually even
RecordTableVirtualizedInitialDataLoadEffect should not be triggered when
there's just a metadata field change (if we trust the name
initialDataLoad)
As title
- adds decorators in twenty-sdk
- update twenty-cli load-manifest to it gets @FieldMetadata infos +
testing
- update twenty-server so it CRUD fields properly, using
universalIdentifier
- Fix UI so we can update managed objects records
- move FieldMetadata items from twenty-server to twenty-shared
Here is what the PR does:
- Surface password state in validatePasswordResetToken, returning
hasPassword so the client can tell whether a user is setting or changing
their password.
- Consume that flag throughout the front end (mock data, stories,
GraphQL types) and update the Reset/Set Password modal to swap the
heading/button label and success toast accordingly.
- After a successful password set/reset, immediately update the
logged-in user’s hasPassword flag so the Settings screen reflects the
new state without a reload.
Modal has two states now - reset password modal uses change password
state since it made intuitive sense.
<p align="center">
<img width="404" height="397" alt="image"
src="https://github.com/user-attachments/assets/c54cc581-1248-4395-833d-0202758e1947"
/>
</p>
<p align="center">
<img width="403" height="393" alt="image"
src="https://github.com/user-attachments/assets/d8a39a95-27e6-4037-86f2-1f74176002ba"
/>
</p>
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
## Summary
Reverts commits afc518a, ae22e64, and 800b5b5 that refactored
`useAgentChat` to address umbrella hook pattern feedback.
## Issues Introduced by Refactoring
The refactoring broke several critical functionalities:
1. **Streaming fails on thread switch** - Messages don't stream properly
when switching between threads
2. **Messages lost on tab close** - When the Ask AI tab is closed, the
request is lost instead of continuing in the background
3. **Blank chat requiring force-reload** - Chats often appear blank and
require switching to another chat to force a reload (closes
[#1771](https://github.com/twentyhq/core-team-issues/issues/1771))
## Root Cause
After extensive debugging, it appears **multiple instances of `useChat`
don't work well together**. The refactored architecture inadvertently
created scenarios where multiple `useChat` instances interfere with each
other.
## Resolution
Reverting to restore functionality. The umbrella hook pattern
optimization needs a different architectural approach that doesn't rely
on multiple `useChat` instances.
## Follow-up
While the umbrella hook feedback is valid, we need to rethink the
implementation strategy:
- Find an alternative to multiple `useChat` instances
- Possibly consolidate chat state management differently