f663cd3c684ef0bb65a697ba7af67a366aeefa0a
45 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. -->
|
||
|
|
cc8fac46c3 |
Add licensing section to legal FAQ (#23560)
<!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23560?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> |
||
|
|
6d60fac92f |
Dashboard doc fix (#23475)
<!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23475?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. --> |
||
|
|
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. --> |
||
|
|
1ee08ff92b |
docs: set correct credit cost for workflow steps and app logic functions (#23297)
The Credits page listed the app logic function row as "A small fraction of a credit / Thousands per credit", which understates the rate. A workflow step and a logic function run each cost a flat 100 micro-credits (`workflow-executor.workspace-service.ts:353`, `logic-function-executor.service.ts:536`), i.e. $0.0001, or 10,000 runs per credit. Since the two rows carried the same rate stated twice, they're merged into one. Also adds a note that Call Recorder and Last contact don't consume credits for their logic function runs. They're in `MARKETPLACE_BILLING_EXEMPT_UNIVERSAL_IDENTIFIERS`, which is 2 of the 3 apps currently in `MARKETPLACE_VETTED_APPLICATIONS`. The note is explicit that the exemption covers only the per-run charge, since those apps still bill metered work (recorded call minutes) through `chargeCredits`. ## Test plan Docs-only change. Rates cross-checked against `workflow-executor.workspace-service.ts` and `logic-function-executor.service.ts`; the exempt list against `marketplace-billing-exempt-applications.constant.ts` and `marketplace-vetted-applications.constant.ts`. Co-authored-by: Martin <martin@twenty.com> |
||
|
|
00e5917d4d |
Documentation update (#23091)
<!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23091?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. --> |
||
|
|
b47e64c9e3 |
docs: surface the self-serve partner marketplace on high-intent pages (#22719)
## Summary Adds partner-marketplace CTAs to four high-intent docs pages (enterprise + migration), routing readers to the **self-serve** partner directory (`twenty.com/partners/list`) while keeping `contact@twenty.com` as a secondary option. This upgrades pages that previously only offered the old "email us to be matched" path (or no partner path at all). Rendered with Mintlify-native components — `<Tip>` callouts, plus a `<CardGroup>` on the Implementation Services page. No new snippet; no `docs.json`, navigation, or translation (`l/`) changes. ## Pages changed — screenshots (one per page) > Preview locally with `npx nx run twenty-docs:dev` (localhost:3000), or use the Mintlify PR preview once it posts on this PR. Paths below are under `docs.twenty.com`. ### 1. `/user-guide/permissions-access/capabilities/sso-configuration` `<Tip>` callout → *Find a certified Twenty partner* (Solutioning), `contact@twenty.com` as a secondary aside. _screenshot:_ <img width="712" height="616" alt="Screenshot 2026-07-09 at 12 14 05" src="https://github.com/user-attachments/assets/e6521634-7783-466f-bfae-a4a49f64d941" /> ### 2. `/user-guide/data-migration/how-tos/migrating-from-self-hosted-to-cloud` `<Tip>` callout → *Get a certified Twenty partner* (Hosting), contact fallback. _screenshot:_ <img width="665" height="193" alt="Screenshot 2026-07-09 at 12 14 23" src="https://github.com/user-attachments/assets/30ecb4d2-fb7e-4e0f-9355-491713290f90" /> ### 3. `/user-guide/data-migration/how-tos/migrating-from-other-crms` `<Tip>` callout → **Done for you** (partner) vs **Onboarding pack** (Twenty team). _screenshot:_ <img width="659" height="273" alt="Screenshot 2026-07-09 at 12 14 35" src="https://github.com/user-attachments/assets/9cc5bb3e-c8be-4734-9e03-dc5b536eeeb7" /> ### 4. `/user-guide/getting-started/capabilities/implementation-services` `<CardGroup>` → **Browse certified partners** / **Get matched by Twenty**. _screenshot:_ <img width="706" height="766" alt="Screenshot 2026-07-09 at 12 14 47" src="https://github.com/user-attachments/assets/01b69197-0f47-46fe-a40e-92c11286827e" /> ## Notes for reviewers - Links deep-link the directory via `?categories=<scope>` (verified live) and carry a `?ref=docs-*` tag. - **Attribution caveat:** twenty.com's analytics (Cloudflare Web Analytics) is path-based, so `?ref=` is not measurable yet. - `contact@twenty.com` intentionally kept as a secondary option. - `mintlify validate` passes. Opened as a draft. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22719?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. --> |
||
|
|
b5b6e110b0 |
Merge app Public URL and Public Domains settings into one App URL section (#22666)
## Context
The app settings tab showed two sections for the same concept: a "Public
URL" block with a very technical description (Permissions-Policy, COOP,
COEP), a blue info banner about the legacy `/s/` endpoint, and a
separate "Public Domains" block. Confusing, and scary-sounding for apps
whose routes are not really "public".
## Changes
**One merged "App URL" section** (still only rendered for apps that
actually expose HTTP-triggered functions):
- Title renamed to the neutral "App URL" with a one-line description:
"This app's routes are served from this URL. Add a custom domain to use
your own."
- Read-only copyable base URL input, custom domain list card right below
it.
- Removed the info banner and all header/CORS jargon.
**Always show the real URL**: `getFunctionsBaseUrl` now takes
`serverBaseUrl` and falls back to `${serverBaseUrl}/s` instead of
returning `undefined`, so self-hosted instances (no dedicated function
domain) see their actual base URL instead of nothing. This centralizes
the fallback previously duplicated in `FrontComponentRenderer` and
`getLogicFunctionHttpUrl`.
**"Public Domain" renamed to "Custom Domain"** in all user-facing
strings (add card, footer button, detail page, snackbars). Internal
identifiers, GraphQL types and routes keep the `PublicDomain` name to
match the backend entity.
**Polish**:
- Domain rows and the add card use a world icon instead of the mail
icon.
- Row description shows "Added x days ago" instead of a raw ISO
timestamp, via a new shared `useGetAddedRelativeDateDescription` hook
also adopted by the approved access domains card that had the same
inline helper.
- `FrontComponentRenderer` consumes `functionsBaseUrl` from
`useGetLogicFunctionHttpUrl` instead of re-deriving it from the same
atoms.
- User docs updated accordingly.
## Testing
- Ran the app locally (Postgres/Redis + server + front), synced a
fixture app with an HTTP-triggered logic function, and verified the
merged section renders correctly with the copyable URL and Add Custom
Domain card, no banner, no duplicate section.
- `getLogicFunctionHttpUrl` unit tests updated and passing (7/7), `npx
nx typecheck twenty-front` and `lint:diff-with-main` green.
- Locale catalogs are untouched; Crowdin sync regenerates them from the
new source strings.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01NyEWoybMBq62cSNfAFdJAT)_
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22666?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. -->
|
||
|
|
46ef8a8813 |
Update workflows documentation (#22356)
## Summary Documentation-only updates to the workflow and logic-function docs: - **Code action ↔ logic functions**: clarify that each Code action is backed by its own logic function, and document how to reuse logic across workflows via `workflowActionTriggerSettings` (Code/User Guide + Logic Functions/Developer docs cross-linked). - **`workflowActionTriggerSettings` example**: add a complete example (`label`, `icon`, `inputSchema`, `outputSchema`) and document the previously-undocumented `outputSchema` field. - **Iterator improvements** (docs for #22031): document the new **"Use the whole item"** (reference the whole current item) and **"Whole list"** (loop over a step's top-level array output) options across the Iterator and array-handling guides. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22356?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. --> |
||
|
|
407273cff2 |
fix(docs): correct typos in multiple files (#22173)
Corrects spelling errors across three documentation files. - `indivual` -> `individual` in `./CLAUDE.md` - `accesible` -> `accessible` in `./packages/twenty-docs/user-guide/getting-started/how-tos/navigate-around-twenty.mdx` - `editting` -> `editing` in `packages/twenty-docs/user-guide/views-pipelines/overview.mdx` <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22173?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: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
19bdf2122a |
docs(user-guide): remove unsupported Between operator for Date filters (#22136)
## What The Filters & Sorting user guide lists a **Between** operator for **Date** fields, but this operator is not currently supported by the product. This removes it from the Date operators table. | Field Type | Before | After | |---|---|---| | Date | Equals, Before, After, **Between**, Is empty | Equals, Before, After, Is empty | ## Why Avoids documenting a capability that does not currently exist. The shared `ViewFilterOperand` enum does not define an `IS_BETWEEN` operand, and the Date filter operands map does not include a Between operator. Related to #20932. ## Notes - Documentation-only change. - Only the canonical English source is edited. - Localized copies under `packages/twenty-docs/l/*` are expected to be regenerated by the existing docs translation workflow. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22136?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. --> |
||
|
|
ea3090e553 |
docs: rewrite billing credits page to clarify credit value and usage (#22099)
Rewrites the billing **Credits** doc so it actually explains what a credit is worth and how far it goes — the previous version listed bare credit counts and described AI cost only as "variable based on usage." What changed: - Leads with **1 credit = $1 of usage**, so the balance is easy to reason about. - Adds a "How far does a credit go?" table grounded in how billing actually works: standard workflow steps cost ~$0.0001 each, quick AI messages a fraction of a cent, while large multi-step agent tasks (e.g. configuring several objects) can run to ~$1 or more. - Explains that AI usage is metered at the model providers' published token rates and converted straight to credits — no marked-up internal rate. - Reframes allocation (5/mo, 50/yr) in terms of equivalent dollar usage, and tightens the rollover, monitoring, and top-up sections. Docs-only change; no code or behavior affected. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22099?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. --> |
||
|
|
5a55c2563e |
Update location of settings (#22033)
In the latest version the «Lab Features» are no longer called like that and are in a different location. See [Discord-Discussion](https://discord.com/channels/1130383047699738754/1508471962308051116) <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22033?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. --> |
||
|
|
1ec59beb8b |
docs(user-guide): remove unsupported Between operator for Number filters (#21838)
## What The [Filters & Sorting user guide](https://docs.twenty.com/user-guide/views-pipelines/capabilities/filters-and-sorting) lists a **Between** operator for **Number** fields, but it does not exist in the product and we do not plan to implement it. This removes it from the operators table. | Field Type | Before | After | |---|---|---| | Number | Equals, Greater than, Less than, **Between**, Is empty | Equals, Greater than, Less than, Is empty | The **Date** row is intentionally left untouched. ## Why Avoids documenting a capability that does not exist (the same gap that prompted #20932). Closing the external PR that attempted to add it for numbers; the docs should reflect what we actually ship. ## Notes - Only the canonical English source is edited; localized copies under `packages/twenty-docs/l/*` are regenerated by the existing i18n docs-translation workflow. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21838?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. --> |
||
|
|
91050dba8d |
docs: update calendar-email page (#21719)
Adds 3 changes 1.) Add IMAP mention 2.) Clarifies disabling SSRF for self hosters running air gapped systems, (we have received this question several times ) 3.) Toggling Syncing internal emails <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21719?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. --> |
||
|
|
dd0039ca1c |
feat(mcp) - optimize instruction prompt and hide get_tool_catalog (#21183)
Workspace-aware initialize.instructions - Deleted the static mcp-server-instructions.const.ts - Created build-mcp-server-instructions.util.ts — a comprehensive system prompt with identity, object list, tool grammar, routing decision tree, intent mapping, skills vs tools, safety constraints, and data efficiency guidelines - Created McpInstructionBuilderService — fetches workspace-specific object names + skill names and injects them into the instructions Hide/deprecate get_tool_catalog Benefit : skip first MCP call (tools are included in instruction) |
||
|
|
d602f35cbd |
feat(data-model): custom-indexes management UI and mutations (#20846)
## Summary
Brings indexes management into the per-object Settings tab as a section
under Search (no feature flag, advanced mode only). Admins can create /
delete non-unique indexes with the UI; apps can declare indexes in code
with `defineIndex`. Composite-typed fields are now indexable by picking
a specific sub-column (e.g. `Address > City`).
A few related polish items also land here (invite-user dropdown lands on
the Invite tab; standard warning callout above the new-index form).
## What ships
### UI — custom indexes on per-object Settings
- New section directly under Search, wrapped in
`AdvancedSettingsWrapper`.
- Filter dropdown on the search bar toggles system-index visibility
(shown by default since advanced mode).
- **+ Add Index** button (disabled with tooltip once the per-object cap
is reached) navigates to a dedicated `SettingsObjectNewIndex` page
(matches the field-creation pattern, not a modal):
- Field picker mirrors the webhook event-form layout (rows of dropdowns,
implicit trailing empty row).
- Composite fields surface their sub-properties (`Address > City`,
`Currency > Amount`, …).
- BTREE / GIN type selector.
- Standard warning Callout: "Use indexes sparingly — each one speeds
reads but slows writes."
- Trash icon on `isCustom: true` rows → confirmation modal →
`deleteOneIndex`.
### Server — `createOneIndex` / `deleteOneIndex` mutations
- Gated by `SettingsPermissionGuard(DATA_MODEL)`.
- `IndexMetadataService` wraps the existing migration runner via
`WorkspaceMigrationValidateBuildAndRunService` so the metadata row and
the SQL index land atomically.
- Validation: rejects empty fields, duplicate `(fieldMetadataId,
subFieldName)` pairs, fields not on the object, requires `subFieldName`
for composite parents, forbids `subFieldName` on scalar/relation,
enforces `MAX_CUSTOM_INDEXES_PER_OBJECT = 10`.
- Delete refuses on `isCustom: false` rows so system indexes can't be
removed via this API.
- Dedicated GraphQL exception handler maps each typed error to the right
transport error class.
### Composite sub-field indexing
- Adds `subFieldName: string | null` column to
`IndexFieldMetadataEntity` (fast instance command).
- The flat-entity flow (`UniversalFlatIndexFieldMetadata`,
`FlatIndexFieldMetadata`, `from-universal-flat-index-to-flat-index`,
runner column resolution) all carry `subFieldName` through.
- For composite parents, the runner uses
`computeCompositeColumnName({...}, property)` for the picked sub-column;
for non-composite parents, behavior is unchanged.
- The `'::'` separator encodes `(fieldMetadataId, subFieldName)` for
dedup on the wire; the frontend uses the same separator inside the
Select component's string value.
### Apps can declare indexes in code (`defineIndex`)
- New `IndexManifest` + `IndexFieldManifest` types in
`twenty-shared/application` wired into the `Manifest` type.
- `defineIndex` SDK helper + `IndexConfig`. CLI manifest builder +
extractor recognize `defineIndex` / `ManifestEntityKey.Indexes`.
- Server: `from-index-manifest-to-universal-flat-index` converter
resolves field IDs, validates composite/scalar `subFieldName` rules, and
delegates to `generateFlatIndexMetadataWithNameOrThrow` for the
deterministic name.
- Orchestrator wires the loop after the field-resolution pass;
per-object cap enforced inline against the manifest.
- Cascade on uninstall is automatic — when an app disappears its indexes
drop with it (universal-flat-entity diff handles it).
- Rich-app fixture ships a real `defineIndex` on `PostCard.status`,
exercising the full manifest → install path in CI.
### Closed for now (open later if needed)
- Apps cannot declare `isUnique` indexes — unique constraints stay with
the field-creation flow.
- Apps cannot use a partial-`indexWhereClause` — the UI surface keeps
the framework's hardcoded allowlist.
- UI cannot create unique or partial indexes either; same reasons.
### Cleanups along the way
- Reused the existing `getCompositeSubFieldLabel` +
`COMPOSITE_FIELD_SUB_FIELD_LABELS` (deleted the duplicates I'd created
early in the PR).
- Moved `MAX_CUSTOM_INDEXES_PER_OBJECT` to `twenty-shared/constants`
(single source for FE + BE).
- Replaced inline `isDefined(x) && x !== ''` with `isNonEmptyString`
(from `@sniptt/guards`).
- Hoisted the per-object fields Map + inlined the cap counter into the
indexes orchestrator loop (drops the install scan from O(indexes ×
totalFields) to O(totalFields + indexes)).
- Per design-feedback: page-based create flow (not a modal), filter
dropdown on the SearchInput (not a separate toggle), webhook-style
picker, field icons.
### Unrelated polish that lands here
- "Invite user" link in the multi-workspace dropdown now lands on the
Invite tab directly (`#invite`) instead of the first tab of the members
page.
## Test plan
- [ ] `npx nx typecheck twenty-server / twenty-front / twenty-sdk /
twenty-shared` — passes
- [ ] `npx nx lint:diff-with-main twenty-server / twenty-front` — clean
- [ ] `npx jest index-metadata.service.spec` — green
- [ ] `npx jest from-index-manifest-to-universal-flat-index` — green
(new converter spec, 8 cases)
- [ ] `npx vitest run
src/sdk/define/indexes/__tests__/define-index.spec.ts` (twenty-sdk) —
green (6 cases)
- [ ] `npx vitest run --config vitest.integration.config.ts -t
"rich-app"` — green (rich-app app-dev integration exercises the new
manifest path with the PostCard.status index)
- [ ] Advanced mode → Settings → any object → Settings tab → Indexes
section is visible under Search
- [ ] Create a single-field BTREE index, confirm SQL index exists
(verify via `pg_indexes`)
- [ ] Create a composite-field index (`Address > City`) and confirm the
column is `addressAddressCity`
- [ ] Create an index spanning two columns; column order matches the
picker order
- [ ] Attempt to create an 11th custom index → button is disabled with
tooltip
- [ ] Delete a custom index → confirmation modal → row disappears, PG
index dropped
- [ ] System indexes have no trash icon and are hidden by default
|
||
|
|
0edd8d400c |
fix(billing) - fix orphaned stripe subs (#20814)
Fix sentry issues https://twenty-v7.sentry.io/issues/7203797925/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20assigned%3Ame&referrer=issue-stream An orphaned sub is a not "canceled" stripe sub with no matching workspace - Clean all orphaned sub (script not included in this PR) - Ensure to soft delete > cancel stripe sub > check for not active sub > hard delete in every workspace deletion flow Bonus : - Remove dead code - Update doc on RLS (to improve AI chat knowledge) |
||
|
|
626455b534 |
chore(members): rename "Access" tab to "Invite" + fix e2e (#20447)
## Summary Two things, both fallout from #20360: 1. Rename the `Members → Access` tab to `Members → Invite`. The previous label leaned security-flavored; "Invite" reads as the verb users come here to do. 2. Fix the `signup_invite_email` Playwright test (failing on main, e.g. https://github.com/twentyhq/twenty/actions/runs/25671161586/job/75356474079). The invite-link button moved off the default Team tab when the Members page got tabbed; the test was looking for it on the wrong tab. ## Rename details - File: `SettingsWorkspaceMembersAccessTab.tsx` → `SettingsWorkspaceMembersInviteTab.tsx` (single git rename, ~99% similarity) - Exported component: `SettingsWorkspaceMembersAccessTab` → `SettingsWorkspaceMembersInviteTab` - Tab id (and URL hash): `access` → `invite` - Tab title: `Access` → `Invite` - Icon: `IconKey` → `IconUserPlus` - Doc breadcrumbs (3 files): `Members → Access` → `Members → Invite` ## E2E fix `MembersSection` (Page Object Model) now has an `inviteTab` locator (via `getByTestId('tab-invite')`) and a `goToInviteTab()` helper. Both `copyInviteLink` and `sendInviteEmail` click the Invite tab first, so they work regardless of which tab the page lands on initially. Idempotent if already there. ## Test plan - [x] CI green (e2e test + lint + typecheck + format) - Lingui `.po` files will pick up the new source paths on the next translation pass — not touched here. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
34b927ff23 |
feat(public-domain): bind public domains to apps + reorganize settings (#20360)
## Summary - **Public domains can now be bound to a specific app.** When a request hits an app-bound public domain, route resolution restricts logic-function matching to that app's HTTP-routed functions only — isolating each app's routes to its own domain instead of letting routes from other apps in the workspace match nondeterministically. - **Settings sidebar reorganized.** Removed the standalone Domains page. Workspace Domain → General. Approved Domains + Invitations → Members "Access" tab. Emailing Domains + Public Domains → Apps "Developer" tab. Roles → Members "Roles" tab. ## Why The use case: someone building a partner portal app or a lead-collection app declares private objects (leads, partners…) plus a few public HTTP routes. Each app needs its own domain (`partners.acme.com`, `leads.acme.com`) without those domains exposing every other app's routes in the same workspace. Today's PublicDomainEntity is workspace-scoped only, so all HTTP-routed logic functions in a workspace compete for any public domain — first match wins nondeterministically. ## Backend - Added nullable `applicationId` FK to `PublicDomainEntity` (cascade-deleted with the app); indexed for the route-trigger lookup. - New fast instance command `2-4-instance-command-fast-1798000003000-add-application-id-to-public-domain` adds the column, index, and FK constraint. - `createPublicDomain(domain, applicationId)` accepts an optional app binding; new `updatePublicDomain(domain, applicationId)` mutation rebinds/unbinds an existing domain. Both validate the application belongs to the workspace. - `WorkspaceDomainsService.resolveWorkspaceAndPublicDomain(origin)` returns both the workspace and the matched public domain in one query — replacing the old back-to-back lookups in the route-trigger hot path. `getWorkspaceByOriginOrDefaultWorkspace` is preserved as a thin wrapper. - `RouteTriggerService` filters `logicFunction` by `applicationId` when the matched public domain is app-scoped; falls back to workspace-wide when unbound. - Three sequential validation queries in `createPublicDomain` now run in parallel via `Promise.all`. ## Frontend | Old location | New location | |---|---| | Settings sidebar → Domains (standalone page) | Removed | | Domains page → Workspace Domain | General page | | Domains page → Approved Domains | Members → Access tab | | Domains page → Emailing Domains | Apps → Developer tab | | Domains page → Public Domains | Apps → Developer tab | | Settings sidebar → Roles (standalone) | Members → Roles tab | | `pages/settings/roles/` | `pages/settings/members/roles/` | - The Public Domain detail page has an Application picker that uses `Select`'s native `emptyOption` + `null` value pattern (matches `SettingsDataModelObjectIdentifiersForm`). - Members page tabs use the existing `TabListFromUrlOptionalEffect` mechanism (rendered automatically by `TabList`) for hash-based tab activation. - `/settings/members/roles` redirects to `/settings/members#roles` so role sub-pages' `navigate(SettingsPath.Roles)` lands on the Members page with the Roles tab pre-selected. - All affected breadcrumbs updated to nest under their new parents. - `SettingsPath.Roles` and friends now nest under `members/`; `Subdomain` and `CustomDomain` under `general/`; `PublicDomain` and `EmailingDomain` under `applications/`. ## Test plan - [x] `nx typecheck twenty-front` passes - [x] `nx typecheck twenty-server` passes - [x] `oxlint --type-aware` clean on all touched files - [x] `prettier --check` clean on all touched files - [x] Migration applied locally; `publicDomain.applicationId` (uuid, nullable) confirmed in DB - [x] GraphQL schema exposes `PublicDomain.applicationId`, `createPublicDomain.applicationId`, `updatePublicDomain` mutation - [x] **End-to-end route resolution scenarios verified locally:** - Domain bound to App A, function in App A → route matches ✅ - Domain bound to App B, function in App A → route does NOT match (HTTP 404 `TRIGGER_NOT_FOUND`) ✅ - Domain unbound (`applicationId = NULL`) → route matches workspace-wide ✅ - Unknown path on bound domain → returns 404 cleanly ✅ - [x] UI sanity (browser-tested at `apple.localhost:3001`): - General page shows Workspace Domain card - Members page shows Team / Access / Roles tabs - Access tab combines Invite by link + by email + Approved Domains - Roles tab embeds the role list - `/settings/members/roles` direct URL → redirects + Roles tab pre-selected - Apps Developer tab shows Emailing Domains + Public Domains sections - Public Domain detail page has Application picker dropdown listing workspace apps - Sidebar nav: "Domains" and "Roles" no longer present (now folded into General/Members) ## Notes for reviewers - Creating a public domain via the UI still requires Cloudflare credentials in the dev `.env` (`CLOUDFLARE_API_KEY`, `CLOUDFLARE_PUBLIC_DOMAIN_ZONE_ID`, `PUBLIC_DOMAIN_URL`). The DNS step is unchanged from main. - The `applicationId` column is nullable, so existing public-domain rows continue to work workspace-wide — no data backfill required. - `SettingsRolesContainer` was deleted (no longer referenced after `SettingsRoles` index page was removed). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
15c52d3a39 |
Documentation update (#20059)
Add missing info about how to edit navigation bar, add many-to-many relation and get Enterprise key for Org license on self-hosted --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
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> |
||
|
|
e68842c268 |
Billing - fixes (#19867)
- Uniformize credit formating : In UI, 1$=1credit. In BE 1 UI credit = 1_000_000 BE "crédits" - Add crédit rollover information + Link to documentation + Documentation update <img width="291" height="317" alt="Screenshot 2026-04-17 at 18 22 59" src="https://github.com/user-attachments/assets/2519fb9f-159d-4c85-95f4-a6e005a8a1a3" /> <img width="848" height="763" alt="Screenshot 2026-04-17 at 14 12 20" src="https://github.com/user-attachments/assets/a3cc0874-f275-49ea-819f-305ec314bdfe" /> <img width="797" height="757" alt="Screenshot 2026-04-17 at 14 12 13" src="https://github.com/user-attachments/assets/9048409b-d5a2-435a-b735-70370705e668" /> - Enable direct top-up (or subscription if in trial) from AI chat <img width="333" height="215" alt="Screenshot 2026-04-17 at 22 52 00" src="https://github.com/user-attachments/assets/7a20c627-2806-4bcf-a037-b45752232be9" /> <img width="457" height="769" alt="Screenshot 2026-04-17 at 22 51 41" src="https://github.com/user-attachments/assets/d2a90c1b-271f-4fe9-8891-baeb2fabb86d" /> - Inform users if credit limit is reached - Banner <img width="1130" height="127" alt="Screenshot 2026-04-17 at 19 15 11" src="https://github.com/user-attachments/assets/30723e5e-c07e-462f-8eb8-e08f52bbab1c" /> |
||
|
|
5c867303e0 |
Fix documentation about importing dates (#19434)
Related to https://github.com/twentyhq/core-team-issues/issues/2364 |
||
|
|
b002930554 |
Update documentation on how to upload a file (#19197)
As per title, update a documentation on how to upload a file given increasing amount of questions for this problem CC: @StephanieJoly4 --------- Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com> |
||
|
|
8ef32c4781 |
Add In-Reply-To to Email Workflow Node (#18641)
Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
95a35f8a1d |
Implement OAuth 2.0 Dynamic Client Registration (RFC 7591) (#18608)
## Summary This PR implements OAuth 2.0 Dynamic Client Registration (RFC 7591) and OAuth 2.0 Protected Resource Metadata (RFC 9728) support, enabling third-party applications to dynamically register as OAuth clients without manual configuration. ## Key Changes ### OAuth Dynamic Client Registration - **New Controller**: `OAuthRegistrationController` at `POST /oauth/register` endpoint - Validates client metadata according to RFC 7591 specifications - Enforces PKCE-only public client model (no client secrets) - Supports only `authorization_code` grant type and `code` response type - Rate limits registrations to 10 per hour per IP address - Returns `client_id` and registration metadata in response - **Input Validation**: `OAuthRegisterInput` DTO with constraints on: - Client name (max 256 chars) - Redirect URIs (max 20, validated for security) - Grant types, response types, scopes, and auth methods - Logo and client URIs (max 2048 chars) - **Discovery Endpoint Update**: Added `registration_endpoint` to OAuth discovery metadata ### Stale Registration Cleanup - **Cleanup Service**: Automatically removes OAuth-only registrations older than 30 days that have no active installations - **Cron Job**: Runs daily at 02:30 AM UTC with batch processing (100 records per batch) - **CLI Command**: `cron:stale-registration-cleanup` to manually trigger cleanup ### MCP (Model Context Protocol) Authentication - **New Guard**: `McpAuthGuard` implements RFC 9728 compliance - Wraps JWT authentication with proper error responses - Returns `WWW-Authenticate` header with protected resource metadata URL on 401 - Enables OAuth-protected MCP endpoints ### Protected Resource Metadata - **New Endpoint**: `GET /.well-known/oauth-protected-resource` (RFC 9728) - Advertises MCP resource as OAuth-protected - Lists supported scopes and bearer token methods - Enables OAuth clients to discover authorization requirements ### Application Registration Updates - **New Source Type**: `OAUTH_ONLY` enum value for OAuth-only registrations - **Install Service**: Skips artifact installation for OAuth-only apps (no code artifacts) ### Frontend Updates - **Authorization Page**: Support both snake_case (standard OAuth) and camelCase (legacy) query parameters - `client_id` / `clientId` - `code_challenge` / `codeChallenge` - `redirect_uri` / `redirectUrl` ## Implementation Details - **Rate Limiting**: Uses token bucket algorithm with 10 registrations per 3,600,000ms window per IP - **Scope Validation**: Requested scopes are capped to allowed OAuth scopes; defaults to all scopes if not specified - **Redirect URI Validation**: Uses existing `validateRedirectUri` utility for security - **Cache Headers**: Registration responses include `Cache-Control: no-store` and `Pragma: no-cache` - **Batch Processing**: Cleanup operations process 100 records at a time to avoid memory issues - **Grace Period**: 30-day grace period before cleanup to allow time for client activation https://claude.ai/code/session_01PxcuWFFRuXMASMaMGTLYk2 --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
882e9fd231 |
Docs: restructure Extend section with API, Webhooks, and Apps pages (#18517)
## Summary - Restructures the developer Extend documentation: moves API and Webhooks to top-level pages, creates dedicated Apps section with Getting Started, Building, and Publishing pages - Updates navigation structure (`docs.json`, `base-structure.json`, `navigation.template.json`) - Updates translated docs for all locales and LLMS.md references across app packages ## Test plan - [ ] Run `mintlify dev` locally and verify navigation structure - [ ] Check that all links in the Extend section work correctly - [ ] Verify translated pages render properly Made with [Cursor](https://cursor.com) --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
7f33286274 | Update discord link (#17627) | ||
|
|
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 |
||
|
|
161689be18 |
feat: fix junction toggle persistence and add type-safe documentation paths (#17421)
## Summary - **Fix junction relation toggle not being saved**: The form schema wasn't tracking the `settings` field, so changes to `junctionTargetFieldId` weren't marked as dirty - **Add type-safe documentation paths**: Generate TypeScript constants from `base-structure.json` to prevent broken documentation links - **Create many-to-many relations documentation**: Step-by-step guide for building many-to-many relations using junction objects - **Update `getDocumentationUrl`**: Now uses shared constants from `twenty-shared` for base URL, default path, and supported languages ## Key Changes ### Junction Toggle Fix - Added `settings` field to the form schema in `SettingsDataModelFieldRelationForm.tsx` - Fixed the toggle to properly merge settings when updating `junctionTargetFieldId` ### Type-Safe Documentation Paths - New constants in `twenty-shared/constants`: - `DOCUMENTATION_PATHS` - All 161 documentation paths as typed constants - `DOCUMENTATION_SUPPORTED_LANGUAGES` - 14 supported languages - `DOCUMENTATION_BASE_URL` / `DOCUMENTATION_DEFAULT_PATH` - Generator script: `yarn docs:generate-paths` - CI integration: Added to `docs-i18n-pull.yaml` workflow ### Documentation - New article: `/user-guide/data-model/how-tos/create-many-to-many-relations` - Updated `/user-guide/data-model/capabilities/relation-fields.mdx` with Lab warning and link ## Test plan - [ ] Verify junction toggle saves correctly when enabled/disabled - [ ] Verify documentation link opens correct localized page - [ ] Verify `yarn docs:generate-paths` regenerates paths correctly |
||
|
|
f218d652df |
[Dashboard] Add chart settings/config documentation (#17053)
closes https://github.com/twentyhq/core-team-issues/issues/1973 --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
f70b171843 |
Updating the user guide to reflect available features (#17139)
updated text regarding email attachments in workflows |
||
|
|
25a9d49ff1 |
New article to detail how to attach pdf files to a given record (#17128)
- added article to detail how to attach a pdf to a given record - added link in another article - updated the english section of the docs.json to have the file appear in the left menu - updated the 2 navigation files --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
701a713042 |
Updated the user guide with new article + updated old content (#16955)
- more details on rate at which messages are imported from Gmail - Settings -> Release deprecated to Settings -> Updates => this leads to updating the file title, file name and the navigation files - Support & Documentation accessible via Settings and no longer the nav bar - updated features out of the lab - no more integration page - added a new article with step by step on how to notify a teammate of a note to review docs.json is updated only for the English part --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
60897b255a |
Adding one How To article to the workflow section (#16760)
- added an image, one article - updated the 2 files under the Navigation folder but not the docs.json - no need to redirect the links given this is a new article |
||
|
|
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> |
||
|
|
c38f34df26 |
Release 1.11.0 (#15900)
## Release 1.11.0 This release includes: - Unlisted Views Changelog file: `packages/twenty-website/src/content/releases/1.11.0.mdx` Release date: 2025-11-18 |
||
|
|
12e2820715 |
fix(docs): Use content instead of props for Card titles to enable translation (#15756)
Co-authored-by: Félix Malfait <felix@twenty.com> |
||
|
|
194a579a03 | fix: Replace angle bracket placeholders with curly braces in docs to fix crowdin's tags mismatch errors (#15751) | ||
|
|
f740bac988 |
add documentation i18n workflows for Crowdin (#15538)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com> |
||
|
|
9f97be67b1 |
Migrate documentation to Mintlify and configure 301 redirects (#15502)
## Summary Completes the migration of all documentation from twenty-website to a new Mintlify-powered documentation site at docs.twenty.com. ## Changes Made ### New Package: `twenty-docs` - ✅ Created new Mintlify documentation package - ✅ Migrated 95 content pages (user-guide, developers, twenty-ui) - ✅ Migrated 81 images - ✅ Converted all custom components to Mintlify native components - ✅ Configured navigation with 2 tabs and 94 pages - ✅ Added Helper AI Agent with searchArticles tool for docs search ### Updated: `twenty-website` - ✅ Added 11 redirect rules (301 permanent) in next.config.js - ✅ Removed all documentation content (111 files) - ✅ Removed documentation routes (user-guide, developers, twenty-ui) - ✅ Removed documentation components (9 files) - ✅ Updated keystatic.config.ts - ✅ Preserved all marketing/release pages ### Updated: Core Files - ✅ Updated README.md - docs links point to docs.twenty.com - ✅ Updated CONTRIBUTING.md - code quality link updated - ✅ Updated SupportDropdown.tsx - user guide link updated - ✅ Updated Footer.tsx - user guide link updated |
||
|
|
2c39fc04c2 | feat: Migrate documentation to Mintlify and implement Helper Agent with search functionality (#15443) |