Chrome doesn't really respect preloading and was loading it before other
important assets, slowing down the app while in 99% of sessions people
don't check the REST API playground
Fix the following error:
Cannot use a pool after calling end on a pool
<img width="917" alt="Screenshot 2025-05-17 at 14 56 18"
src="https://github.com/user-attachments/assets/63081831-9a7e-4633-8274-de9f8a48dbae"
/>
The problem was that the datasource manager was destroying the
connections when a datasource cache expired.
This PR implements a global PostgreSQL connection pool sharing
mechanism.
- Patches pg.Pool to reuse connection pools across the application when
connection parameters match, reducing resource overhead.
- New environment variables allow enabling/disabling sharing and
configuring pool size, idle timeout, and client exit behavior.
WorkspaceDatasourceFactory will now use shared pools if enabled, this
will avoid recreating 10 connections for each pods for each workspace.
---------
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
As discussed with @Weiko
Even though we cache the datasource, the connection expire after
10minutes in TypeORM, that might be the reason why our app is spamming
the proxy asking for connections. Also lowering the pool size.
Revert changes in #12006 as it might still be handy to have the DB
auto-created (e.g. for test or self-hosting users), but if there is a
permission exception we will just ignore it and assume the database
exist in that case
## Architecture Detail
The goal is to merge the two TypeORM schemas.
Having two schemas prevent doing things like fieldMetadata.workspace in
TypeORM, and create useless debates since there is no clear line (is a
serverlessFunction core or metadata? What about events? etc.)
### Before
```
┌───────────────────┐ ┌───────────────────┐
│ core schema │ │ metadata schema │
├───────────────────┤ ├───────────────────┤
│- User │ │- ObjectMetadata │
│- Workspace │ │- FieldMetadata │
│- UserWorkspace │ │- RelationMetadata │
│- etc. │ │- etc. │
└───────────────────┘ └───────────────────┘
```
### After the Migration
```
┌───────────────────────────────────────────┐
│ engine schema │
├───────────────────────────────────────────┤
│- User - ObjectMetadata │
│- Workspace - FieldMetadata │
│- UserWorkspace - RelationMetadata │
│- etc. - etc. │
└───────────────────────────────────────────┘
```
## Strategy
1. During 0.53 we backfill the *_typeorm_migrations* table of the core
schema with all metadata migrations
2. That way in 0.54 we can move the metadata migrations from the
metadata folder to the core folder. We will also edit the migration
files to reference "core" instead of "metadata". For people doing a
fresh install this will run smoothly and create the tables in Core
directly. For people on an existing install, this migrations will not
run because they were added to the *_typeorm_migrations* in 0.53
3. In 0.55 we will rename "core" to something else (for example
"engine")
Note: if someone jumps version, for example skips to 0.54 directly
without having run 0.53 then this could cause issue. In 0.54 we should
consider gating the "migrate:prod" in the docker file so that it's
controlled and run by the upgrade command (and not run if the command
wasn't executed properly)
No need to audit log workflow runs as it's already a form of audit log.
Add more audit log for other objects
Rename MessagingTelemetry to MessagingMonitoring
Merge Analytics and Audit in one (Audit)
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
isEmailVerified was set to false which was annoying in the staging
environment
Also updated password for tim@apple.dev from AppleCar2025 to just
tim@apple.dev since the joke is outdated
We didn't get much complaints on Localization so I guess we can expand
it more and make it the default behavior to use the browser's locale
when you signup
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This is hard to test without merging PRs unfortunately
Goal of this PR is to replace the action I had introduced since there
was already a similar one in the codebase
We want to have fewer base path for routing.
We will have:
- /files
- /webhooks
- /graphql
- /metadata
- /rest
- /auth
- /healthz
I'm moving /open-api under /rest, and centralizing the webhooks
(removing /stripe and /cloudflare)
Now the source of truth for the version is set during the build process.
We set it as an environment variable from the tags.
We could add it back to the package.json during the build process (from
the git tag), but there is not use for it at the moment since it's not
npm packages.
Let's deprecate Sentry Release and use APP_VERSION instead.
It'll make it more clear in the interface to use named version for bug
analysis, than commit sha
Recoil-sync was causing issues with Firefox, replacing it with a simpler
mechanism to hydrate variables on page load
---------
Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
A small PR but a big step towards making Twenty easier to self-host and
upgrade!
Now changing the tag and pulling a new version should be the only step
to upgrade as migrations script will be ran automatically upon starting
the containers. It was already the case for typeorm migrations, but not
for standard objects migration and data migration scripts. It is still
possible to disable this behavior for the most complex deployments such
as our own cloud.
Refactor query runner to improve the import method for upserts, we now
take into account any unique field and prevent any conflict upfront.
Previously, we would only update if an `id` was passed.
https://github.com/user-attachments/assets/8087b864-ba42-4b6e-abf2-b9ea66e6c467
This is only a first step, there are other things to fix on the frontend
for this to work.
Fixes#11310
Note:
- I changed "system to advanced" because I think we will link that to
the Advanced Mode in the future
- Not sure when to use useCallback / useMemo, AI added some useCallbacks
which I removed but I left some useMemo... Not sure what should be the
rule
- It had to use MenuItem because this sub-menu behavior wasn't available
in the Standard select component. We should probably rename the
"MenuItem" elements to something more generic. I didn't do it in this PR
because I'm not sure about the strategy and it would change a lot of
files.
Mostly renaming objects to avoid conflicts (it was painful because names
were too generic so you could cmd+replace easily)
Also refactoring `useBuildAvailableFieldsForImport`
Advanced mode toggle was in `twenty-ui` which doesn't support Lingui.
I removed lingui from the global package json and moved it to the local
package.json instead to prevent that kind of error from happening again
CSS was loaded in a global context (full screen which might be re-used
for other use cases in the future) instead of a local context.
\+ small update on .env.example
Prepare for better version upgrade system + split admin panel into two
permissions + fix GraphQL generation detection
---------
Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Workspace Member will get their own record page in the future.
This PR lays backend changes to prepare for this:
- Settings most fields on WorkspaceMember as system fields
- Renaming workspaceMember/workspaceMemberId to
forWorkspaceMember/forWorkspaceMemberId as it conflicts with the morph
relationship, if we want to be able to add a workspace member as
favorite
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This pull request focuses on improving localization by replacing
hardcoded strings with translatable strings using the `Trans` component
from `@lingui/react/macro`. Additionally, it introduces locale support
to several email components. Here are the most important changes:
### Localization Improvements:
* Replaced hardcoded strings with `Trans` components in various email
templates to support localization.
(`packages/twenty-emails/src/emails/clean-suspended-workspace.email.tsx`,
`packages/twenty-emails/src/emails/password-reset-link.email.tsx`,
`packages/twenty-emails/src/emails/password-update-notify.email.tsx`,
`packages/twenty-emails/src/emails/send-email-verification-link.email.tsx`,
`packages/twenty-emails/src/emails/send-invite-link.email.tsx`,
`packages/twenty-emails/src/emails/warn-suspended-workspace.email.tsx`)
[[1]](diffhunk://#diff-ca227a03c0aa66428daff938c743435e8a4dc3ffa960c0952f2697a23e280fdbR6-R25)
[[2]](diffhunk://#diff-ca227a03c0aa66428daff938c743435e8a4dc3ffa960c0952f2697a23e280fdbL42-R45)
[[3]](diffhunk://#diff-523cd37f5680ce418450946f62b7804b6586158efb190ced73920ef0fdf96bc8L1)
[[4]](diffhunk://#diff-523cd37f5680ce418450946f62b7804b6586158efb190ced73920ef0fdf96bc8L23-R23)
[[5]](diffhunk://#diff-cf16aa55d3eeb6be606bbe93de4c83b6f146c49b60d6f512d4b87e49fe14338cL29-R29)
[[6]](diffhunk://#diff-cf16aa55d3eeb6be606bbe93de4c83b6f146c49b60d6f512d4b87e49fe14338cL46-R46)
[[7]](diffhunk://#diff-16b613160f937563ec108176f595d8f275a1d87a5b8245d84df60d775f3efebeL1)
[[8]](diffhunk://#diff-16b613160f937563ec108176f595d8f275a1d87a5b8245d84df60d775f3efebeL22-R22)
[[9]](diffhunk://#diff-0da62e7cc5cfcb32cc25f067fa1d50123047c239af210398f065455ab6700886L1)
[[10]](diffhunk://#diff-0da62e7cc5cfcb32cc25f067fa1d50123047c239af210398f065455ab6700886L42-R41)
[[11]](diffhunk://#diff-0da62e7cc5cfcb32cc25f067fa1d50123047c239af210398f065455ab6700886L57-R56)
[[12]](diffhunk://#diff-483346065c074946a43c18492334bd680422a1d4cb994dc8c3cd39d0208e6016L1-R21)
[[13]](diffhunk://#diff-483346065c074946a43c18492334bd680422a1d4cb994dc8c3cd39d0208e6016L28-R31)
[[14]](diffhunk://#diff-483346065c074946a43c18492334bd680422a1d4cb994dc8c3cd39d0208e6016L53-R55)
### Locale Support:
* Added `locale` prop to email components to dynamically set the locale.
(`packages/twenty-emails/src/emails/clean-suspended-workspace.email.tsx`,
`packages/twenty-emails/src/emails/warn-suspended-workspace.email.tsx`)
[[1]](diffhunk://#diff-ca227a03c0aa66428daff938c743435e8a4dc3ffa960c0952f2697a23e280fdbR6-R25)
[[2]](diffhunk://#diff-483346065c074946a43c18492334bd680422a1d4cb994dc8c3cd39d0208e6016L1-R21)
### SnackBar Messages:
* Replaced hardcoded SnackBar messages with translatable strings using
the `t` function from `@lingui/react/macro`.
(`packages/twenty-front/src/modules/auth/components/VerifyEmailEffect.tsx`,
`packages/twenty-front/src/modules/auth/hooks/useVerifyLogin.ts`,
`packages/twenty-front/src/modules/auth/sign-in-up/hooks/useHandleResendEmailVerificationToken.ts`,
`packages/twenty-front/src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts`,
`packages/twenty-front/src/modules/object-record/record-field/components/LightCopyIconButton.tsx`,
`packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/PhonesFieldDisplay.tsx`)
[[1]](diffhunk://#diff-551f2f94eacd8856d22bab7e63dd3ad693f87e9fa9b289864802ebc387f72b42R7)
[[2]](diffhunk://#diff-551f2f94eacd8856d22bab7e63dd3ad693f87e9fa9b289864802ebc387f72b42L24-R29)
[[3]](diffhunk://#diff-551f2f94eacd8856d22bab7e63dd3ad693f87e9fa9b289864802ebc387f72b42L43-R51)
[[4]](diffhunk://#diff-428199461992a01325159f5fbf826d845f05f3361279eccd3f1ce416e0114845R7-R15)
[[5]](diffhunk://#diff-428199461992a01325159f5fbf826d845f05f3361279eccd3f1ce416e0114845L24-R26)
[[6]](diffhunk://#diff-cde42d6abfed63e52c2bda09d537a6577148d0baf957fde75ceaa8657ed58403R5)
[[7]](diffhunk://#diff-cde42d6abfed63e52c2bda09d537a6577148d0baf957fde75ceaa8657ed58403L16-R17)
[[8]](diffhunk://#diff-cde42d6abfed63e52c2bda09d537a6577148d0baf957fde75ceaa8657ed58403L28-R33)
[[9]](diffhunk://#diff-9332c1988864863f12516c2fb77e814af60bedb37c36ffa094f49afc335d5457R5-R17)
[[10]](diffhunk://#diff-9332c1988864863f12516c2fb77e814af60bedb37c36ffa094f49afc335d5457L27-R33)
[[11]](diffhunk://#diff-9332c1988864863f12516c2fb77e814af60bedb37c36ffa094f49afc335d5457L42-R44)
[[12]](diffhunk://#diff-8d64afa825b47ab71d18e3e284408e2097f5fd2365eae84d9d25d3568c48e49cR7)
[[13]](diffhunk://#diff-8d64afa825b47ab71d18e3e284408e2097f5fd2365eae84d9d25d3568c48e49cR20-R28)
[[14]](diffhunk://#diff-6e4361ded2b5656afaeb1befa8b1d23a45b490a1118550da290e27cdb8ebcdceR6)
[[15]](diffhunk://#diff-6e4361ded2b5656afaeb1befa8b1d23a45b490a1118550da290e27cdb8ebcdceR19-R20)
[[16]](diffhunk://#diff-6e4361ded2b5656afaeb1befa8b1d23a45b490a1118550da290e27cdb8ebcdceL29-R38)
There are a lot of requests being done in parallel when you load the
page, and the support chat is responsible for some of them. I don't
think it's critical to have it upon loading so delaying it by 2 seconds
More progress on translations:
- Migrate from translations.io to crowdin
- Optimize performance and robustness
- Set workspaceMember/user locale upon signup
Fortunately we're not using NODE_ENV=production for our deployment, but
we need to think of a better long-term fix. Not easy because Lingui
strips out messages in production environment
Similar to ObjectMetadata translation
Also fixed an issue linked to the migration from `t` to `message`
helper: we're forced to rebuild the ID ourselves
Fixes#9827
Also uncovered a conflict with `@objectType('Relation')` and
`@objectType('relation)`
I don't want to address it in this PR so I will create a followup issue
when we close this but I think there's a confusion between
Relation/RelationMetadata, it's unclear what is what
---------
Co-authored-by: Antoine Moreaux <moreaux.antoine@gmail.com>
Fixes#9761
Instead of cleaning RecoilState we should keep the api key visible as
long as the user didn't refresh/leave the app, it's better from a UX
perspective and the code is also more elegant, removing a useEffect
Note: the root cause of the bug was a missing "/settings" path in
isMatchingLocation in useCleaningRecoilState (due to the recent
refactoring) ; but I think this fix is better