0f06fccdeea8f762998ec18fbc16042afae90df4
22 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7b7e4a5eca |
docs: fix inaccuracies found auditing the docs against v2.27.0 (#23616)
Prompted by user feedback: *"The documentation doesn't always reflect
the latest release. Some articles are outdated or incomplete."*
I audited every English page under `packages/twenty-docs` against the
code at v2.27.0, verifying each checkable claim (commands, env vars,
enum members, payload shapes, prop tables, API routes) against source in
`packages/`. Anything without a `file:line` citation proving the docs
wrong was dropped.
**Result: 414 findings across 226 pages — 75 critical, 169 major, 170
minor.** The feedback is accurate, and understates it in the
developer-facing sections.
This PR fixes a first slice. The full findings list is below so the rest
can be picked up.
---
## What this PR changes
**Removes the `twenty-ui` component reference** (25 English pages + 325
translations). The section predated the extraction of the design system
into the `twenty-ui` package:
- Not one import path resolved. `twenty-ui/display` and
`twenty-ui/components` are not export subpaths (real ones:
`data-display`, `feedback`, `icon`, `input`, `navigation`, `surfaces`,
`layout`, …), and ~20 more examples imported `@/ui/...` paths no longer
in twenty-front.
- Three documented components no longer exist: `SoonPill`,
`AutosizeTextInput`, `MenuItemCommand`.
- `Chip`'s props table documented the deleted `EntityChip`.
`ProgressBar`'s entire API was replaced
(`duration`/`delay`/`easing`/`barHeight`/`autoStart` →
`value`/`barColor`/`countdownDurationInMs`/…).
It was also unreachable from the navigation, so the pages were indexed
and searchable but maintained by nobody. Storybook is the live source of
truth here, which is why this is a deletion rather than a repair.
**Legal FAQ.** Corrects the workspace deletion timeline to match clause
4.9 of the DPA the product itself generates (~90 days from live systems,
a further ~90 for backups, isolated throughout) instead of the previous
claim of immediate removal with 7-day backup retention. Rephrases the
support-access answer to describe what the product actually does: access
is on by default and can be disabled in Settings → General → Security,
rather than the previous claim that it requires the customer to report
an issue and grant access.
**Self-hosting setup page.** The SMTP configuration block used
`<ArticleTabs>/<ArticleTab>`, leftovers from the pre-Mintlify site.
Those components are undefined here, so the Gmail/Office365/smtp4dev
instructions were not rendering at all. Converted to `<Tabs>/<Tab>`.
**Removes a fabricated Enterprise gate.** A Warning on the app
publishing page claimed cross-workspace sharing of tarball apps requires
an Enterprise key and that the Distribution tab shows an upgrade prompt.
No such gate exists in code, and its link target didn't exist either.
**Link and asset fixes.** Retargeted the two `docs.json` redirects whose
destinations 404'd; fixed the Code of Conduct link (file lives under
`.github/`); fixed the app-roles example link to
`examples/hello-world/src/roles/default-role.ts`; pointed the Contribute
frontend card, four `/developers/extend/apps/getting-started` links and
one `/twenty-ui/display` link at real pages; dropped two `<img>` tags
whose files are absent from the repo.
After this PR: every internal link and image reference resolves, all 171
navigation entries resolve to a file, and no redirect destination is
dead.
---
## Audit: what else is wrong
### Root causes
The failures aren't random rot. Four mechanisms produce nearly all of
them:
1. **Nothing links renaming a symbol to updating the page that documents
it.** Whole pages describe APIs returning zero grep hits:
`MessageQueueServiceBase`, `useScopedHotkeys`/`PageHotkeyScope`,
`@Gate`, `SoonPill`.
2. **"Coming soon" is written once and never revisited.** Nine features
are documented as unavailable that have shipped.
3. **Pages are dropped from navigation but left on disk.** 55 were
unreachable yet still indexed and searchable.
4. **Docs written from intent rather than from code.** One case is
provably born-stale: the `front-components` limitations table was
written in a commit that landed *after* the commit which polyfilled the
APIs it lists as unsupported.
### Priority 1: pages that actively break the reader
**Workflow template variables are wrong across 12 pages.** The largest
cluster — 16 critical findings, one root cause. Record-event triggers
expose the record under `properties.after`/`properties.before`; manual
triggers under `payload`; webhook triggers store the posted body flat
with no wrapper. Docs use `{{trigger.object.*}}`, `{{trigger.body.*}}`,
`{{trigger.subject}}` throughout. Search Records returns `{ first, all,
totalCount }`, not an array, and the resolver is Handlebars, which
doesn't accept `[0]` indexing at all — so `{{searchRecords[0].name}}`
and `{{searchRecords.length}}` cannot work. Iterator exposes
`currentItem`, not `item`/`index`. Evidence:
`generate-fake-object-record-event.ts:44-60`,
`workflow-schema.workspace-service.ts:501-517`,
`find-records.workflow-action.ts:111-117`,
`workflow-iterator-result.type.ts:2-3`,
`twenty-shared/src/utils/evalFromContext.ts`. Every workflow tutorial on
the site is copy-paste-broken. Highest-value fix in the audit, and
mostly mechanical.
**Self-hosting runbook commands don't work.** Backup names a container
and database that don't exist (service is `db` → `twenty-db-1`; database
is `default`, not `twenty`). Restore runs `docker compose stop
twenty-server twenty-front`, neither of which is a service — the compose
file defines `server`, `worker`, `db`, `redis`, and there's no separate
frontend service. The "unable to log in" fix runs `yarn` and `npx nx
database:reset` inside the production container, whose Dockerfile
deletes `npm`/`npx` and ships only `dist/`. Someone following the backup
page ends up with no backup.
**API, webhook and OAuth contracts are wrong.** The documented webhook
payload (`event`, `data`, `timestamp`) is not what the server sends —
the real body is `targetUrl`, `eventName`, `objectMetadata`,
`workspaceId`, `webhookId`, `eventDate`, `userId`, `workspaceMemberId`,
`record`, optional `updatedFields`
(`transform-event-batch-to-webhook-events.ts:34-46`). Any integration
written from that page fails to parse. `GET /oauth/authorize` doesn't
exist (server serves `/oauth/register`, `/token`, `/revoke`,
`/introspect`; authorization is served by the frontend at `/authorize`).
`/oauth/register` never returns a `client_secret` —
`token_endpoint_auth_method` is hard-coded `'none'` — so the documented
response and the "store it securely" warning are fiction, and the Client
Credentials section is unusable with a DCR client. PKCE is mandatory,
not "recommended". Batch limit is 200, not 60 (`QUERY_MAX_RECORDS =
200`), making the derived throughput estimates ~3.3x off.
**Contributor onboarding teaches removed APIs.** `queue.mdx`,
`hotkeys.mdx` and `feature-flags.mdx` are wrong at essentially every
step. Documented nx targets `twenty-server:database:migrate:prod`,
`twenty-server:test:unit` and `npx nx start` aren't real targets and
fail outright. `local-setup.mdx` never mentions
`packages/twenty-utils/setup-dev-env.sh`, the supported entry point.
Both style guides teach the `${({ theme }) => ...}` pattern, which now
returns **zero** hits in twenty-front against 929 files using
`themeCssVariables`. `frontend-commands.mdx` still lists Craco; the
frontend is Vite.
**SSO configuration is substantially fiction.** Twenty supports exactly
two protocols, OIDC and SAML. The docs omit OIDC entirely, present
Google Workspace and Microsoft Entra ID (separate social-login toggles)
as SSO providers, list configuration fields matching neither form, and
instruct the reader to click a **Test Configuration** button that exists
nowhere in the codebase.
**Data model.** The field-type table documents two types that don't
exist (`Domain`, `Long Text`) and omits three users can actually pick
(`Files`, `Full Name`, `Rich Text`). The filter-operator table is wrong
for every field type listed: Text has none of its four documented
operators, Date is missing six of nine.
**Import guidance that fails silently.** `DD/MM/YYYY` is documented as
supported; import uses plain `new Date(value)`, so `15/03/2024` is
always rejected and `03/15/2024` always read US-style — and the sibling
`fix-import-errors.mdx` says the opposite. The company sample CSV is
unusable as written (`Domain / Domain Label` headers don't exist; real
ones are `Domain Name / Link Label`).
### Priority 2: shipped features documented as unavailable
This is the specific complaint in the feedback. Each is a one-line fix.
| Documented as | Reality |
|---|---|
| AI Agent action "Coming soon" (2 pages) |
`WorkflowActionType.AI_AGENT` ships, in the picker, no feature flag |
| "There is no built-in if/else logic" (2 pages) |
`WorkflowActionType.IF_ELSE` ships |
| Webhook event filtering "may be added in future releases" (2 pages) |
per-webhook `operations` array with `*.created` / `person.*` / `*.*`
wildcards |
| Many-to-many "coming in H2 2026" | Junction Relations shipped as
public beta; Twenty's own how-to documents it |
| Email campaigns "available soon" (2 pages) | MessageCampaign object,
send/stats jobs, unsubscribe topics all ship |
| CC/BCC "not yet available" | exists on Send Email |
| Workflow retry "on our roadmap" | run-level retry command plus
per-step `retryOnFailure` |
| front-components limitations table | `getBoundingClientRect`,
`offset*`/`client*`/`scroll*`, `getComputedStyle`, `getElementById` all
polyfilled |
| Node SDK "does not exist" | `twenty-client-sdk@2.27.0` ships and is
documented elsewhere in these docs |
Four "coming soon" claims were checked and are **still accurate** —
webhook trigger authentication, dashboard-level filters, dashboard
timezone, background-job priority. Leave them.
One needs rewording rather than promotion: **gauge charts** are
described as on the roadmap, but the upgrade command
`2-3-workspace-command-...-delete-gauge-widgets` says support was
*removed*.
### Priority 3: structural
**30 orphaned pages remain** after the twenty-ui deletion: 15 of 18
`developers/contribute/*`, all 6 `user-guide/getting-started/*`, plus
`self-host.mdx`, `key-rotation.mdx`, `extend.mdx`,
`views-pipelines/overview.mdx`, `ai/capabilities/mcp.mdx`,
`data-migration/how-tos/export-faq.mdx`,
`extend/capabilities/{apis,webhooks}.mdx`. Each needs an explicit
decision: re-add, or delete plus redirect. Two look worth re-adding
rather than deleting — `user-guide/ai/capabilities/mcp.mdx` is accurate,
documents a shipped feature that's a plan line-item, and is reachable
only via a legacy redirect; `views-pipelines/overview.mdx` is linked
from three in-nav pages.
`user-guide/getting-started/capabilities/implementation-services.mdx`
must be merged rather than deleted, since three in-nav pages deep-link
it.
**Duplicate pages.** `getting-started/core-concepts/glossary.mdx` and
`user-guide/getting-started/capabilities/glossary.mdx` are 99%
identical. `developers/extend/webhooks.mdx` and
`developers/extend/capabilities/webhooks.mdx` are 88% identical and
carry the same wrong payload. `workflow-branches.mdx` and
`use-branches-in-workflows.mdx` are both in the sidebar and give
*contradictory* branch-creation instructions.
**Other.** 44 pages have no frontmatter `description`. The Russian
locale is 14 pages behind every other locale, including the entire
document-generator tutorial.
### Still needs a human owner
The legal FAQ promises breach notification "within 48 hours" while
clause 4.6 of the generated DPA (`dpa-template.constant.ts:178`) targets
72. Per direction, the docs keep 48h — a stricter public commitment than
the contract is a deliberate choice — but the DPA and the docs still
disagree, and someone owning the DPA should decide which moves.
Claims about SOC 2, GDPR attestation, backup cadence and AI-training use
could not be substantiated from the repository either way and need the
same treatment.
### Preventing recurrence
Three cheap guards would have caught most of the 75 criticals:
- **A CI check** that every navigation page resolves, every internal
link and image resolves, and no `.mdx` outside `l/` is orphaned. Catches
the entire structural third. This PR leaves the docs in a state where
such a check would pass.
- **Generate the volatile tables from their source enums** — field
types, workflow actions and triggers, filter operands, permission flags,
chart types, env vars — rather than hand-maintaining them. These
accounted for a large share of the major findings.
- **Treat "coming soon" as an expiring assertion**: tag each with the
symbol it depends on and fail the docs build when that symbol appears in
code.
## Suggested order for the rest
1. Workflow variable syntax across the 12 tutorial pages — largest
cluster, mechanical, most directly matches the feedback.
2. Self-host backup/restore/troubleshooting commands — highest blast
radius per reader.
3. Webhook payload and OAuth endpoints — blocks integrators.
4. The nine "coming soon" claims — one line each, and the most visible
form of "docs don't reflect the latest release".
5. Decide the 30 remaining orphans.
## Test plan
- [x] Every internal link and image reference in the docs resolves
- [x] All 171 navigation entries resolve to a file on disk
- [x] No `docs.json` redirect destination is dead
- [x] No inbound links to the deleted `twenty-ui` pages remain
- [x] `docs.json` structure intact after edit (138 redirects, 14
languages)
- [ ] Visual check of the self-hosting SMTP tabs once the docs preview
builds
---
_Generated by [Claude
Code](https://claude.ai/code/session_01AnUNYYdkN3PMTPb2m6CnqC)_
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23616?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
|
||
|
|
2be01df271 |
docs: state v1.23 as prerequisite for cross-version upgrades (#23575)
Fixes #23568 The upgrade guide stated v1.22 was enough before jumping to a 2.x release. In practice that path fails during the workspace migration with `column ViewSortEntity.subFieldName does not exist`. Going through v1.23 first works. Changes in `packages/twenty-docs/developers/self-host/capabilities/upgrade-guide.mdx`: - Cross-version upgrade section now says v1.23+ instead of v1.22+, example updated to v1.23 -> v2.0 - "Before v1.22" section renamed to "Before v1.23" and its instructions updated Only the English source is edited, the `l/<locale>/` copies are Crowdin-managed and will resync. Co-authored-by: prastoin <paul.rastoin@gmail.com> |
||
|
|
e5ac9f5b8b |
Docs update (#23429)
Follow-up based on comments from https://github.com/twentyhq/twenty/pull/23266 <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23429?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
975b5c256c |
Documentation update ( Legal FAQ and more ) (#23266)
New legal section and minor fixes <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23266?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
bf1220883f |
docs: partner CTAs on high-traffic pages (workflows, data-model, docker-compose) (#22808)
## Summary Follow-up to #22719 (merged), which added partner-marketplace CTAs to four **high-intent, low-traffic** docs pages (SSO, both migration guides, implementation services). Reviewing the docs' **top-visited pages** showed none of those four rank in the top ~20 — they're the high-intent tail, which is correct, but small reach. This PR extends the same pattern to three **high-traffic pages that also carry buying intent**, without touching the pure top-of-funnel intros/quickstarts (volume without intent → a CTA there is just noise). Same conventions as #22719: Mintlify-native `<Tip>` callouts, partner-first with `contact@twenty.com` secondary, directory deep-linked via `?categories=<scope>` and tagged with `?ref=docs-*`. No new snippet; no `docs.json`, navigation, or translation (`l/`) changes. ## Pages changed — screenshots (one per page) > Preview locally with `npx mintlify dev` from `packages/twenty-docs`, or use the Mintlify PR preview once it posts. Paths below are under `docs.twenty.com`. ### 1. `/user-guide/workflows/overview` (~593 views) New `## Need Help?` two-bullet `<Tip>` → **Done for you** (Solutioning partner) / **Onboarding pack** (Workflow Creation). Maps 1:1 to the named onboarding service. _screenshot:_ <img width="1440" height="818" alt="Screenshot 2026-07-10 at 14 34 32" src="https://github.com/user-attachments/assets/231f681d-b5be-4b1e-9b6a-a4947a9fca37" /> ### 2. `/user-guide/data-model/overview` (~954 views) Replaced the plain "Need Help?" line with a two-bullet `<Tip>` → **Done for you** (Solutioning partner) / **Onboarding pack** (Data Model Design). Keeps the existing Implementation Services link. _screenshot:_ <img width="1436" height="817" alt="Screenshot 2026-07-10 at 14 34 14" src="https://github.com/user-attachments/assets/c0fe1064-1030-4062-91c7-24644ac31654" /> ### 3. `/developers/self-host/capabilities/docker-compose` (~2421 views) New `## Managed Hosting` single-line `<Tip>` → *find a certified Twenty hosting partner* (Hosting), contact fallback. Framed as a lighter "prefer not to run it yourself?" alternative — deliberately low-pressure for the DIY self-host audience. _screenshot:_ <img width="1437" height="815" alt="Screenshot 2026-07-10 at 14 33 39" src="https://github.com/user-attachments/assets/a37207cd-2aaa-4aba-848d-cbf06a1e1321" /> ## Notes for reviewers - Page-selection rationale: intent × volume. Kept the four intent-tail pages from #22719; added the highest-traffic pages that also carry a natural partner-buying moment (self-host → Hosting; workflows / data-model → Solutioning). Intros/quickstarts/contribute pages intentionally left untouched. - **Attribution caveat (unchanged from #22719):** twenty.com's analytics (Cloudflare Web Analytics) is path-based, so `?ref=` is not measurable yet. Per-page measurement via a `/go/*` redirect Worker remains a planned, separate follow-up (out of scope here). - `mintlify validate` passes. Opened as a draft. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22808?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
7d7f32b243 |
docs: remove the self-host cloud providers page (#21134)
## What Removes the community-maintained **"Other methods"** cloud-providers page from the self-host docs (it covered Kubernetes/Terraform/Coolify community deployments). ## Changes - **Deleted** `developers/self-host/capabilities/cloud-providers.mdx` and its 13 localized copies (ar, cs, de, es, fr, it, ja, ko, pt, ro, ru, tr, zh). - **Removed the slug** from `navigation/base-structure.json` (the source of truth) and regenerated the derived files via the repo's own generators (`yarn docs:generate`, `yarn docs:generate-paths`): - `docs.json` — nav entries dropped for every locale. - `twenty-shared/.../DocumentationPaths.ts` — `DEVELOPERS_SELF_HOST_CAPABILITIES_CLOUD_PROVIDERS` constant dropped (was unused elsewhere). - **Removed the "Cloud Providers" card** from the `self-host` overview pages across all locales. - **Dropped the dangling redirect** `/developers/self-hosting/cloud-providers` (its destination no longer exists). - Cleared the matching entry from the unused `navigation-schema.json` for consistency. Net: 68 line deletions across config (pure removal); no insertions. ## Verification - `grep` confirms **0** remaining references to `cloud-providers` anywhere in the repo. - All touched JSON files parse; `oxlint` on twenty-docs reports 0 errors. - Generators (not hand edits) produced `docs.json` and `DocumentationPaths.ts`. > Note: `mintlify broken-links` can't run to completion on this branch due to a **pre-existing** MDX parse error in the unrelated `l/ar/.../contribute/contribute.mdx`; the grep above is the equivalent guarantee that no link points at the removed page. |
||
|
|
91ce59d8e2 |
refactor(jwt): gate signing-key auto-rotation cron on SIGNING_KEY_ROTATION_DAYS (#20866)
Only register the JWT signing-key rotation cron when `SIGNING_KEY_ROTATION_DAYS` is set, and move that variable to Advanced Settings. |
||
|
|
05f31c1837 |
docs(self-host): document ENCRYPTION_KEY, FALLBACK_ENCRYPTION_KEY and key rotation procedures (#20611)
## Summary - Documents the new at-rest encryption envelope (`ENCRYPTION_KEY` / `FALLBACK_ENCRYPTION_KEY`) introduced in v2.5+ and clarifies its relationship to the legacy `APP_SECRET`-as-encryption-key path. - Adds a new dedicated **Key rotation** guide covering manual / Enterprise-cron JWT signing-key rotation, signing-key revocation, and the online `ENCRYPTION_KEY` rotation procedure (including the new \`secret-encryption:rotate\` CLI shipped in a follow-up PR). - Updates the docker-compose quickstart to generate a dedicated \`ENCRYPTION_KEY\` from day 1. - Mentions the v2.5+ enc:v2 backfill in the upgrade guide. English-only — the localized mirrors will be picked up by i18n CI. ## Test plan - [ ] Mintlify build passes locally / in CI - [ ] Sidebar entry renders under **Self-Host → Key rotation** - [ ] Internal links to /developers/self-host/capabilities/key-rotation resolve from setup.mdx, docker-compose.mdx and upgrade-guide.mdx --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
a583ee405b | Cross version and upgrade status docs (#19926) | ||
|
|
5d438bb70c |
Docs: restructure navigation, add halftone illustrations, clean up hero images (#19728)
## Summary - **New Getting Started section** with quickstart guide and restructured navigation - **Halftone-style illustrations** for User Guide and Developer introduction cards using a Canvas 2D filter script - **Removed hero images** (`image:` frontmatter + `<Frame><img>` blocks) from all user-guide article pages - **Cleaned up translations** (13 languages): removed hero images and updated introduction cards to use halftone style - **Cleaned up twenty-ui pages**: removed outdated hero images from component docs - **Deleted orphaned images**: `table.png`, `kanban.png` - **Developer page**: fixed duplicate icon, switched to 3-column layout ## Test plan - [ ] Verify docs site builds without errors - [ ] Check User Guide introduction page renders halftone card images in both light and dark mode - [ ] Check Developer introduction page renders 3-column layout with distinct icons - [ ] Confirm article pages no longer show hero images at the top - [ ] Spot-check a few translated pages to ensure hero images are removed 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
895bb58fc6 |
feat: add S3 presigned URL redirect for file downloads (#18864)
## Summary - When `STORAGE_S3_PRESIGNED_URL_BASE` is configured, the file controller returns a **302 redirect** to a presigned S3 URL instead of proxying every byte through the server. This eliminates server bandwidth and CPU overhead for S3-backed deployments. - For local storage or S3 without a public endpoint, behavior is unchanged (stream + pipe with security headers). - Added `getPresignedUrl` to the `StorageDriver` interface (required method returning `string | null`), with implementations in S3Driver (uses a separate presign client with the public endpoint), LocalDriver (returns `null`), and ValidatedStorageDriver (path traversal protection + delegation). - Added a unified `getFileResponseById` method in `FileService` that performs a single DB lookup and returns either a redirect URL or a stream, avoiding double lookups. - Extracted `getContentDisposition` from the header util so both the proxy path and presigned URL path share the same inline/attachment allowlist. - Added MinIO service to `docker-compose.dev.yml` (optional `s3` profile) for local S3 testing. - Documented S3 presigned URL setup, CORS, and `nosniff` requirements in the self-hosting docs. ## Test plan - [x] All 63 unit tests pass across 5 test suites (util, S3 driver, validated driver, file storage service, controller) - [x] `npx nx typecheck twenty-server` passes - [ ] Manual E2E test with MinIO: `docker compose --profile s3 up -d`, configure S3 env vars, verify `curl -I` returns 302 with `Location` header pointing to MinIO - [ ] Verify local storage (no `STORAGE_S3_PRESIGNED_URL_BASE`) still streams files with 200 + security headers - [ ] Verify public assets endpoint still proxies (no redirect) Made with [Cursor](https://cursor.com) |
||
|
|
89300564ba |
Add a note to documentation about variable change (#18752)
Fixes https://github.com/twentyhq/twenty/issues/18646 --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
70a060b4ee |
docs: fix contributor docs links and typos (#18637)
## Summary This PR fixes several small documentation issues in the contributor and setup guides: - fixes broken docs links in the root README - corrects multiple typos and capitalization issues in contributor docs - fixes malformed Markdown for the Redis command in local setup - improves wording in the Docker Compose self-hosting guide ## Changes - updated README installation links to the current docs routes - changed `Open-source` to `open-source` - fixed `specially` -> `especially` in the frontend style guide - normalized `MacOS` -> `macOS`, `powershell` -> `PowerShell`, and `Postgresql` -> `PostgreSQL` - replaced the invalid `localhost:5432` Markdown link with inline code - fixed the malformed fenced code block for `brew services start redis` - cleaned up Redis naming/capitalization and a few grammar issues in the setup docs - improved the warning and environment-variable wording in the Docker Compose guide ## Testing - not run; docs-only changes --------- Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com> |
||
|
|
f0c83434a7 |
feat: default code interpreter and logic function to Disabled in production (#18559)
## Summary For security reasons, the code interpreter and logic function drivers now default based on `NODE_ENV`: - **Production** (`NODE_ENV=production` or unset): Default to **Disabled** - **Development** (`NODE_ENV=development`): Default to **LOCAL** for convenience This ensures self-hosted production deployments don't accidentally run user-provided code without explicit configuration. ## Changes ### Config (`config-variables.ts`) - `CODE_INTERPRETER_TYPE`: Disabled in prod, LOCAL in dev - `LOGIC_FUNCTION_TYPE`: Disabled in prod, LOCAL in dev ### Documentation (`setup.mdx`) - Added **Security Defaults** section explaining NODE_ENV-based behavior - Fixed variable names: `SERVERLESS_TYPE` → `LOGIC_FUNCTION_TYPE`, `SERVERLESS_LAMBDA_*` → `LOGIC_FUNCTION_LAMBDA_*` - Added **Code Interpreter** section with available drivers (Disabled, Local, E2B) ### Environment files - `.env.example`: Updated to `LOGIC_FUNCTION_TYPE` with comments - `.env.test`: Added `LOGIC_FUNCTION_TYPE=LOCAL` for logic function integration tests Made with [Cursor](https://cursor.com) --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> |
||
|
|
9d57bc39e5 |
Migrate from ESLint to OxLint (#18443)
## Summary Fully replaces ESLint with OxLint across the entire monorepo: - **Replaced all ESLint configs** (`eslint.config.mjs`) with OxLint configs (`.oxlintrc.json`) for every package: `twenty-front`, `twenty-server`, `twenty-emails`, `twenty-ui`, `twenty-shared`, `twenty-sdk`, `twenty-zapier`, `twenty-docs`, `twenty-website`, `twenty-apps/*`, `create-twenty-app` - **Migrated custom lint rules** from ESLint plugin format to OxLint JS plugin system (`@oxlint/plugins`), including `styled-components-prefixed-with-styled`, `no-hardcoded-colors`, `sort-css-properties-alphabetically`, `graphql-resolvers-should-be-guarded`, `rest-api-methods-should-be-guarded`, `max-consts-per-file`, and Jotai-related rules - **Migrated custom rule tests** from ESLint `RuleTester` + Jest to `oxlint/plugins-dev` `RuleTester` + Vitest - **Removed all ESLint dependencies** from `package.json` files and regenerated lockfiles - **Updated Nx targets** (`lint`, `lint:diff-with-main`, `fmt`) in `nx.json` and per-project `project.json` to use `oxlint` commands with proper `dependsOn` for plugin builds - **Updated CI workflows** (`.github/workflows/ci-*.yaml`) — no more ESLint executor - **Updated IDE setup**: replaced `dbaeumer.vscode-eslint` with `oxc.oxc-vscode` extension, configured `source.fixAll.oxc` and format-on-save with Prettier - **Replaced all `eslint-disable` comments** with `oxlint-disable` equivalents across the codebase - **Updated docs** (`twenty-docs`) to reference OxLint instead of ESLint - **Renamed** `twenty-eslint-rules` package to `twenty-oxlint-rules` ### Temporarily disabled rules (tracked in `OXLINT_MIGRATION_TODO.md`) | Rule | Package | Violations | Auto-fixable | |------|---------|-----------|-------------| | `twenty/sort-css-properties-alphabetically` | twenty-front | 578 | Yes | | `typescript/consistent-type-imports` | twenty-server | 3814 | Yes | | `twenty/max-consts-per-file` | twenty-server | 94 | No | ### Dropped plugins (no OxLint equivalent) `eslint-plugin-project-structure`, `lingui/*`, `@stylistic/*`, `import/order`, `prefer-arrow/prefer-arrow-functions`, `eslint-plugin-mdx`, `@next/eslint-plugin-next`, `eslint-plugin-storybook`, `eslint-plugin-react-refresh`. Partial coverage for `jsx-a11y` and `unused-imports`. ### Additional fixes (pre-existing issues exposed by merge) - Fixed `EmailThreadPreview.tsx` broken import from main rename (`useOpenEmailThreadInSidePanel`) - Restored truthiness guard in `getActivityTargetObjectRecords.ts` - Fixed `AgentTurnResolver` return types to match entity (virtual `fileMediaType`/`fileUrl` are resolved via `@ResolveField()`) ## Test plan - [x] `npx nx lint twenty-front` passes - [x] `npx nx lint twenty-server` passes - [x] `npx nx lint twenty-docs` passes - [x] Custom oxlint rules validated with Vitest: `npx nx test twenty-oxlint-rules` - [x] `npx nx typecheck twenty-front` passes - [x] `npx nx typecheck twenty-server` passes - [x] CI workflows trigger correctly with `dependsOn: ["twenty-oxlint-rules:build"]` - [x] IDE linting works with `oxc.oxc-vscode` extension |
||
|
|
1affa1e004 |
chore(front): remove vite-plugin-checker background TS/ESLint checks (#18437)
## Summary Removes `vite-plugin-checker` and all references to `VITE_DISABLE_TYPESCRIPT_CHECKER` / `VITE_DISABLE_ESLINT_CHECKER`. These background checks are no longer needed because our dev experience now relies on **independent** linters and type-checkers: - `npx nx lint:diff-with-main twenty-front` for ESLint - `npx nx typecheck twenty-front` for TypeScript Running these as separate processes (rather than inside Vite) is faster, gives cleaner output, and avoids the significant memory overhead that `vite-plugin-checker` introduces during `vite dev` and `vite build`. The old env vars to disable them are removed from `vite.config.ts`, `package.json` scripts, `nx.json`, `.env.example`, and all translated docs. |
||
|
|
7a2e397ad1 |
Complete linaria migration (#18361)
## Summary
Completes the migration of the frontend styling system from **Emotion**
(`@emotion/styled`, `@emotion/react`) to **Linaria** (`@linaria/react`,
`@linaria/core`), a zero-runtime CSS-in-JS library where styles are
extracted at build time.
This is the final step of the migration — all ~494 files across
`twenty-front`, `twenty-ui`, `twenty-website`, and `twenty-sdk` are now
fully converted.
## Changes
### Styling Migration (across ~480 component files)
- Replaced all `@emotion/styled` imports with `@linaria/react`
- Converted runtime theme access patterns (`({ theme }) => theme.x.y`)
to build-time `themeCssVariables` CSS custom properties
- Replaced `useTheme()` hook (from Emotion) with
`useContext(ThemeContext)` where runtime theme values are still needed
(e.g., passing colors to non-CSS props like icon components)
- Removed `@emotion/react` `css` helper usages in favor of Linaria
template literals
### Dependency & Configuration Changes
- **Removed**: `@emotion/react`, `@emotion/styled` from root
`package.json`
- **Added**: `@wyw-in-js/babel-preset`, `next-with-linaria` (for
twenty-website SSR support)
- Updated Nx generator defaults from `@emotion/styled` to
`@linaria/react` in `nx.json`
- Simplified `vite.config.ts` (removed Emotion-specific configuration)
- Updated `twenty-website/next.config.js` to use `next-with-linaria` for
SSR Linaria support
### Storybook & Testing
- Removed `ThemeProvider` from Emotion in Storybook previews
(`twenty-front`, `twenty-sdk`)
- Now relies solely on `ThemeContextProvider` for theme injection
### Documentation
- Removed the temporary `docs/emotion-to-linaria-migration-plan.md`
(migration complete)
- Updated `CLAUDE.md` and `README.md` to reflect Linaria as the styling
stack
- Updated frontend style guide docs across all locales
## How it works
Linaria extracts styles at build time via the `@wyw-in-js/vite` plugin.
All expressions in `styled` template literals must be **statically
evaluable** — no runtime theme objects or closures over component state.
- **Static styles** use `themeCssVariables` which map to CSS custom
properties (`var(--theme-color-x)`)
- **Runtime theme access** (for non-CSS use cases like icon `color`
props) uses `useContext(ThemeContext)` instead of Emotion's `useTheme()`
|
||
|
|
da6f1bbef3 |
Rename serverlessFunction to logicFunction (#17494)
## Summary Rename "Serverless Function" to "Logic Function" across the codebase for clearer naming. ### Environment Variable Changes | Old | New | |-----|-----| | `SERVERLESS_TYPE` | `LOGIC_FUNCTION_TYPE` | | `SERVERLESS_LAMBDA_REGION` | `LOGIC_FUNCTION_LAMBDA_REGION` | | `SERVERLESS_LAMBDA_ROLE` | `LOGIC_FUNCTION_LAMBDA_ROLE` | | `SERVERLESS_LAMBDA_SUBHOSTING_URL` | `LOGIC_FUNCTION_LAMBDA_SUBHOSTING_URL` | | `SERVERLESS_LAMBDA_ACCESS_KEY_ID` | `LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID` | | `SERVERLESS_LAMBDA_SECRET_ACCESS_KEY` | `LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY` | ### Breaking Changes - Environment variables must be updated in production deployments - Database migration renames `serverlessFunction` → `logicFunction` tables |
||
|
|
6a709d9c50 |
feat(serverless): add basic sandbox isolation and flexible driver options (#17176)
## Overview - Add a DISABLED serverless driver to explicitly turn off execution - Clarify self-hosting docs with driver options and recommended usage - Keep integration coverage for serverless function execution (default + external package example) ## Notes - Local driver remains the default for development usage; Lambda or Disabled recommended for production deployments - No functional changes to Lambda execution <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces flexible serverless execution modes and safer local execution. > > - **New driver:** `DISABLED` serverless driver with wiring in `serverless.interface`, factory, module provider, and GraphQL exception mapping; new exception code `SERVERLESS_FUNCTION_DISABLED`. > - **Local driver hardening:** Strip `NODE_OPTIONS` when spawning child processes; cleanup promise signature; better log capture. > - **Dependency build reliability:** Use `execFile` with bundled Yarn (`.yarn/releases/yarn-4.9.2.cjs`), strip `NODE_OPTIONS`, improved error messages, and parallel cleanup excluding `node_modules`. > - **Docs:** Add serverless section detailing `SERVERLESS_TYPE` options (LOCAL, LAMBDA, DISABLED), security notice, and recommended configs. > - **Config/env:** Default `IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS` set to `true` (examples/tests default `false`); sample envs updated. > - **Tests:** Add integration tests and GraphQL helpers for creating, updating, publishing, executing, and deleting serverless functions, including external package usage and error paths. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1a2958cc19cff1b0108c51b83095bbf95e75d931. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> |
||
|
|
0dec4b9b67 |
docs: add IS_MULTIWORKSPACE_ENABLED documentation (#16758)
## Summary Adds comprehensive documentation for the `IS_MULTIWORKSPACE_ENABLED` configuration variable, which was previously undocumented despite being a fundamental configuration option that significantly changes how Twenty behaves. ## Changes ### Self-Host Setup Guide (`setup.mdx`) Added a new **Multi-Workspace Mode** section that explains: - **Single-workspace mode (default)**: Only one workspace allowed, first user gets admin privileges, signups disabled after first workspace - **Multi-workspace mode**: Multiple workspaces with subdomain-based URLs (e.g., `sales.your-domain.com`) - **Related config variables**: `DEFAULT_SUBDOMAIN` and `IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS` - **DNS configuration**: Wildcard DNS setup for dynamic subdomains - **Workspace creation restrictions**: How to limit workspace creation to server admins ### Local Setup Guide (`local-setup.mdx`) Added an info callout in the environment variables section to make contributors aware of multi-workspace mode, useful when testing subdomain-based features. ## Why This Matters The `IS_MULTIWORKSPACE_ENABLED` variable controls: - Whether multiple workspaces can exist on a single instance - URL structure (plain domain vs subdomains) - First user privileges - Sign-up behavior after initial setup - SSO workspace resolution logic This is critical knowledge for self-hosters who want to run Twenty as a multi-tenant SaaS. |
||
|
|
0731a616b7 |
Restore navigation structure from PR #16705 (#16742)
## Summary The merge conflict resolution from PR #16705 incorrectly discarded the new documentation structure changes. This PR updates the navigation JSON files (the correct approach) to restore the intended changes. ## Changes restored - New 'Capabilities' and 'How-Tos' subgroups organization - Renamed sections (e.g., 'Getting Started' → 'Discover Twenty') - New sections: Data Migration, Calendar & Emails, AI, Views & Pipelines, Dashboards, Permissions & Access, Billing - Reorganized Developers section with Extend, Self-Host, and Contribute groups ## Files updated - `navigation/base-structure.json` - `navigation/navigation-schema.json` - `navigation/navigation.template.json` ## Context PR #16705 was merged but the merge conflict was incorrectly resolved, causing all the structural changes to be lost. The previous fix (PR #16741) updated docs.json directly, but the correct approach is to update the navigation JSON files instead. This PR properly restores those changes from the final commit of PR #16705 (`c856e0d598a0056c2bdaf528502e08261daf7c7c`). --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
183d034716 |
User guide structure update (#16705)
Reorganizing by Feature sections Capabilities folders to give an overview of each feature How-Tos folders to give guidance for advanced customizations Reorganized the Developers section as well, moving the API sub section there added some new visuals and videos to illustrate the How-Tos articles checked the typos, the links and added a section at the end of the doc.json file to redirect existing links to the new ones (SEO purpose + continuity of the user experience) What I have not updated is the "l" folder that, per my understanding, contains the translation of the User Guide - that I only edited in English <!-- CURSOR_SUMMARY --> --- > [!NOTE] > <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is generating a summary for commit 5301502a32856e5b45d7ef30253fa7db6dc55233. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Abdul Rahman <ar5438376@gmail.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com> |