## Summary
- add packages/twenty-apps/rollup-engine: a parameterised rollup engine
that ships a default Opportunity → Company
aggregation.
- declare runtime config in package.json (TWENTY_API_KEY, optional
TWENTY_API_BASE_URL, and ROLLUP_ENGINE_CONFIG) so
app configuration lives entirely in Settings → Apps → [App] →
Configuration.
- document the workflow in README.md: deploy via twenty app sync,
populate env vars in the UI, use the Test panel with
a ready JSON payload, and reference troubleshooting tips.
- adjust the function entry point to a named async export and add
fallback logic for blank base URLs, matching the
UI’s env behaviour.
- prune legacy templates and examples so
config/templates/opportunity-to-company.json is the single copy/paste
starting point.
## UI / UX impact
After syncing the app:
- the Configuration screen shows the three env keys with helpful
descriptions (API key, optional base URL, JSON
override),
- the built-in Test your function panel works immediately
- and the default JSON config is available from
config/templates/opportunity-to-company.json for users who need to
customise rollups.
## Testing
- Out-of-the-box deploy to the hosted workspace (Opportunity update) ✓
- “Test your function” with the default config ✓
- Override example: point debugOpportunityCount at a scratch field via
ROLLUP_ENGINE_CONFIG ✓
- Optional: local smoke test (yarn install && yarn smoke) still passes
108 lines
5.1 KiB
Markdown
108 lines
5.1 KiB
Markdown
# Rollup engine
|
||
|
||
General-purpose rollup engine for Twenty workspaces. The bundle ships a
|
||
serverless function that materialises aggregations from a child object onto a
|
||
parent object. The default configuration targets Opportunity → Company rollups.
|
||
|
||
## Requirements
|
||
- `twenty-cli` `npm install -g twenty-cli`
|
||
- an API key with access to your workspace. Generate one at
|
||
`https://twenty.com/settings/api-webhooks`.
|
||
- Node 20+ (only required if you plan to run the optional smoke test locally).
|
||
|
||
## Metadata prerequisites
|
||
- Opportunity is a standard object, no extra provisioning required.
|
||
- Add these fields to the `company` object (API names shown):
|
||
- `totalPipelineAmount` (Currency)
|
||
- `totalOpportunityCount` (Number)
|
||
- `wonPipelineAmount` (Currency)
|
||
- `wonOpportunityCount` (Number)
|
||
- `openPipelineAmount` (Currency)
|
||
- `openOpportunityCount` (Number)
|
||
- `lastOpportunityCloseDate` (Date)
|
||
- To script the setup, export `TWENTY_API_KEY` (and `TWENTY_METADATA_BASE_URL` if you are not targeting `http://localhost:3000/rest/metadata`) and run `yarn setup:metadata`. The helper script calls the Metadata API to ensure each field exists on the Company object, skipping anything already provisioned.
|
||
|
||
Create the fields before syncing so PATCH requests succeed.
|
||
|
||
## Quick start
|
||
|
||
1. **Deploy the app**
|
||
```bash
|
||
twenty auth login
|
||
cd rollup-engine
|
||
twenty app sync
|
||
```
|
||
|
||
2. **Configure environment variables**
|
||
- Open **Settings → Apps → Rollup engine → Configuration**.
|
||
- Provide values for the manifest-defined keys:
|
||
- `TWENTY_API_KEY` (required secret; create it in Twenty → Settings → API & Webhooks).
|
||
- `TWENTY_API_BASE_URL` (optional; leave blank to use `https://app.twenty.com/rest`).
|
||
- `ROLLUP_ENGINE_CONFIG` (optional JSON override; leave blank to use the baked-in config).
|
||
- Save the configuration. Changes are applied immediately—no redeploy required.
|
||
|
||
3. **Verify via the Test panel**
|
||
- Still on the app page, select **Test**.
|
||
- Paste a JSON payload with the company ID you want to validate:
|
||
|
||
```json
|
||
{
|
||
"trigger": { "type": "databaseEvent", "eventName": "opportunity.updated" },
|
||
"record": { "companyId": "YOUR_COMPANY_ID" },
|
||
"opportunity": { "companyId": "YOUR_COMPANY_ID" }
|
||
}
|
||
```
|
||
|
||
- Click **Run**. You should see a success summary and the company’s rollup fields updating.
|
||
|
||
4. **Trigger live rollups**
|
||
- Any Opportunity create/update/delete (or the nightly cron) now feeds into the Company metrics.
|
||
|
||
## Runtime configuration
|
||
- `serverlessFunctions/calculaterollups/src/rollupConfig.ts` holds the baked-in defaults.
|
||
Override them by setting `ROLLUP_ENGINE_CONFIG` (aliases: `ROLLUPS_CONFIG`,
|
||
`CALCULATE_ROLLUPS_CONFIG`) to a JSON array in the Configuration UI.
|
||
- `config/templates/opportunity-to-company.json` matches the default rollups shipped with the bundle.
|
||
Copy it, tweak the object/field names you need, and paste the edited JSON into `ROLLUP_ENGINE_CONFIG`.
|
||
- `filters[].dynamicValue` currently supports `"startOfYear"` (UTC midnight on the first day of the
|
||
current calendar year).
|
||
|
||
### Default Opportunity → Company rollups
|
||
| Parent field | Suggested type | Description |
|
||
| --- | --- | --- |
|
||
| `totalPipelineAmount` | Currency (`amountMicros`, `currencyCode`) | Sum of positive-valued Opportunities linked to the Company. |
|
||
| `totalOpportunityCount` | Number | Count of Opportunities linked to the Company. |
|
||
| `wonPipelineAmount` | Currency (`amountMicros`, `currencyCode`) | Sum of Opportunities where `stage === "CUSTOMER"`. |
|
||
| `wonOpportunityCount` | Number | Count of Opportunities where `stage === "CUSTOMER"`. |
|
||
| `openPipelineAmount` | Currency (`amountMicros`, `currencyCode`) | Sum of Opportunities where `stage !== "CUSTOMER"`. |
|
||
| `openOpportunityCount` | Number | Count of Opportunities where `stage !== "CUSTOMER"`. |
|
||
| `lastOpportunityCloseDate` | Date | Most recent `closeDate` (ISO date). |
|
||
|
||
Assumptions:
|
||
- Opportunities expose `companyId`, `amount.amountMicros`, `amount.currencyCode`,
|
||
`stage`, and `closeDate`. Adjust filters or fields as needed via the JSON
|
||
config.
|
||
- Amount totals are stored in micros (integers) to align with Twenty’s composite
|
||
currency fields.
|
||
|
||
## Optional local smoke test
|
||
Run this if you want to exercise the aggregation logic without calling the live API.
|
||
|
||
```bash
|
||
cd rollup-engine
|
||
yarn install
|
||
yarn smoke
|
||
```
|
||
|
||
The smoke script replaces `fetch` with an in-memory mock, executes the rollup function using sample
|
||
Opportunity data, and asserts the PATCH payload that would be sent to Twenty.
|
||
|
||
## Troubleshooting
|
||
- **`Test your function` reports `mainFile.main is not a function`:** delete the app
|
||
(`twenty app delete`) and sync it again (`twenty app sync`) to clear any stale bundle.
|
||
- **`status: "error", message: "Unable to parse rollup configuration override"`:** confirm that
|
||
`ROLLUP_ENGINE_CONFIG` contains valid JSON or leave it blank to fall back to the baked-in defaults.
|
||
- **No company updates after configuring everything:** double-check the Company field API names,
|
||
confirm the Opportunity records have `amount.amountMicros > 0`, and use the Test panel to inspect
|
||
the summary details/logs.
|