Files
twenty/packages/twenty-apps/internal/twenty-partners/package.json
T
Rashad Karanouh 9d8ce7c325 v1.3.2 — Modularize partners app into vertical-slice modules/ (#23168)
**Version:** `twenty-partners@1.3.2` (patch — internal refactor, no
visible behavior change)

## What & why

Reorganizes the `twenty-partners` SDK app from a flat, type-first layout
(`src/{objects,fields,views,logic-functions,front-components,…}`) into a
**vertical-slice** layout under `src/modules/<domain>/<feature>/`. Files
that
change together now live together; each SDK entrypoint is a thin
discoverable
shim over a service + graphql-ops + mapper/connector layer.

This is a pure structural refactor — **no object, field, view, enum,
logic
function, trigger, role, or application variable changed.**

## Final layout

```
src/modules/
  shared/        http · services · graphql · utils · front-components · navigation-menu-items (cross-domain nav folders)
  opportunity/   fields·view-fields·views·navigation-menu-items·page-layouts·constants + intake/ + matching/
  partner/       objects·fields·constants·utils + directory/ · self-service/ · marketplace/ · application-intake/ (Discord connector/)
  application/   objects·fields·views·navigation-menu-items·page-layouts + services · graphql
```

Every `defineLogicFunction` entrypoint is now a thin
`*.logic-function.ts`
(all < 40 lines) at its domain/feature root, delegating to a
`*.service.ts`;
graphql operations live in `graphql/{queries,mutations}/`, pure
transforms in
`mappers/`, outbound APIs (the Discord webhook) in `connector/`, pure
helpers
in `utils/`.

## Safety — the load-bearing invariant

The server diffs app primitives by `universalIdentifier`, so a
changed/dropped
UUID would drop-and-recreate the object on prod (data loss). This branch
holds
that line:

- **887 `universalIdentifier`s byte-identical** to the branch base
(every
relocation is a `git mv`; every extracted entrypoint keeps its original
UUID/name/trigger verbatim). Re-verified byte-identical across the
rebase.
- `yarn twenty dev --once` against a live workspace = **"No changes.
Twenty
metadata matches your manifest."**, confirmed idempotent on a second run
—
the whole refactor is a metadata no-op (zero create/delete/identity
change).
- Every extracted graphql op was verified **byte-identical** to its
original
(args, `first:` caps, pagination, selection sets), and the
partner-application
Discord embed's deliberate PII omission (no email / hourly rate) is
preserved.

## Rebased onto latest `main`

This branch is rebased onto `main` (`d20e5378fd`) and now carries main's
`twenty-sdk` / `twenty-client-sdk` **2.23.0-alpha.2** bump.

Note for reviewers: main had independently bumped this package to
`1.3.1`, so
the original `1.3.0 → 1.3.1` commit here was redundant and git dropped
it during
the rebase (`patch contents already upstream`) — with **no textual
conflict**,
since both sides wrote the same version string. The bump is therefore
now
**`1.3.2`**. The rebase touched only `package.json` and `yarn.lock`;
**every line
of refactored source is byte-identical** to the pre-rebase tree.

## Verification

All run on the rebased tree, against SDK `2.23.0-alpha.2` and a live
Twenty
server `v2.23.2`:

| Check | Result |
|---|---|
| `universalIdentifier` set | 887, byte-identical |
| `yarn twenty dev --once` | "No changes" (idempotent on re-run) |
| Typecheck | pass |
| `yarn lint` | 0 warnings, 0 errors (287 files) |
| `yarn test:unit` | 158/158 (23 files) |
| `yarn test:integration` | 45/45 (13 files) |

## Also in this PR

- **Architecture convention doc** — `AGENTS.md` (+ a one-line
`CLAUDE.md` pointer)
at the package root documents the vertical-slice conventions this
refactor
establishes: the layout, the dependency rule (`logic-function → service
→
graphql/connector`), file naming, connector = outbound-only (inbound
webhooks
are logic-functions), and the UUID invariant. It ships here so the doc
and the
  structure it describes land together.
- **`modules/shared/`** dedup: the secret-guarded intake envelope, the
find-or-create-company/person helpers + their graphql ops, `collectAll`
  pagination, `http-url`/`strip-markdown`/`is-non-empty-string` utils.
- **Vitest configs collapsed** into one `vitest.config.ts` with `unit` +
  `integration` projects (`yarn test:unit` / `yarn test:integration`).
- Cross-domain nav folders (`pipeline-folder`,
`partner-workspace-folder`)
  hoisted to `modules/shared/navigation-menu-items/`.

## Deferred (non-blocking, tracked follow-ups)

- Add direct unit tests for the shared `collectAll` / `isNonEmptyString`
utils
  (currently covered indirectly).
- Move `submit-client-brief`'s zod schema out of its mapper file into
its own
  schema file (mirroring the partner side).
- Route `stamp-partner-user-on-child` through the shared self-service
mutation ops.
- `find-partner-by-member.ts` is duplicated identically in the
`application` and
  `self-service` domains; a candidate to hoist into `modules/shared/`.
2026-07-23 13:59:00 +02:00

48 lines
1.4 KiB
JSON

{
"name": "twenty-partners",
"version": "1.3.2",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.0.2",
"twenty": ">=2.23.0"
},
"keywords": [],
"packageManager": "yarn@4.13.0",
"scripts": {
"twenty": "twenty",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json .",
"test": "vitest run",
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project integration",
"test:watch": "vitest",
"seed": "tsx src/scripts/seed.ts",
"seed:prod": "ENV_FILE=.env.prod tsx src/scripts/seed.ts",
"purge": "tsx src/scripts/purge-soft-deleted.ts",
"purge:prod": "ENV_FILE=.env.prod tsx src/scripts/purge-soft-deleted.ts",
"rls:configure": "tsx src/scripts/configure-partner-rls.ts",
"rls:configure:prod": "ENV_FILE=.env.prod tsx src/scripts/configure-partner-rls.ts"
},
"dependencies": {
"react-markdown": "^10.1.0",
"twenty-client-sdk": "2.23.0-alpha.2",
"twenty-sdk": "2.23.0-alpha.2",
"zod": "^4.1.11"
},
"devDependencies": {
"@types/node": "^24.7.2",
"@types/react": "^19.0.0",
"@types/react-dom": "^19",
"dotenv": "^16.0.0",
"oxlint": "^0.16.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tsx": "^4.0.0",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^4.2.1",
"vitest": "^4.0.0"
}
}