Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 350 additions & 0 deletions docs/FORK-UPDATE.md

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions docs/decisions/0001-distribute-piece-as-archive-not-registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# 1. Distribute the OroCommerce piece as an uploaded archive, not via the npm registry

Date: 2026-09-07 (decision taken 2026-08-19, confirmed 2026-09-01 and 2026-09-07)
Status: accepted
Evidence: the tracking ticket comments of 19 Aug, 20 Aug, 1 Sep 2026; an internal run log, 7 Sep 2026

## Context

Activepieces can install a piece two ways: `REGISTRY` (give it an npm package name and version, it
downloads from npm) or `ARCHIVE` (upload the packed `.tgz` in the request). Flows pin the exact piece
version, so every version has to be installed explicitly either way.

On Community Edition (the edition stock images and our customers run), installs go through
`communityPiecesModule`. Its `REGISTRY` path resolves the download URL by looking the package up in
`piece_metadata` — the same table the install is meant to populate. For a package the instance has never
seen this is a closed loop: no row → 404 before npm is contacted; create the row by hand → 409 duplicate.
Tested 1 Sep 2026 on stock CE 0.88.1 with `piece-slack@0.5.0` (on npm, no metadata row) and with a test
package at two versions in both orders. Official catalog pieces are unaffected because the catalog is seeded
into `piece_metadata` at boot; `piece-slack@0.17.9` installed fine from the registry.

Enterprise and Cloud editions use a different module (`pieceSetModule`); their behaviour for unknown
packages is untested. The vendor documents piece management as an enterprise feature and hides the archive
option in the CE UI while leaving it open in the CE API (`POST /v1/pieces`).

Separately, the package name is undecided (upstream PR #13859 is open; renaming a piece orphans every flow
built with the old name), so publishing to npm now would lock in a name we may regret.

## Decision

Ship the piece as a `.tgz` built from a tagged commit on `poc/orocommerce` and install it with
`POST /v1/pieces` as `packageType=ARCHIVE`, `scope=PLATFORM`. Do not publish to npm until the name is
decided and a registry install path is shown to work on the editions we target. Do not file the CE
registry behaviour upstream: the likely outcome is "working as intended", possibly with the same gate
applied to the archive path we depend on.

## Consequences

- The customer runbook must carry the upload step; the Oro bundle's setup command does not install pieces.
- `POST /v1/pieces` exists only on CE. Customers on EE/Cloud cannot take this path and need our image
(which bakes the piece in as a dev piece). Whether EE offers an equivalent install route is open.
- The release identity is the tarball's sha256 plus the commit; AP stores the archive byte-for-byte.
- Every piece version bump means an explicit upload per instance and a re-pin per flow.
- Re-check this decision at every Activepieces version bump: one curl re-testing the archive install on
the new CE version, in case the archive path gains the enterprise gate.
- If upstream ever fixes registry resolution for unknown packages, images already deployed still carry
the old resolver, so the archive path stays the baseline regardless.
41 changes: 41 additions & 0 deletions docs/decisions/0002-exact-version-pinning-and-re-pin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 2. Flows pin the exact piece version; every upgrade is an explicit per-flow re-pin

Date: 2026-09-07 (behaviour established 3 Sep 2026, confirmed 7 Sep 2026)
Status: accepted (this is Activepieces behaviour we live with, not a choice we made)
Evidence: upgrade rehearsal 3 Sep 2026 (internal upgrade-rehearsal results); an internal run log, 7 Sep 2026

## Context

An Activepieces flow stores the piece name *and exact version* in each trigger and action step. Installing
a newer piece version does nothing to existing flows; they keep running the version they were built with.
There is no "latest" and no automatic upgrade, for official pieces or ours.

The Oro bundle's `default_piece_version` setting only affects connections created after it changes; it does
not move existing flows either.

Our trigger registers a webhook in Oro on enable, with a secret Oro accepts only at creation time. So a
re-pin is not a metadata edit: enabling the flow at the new version deletes the old webhook row and creates
a new one with a new secret.

## Decision

Treat every piece version bump as a per-flow operation, done through the API, not the UI:

1. `POST /v1/flows/{id}` with `UPDATE_TRIGGER` — send the whole trigger object, changing only
`settings.pieceVersion`.
2. `POST /v1/flows/{id}` with `LOCK_AND_PUBLISH`.

Then verify in Oro that the flow's URL has exactly one webhook row and `length(secret) = 108`.

The UI "upgrade" path is not used: it resets the connection and topic inputs.

## Consequences

- A release is not done when the tarball is installed; it is done when every flow using the piece has
been re-pinned. Both lanes (image and archive) have this step.
- Two webhook rows for one URL means an old unsigned registration is still live — the check is
load-bearing, not cosmetic.
- The `default_piece_version` in the Oro bundle must be bumped with each release (companion change), or
new connections point at a version that may not be installed.
- A scripted re-pin (list flows using the piece → two calls each → verify) is the natural next tool;
today it is done by hand.
48 changes: 48 additions & 0 deletions docs/decisions/0003-api-key-provisioning-by-direct-db-write.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 3. On Community Edition the platform API key is created by writing the `api_key` row directly

Date: 2026-09-07
Status: accepted as the only available mechanism; a proper provisioning path remains an open decision
(owner and date not set)
Evidence: an internal run log, 7 Sep 2026; `authenticate.ts`, `app.ts` in the fork at `5fbed5df94`;
the Oro bundle's provisioning command

## Context

Everything the Oro bundle does against Activepieces server-side authenticates with a platform API key
(`sk-…`). Activepieces authenticates such a key by hashing it and looking the hash up in `api_key`; the
lookup code is shared by all editions and has no edition guard. But Community Edition registers no
endpoint to *create* an API key — that route set lives in the enterprise module only. A key whose hash is
not in the table is rejected (401), so the key cannot simply be "forged".

The Oro setup command therefore writes the row itself through Doctrine:
`id` (21-char NanoId), `created`/`updated` (timestamptz), `displayName`, `platformId`, `hashedValue` (hex
SHA-256 of the full key), `truncatedValue` (last 4), `lastUsedAt` (NULL). Key format: `sk-` + 61 NanoId
characters (`A-Za-z0-9`), 64 characters total. Oro keeps the key encrypted in system config
(`oro_activepieces_integration.api_key`, AES-256-CBC keyed by `kernel.secret`). Reproduced by hand on a
clean CE 0.88.1 on 7 Sep 2026: the inserted key authenticated; a control key not in the table did not.

The same command also writes `app_connection`, `user`, `project` and `platform.pinnedPieces` directly. The
"read-only" AP database connection used for this blocks DDL only, not DML.

## Decision

Accept the direct `api_key` write as the provisioning mechanism for CE, and document the exact row shape
so it is reviewable. Record the five direct-write surfaces as the specification any future provisioning
path must replace.

## Consequences

- Provisioning is coupled to Activepieces' schema. Any AP version bump must re-check the `api_key`,
`app_connection`, `user`, `project` and `platform` columns before the bundle is pointed at it.
- The key is readable by anyone with Oro DB read plus the app secret, or console access — same as any
Oro-stored credential; nothing extra.
- Two follow-ups on the provisioning command are open and tracked internally with the integration ticket:
making it safe to re-run, and handling the credentials it emits. Owner unassigned.
- On EE, an API-key endpoint exists; whether the bundle should use it there instead of the DB write is
part of the open provisioning decision.
- Three of the five direct writes are avoidable even on CE (findings of 21 Aug 2026): CE exposes
`POST /v1/projects`, `POST /v1/app-connections` (upsert) and `POST /v1/authentication/sign-up` — the last
being the only way to create a user on CE. Only the API key has no endpoint. The catch is bootstrap: a
machine caller would normally authenticate those calls with an API key, which CE cannot mint, so a
provisioning rewrite on CE would have to run as a signed-in user rather than a service principal. That
trade-off is the substance of the open decision.
41 changes: 41 additions & 0 deletions docs/decisions/0004-two-branch-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 4. Two branches: piece code on `poc/orocommerce`, embedding and image on `poc/orocommerce_prefixed-path-install`

Date: 2026-09-07 (policy stated 27 Aug 2026 by the branch owner and 3 Sep 2026 by one maintainer, Slack)
Status: accepted
Evidence: Slack 27 Aug, 3 Sep 2026; `FORK-UPDATE.md` §1; an internal run log, 7 Sep 2026

## Context

The fork carries two kinds of change to upstream Activepieces. The piece
(`packages/pieces/community/orocommerce/`) is self-contained and is also proposed upstream (#13859). The
embedding work — running Activepieces under Oro's URL prefix, the Oro Docker image (`Dockerfile.oro`,
`.env.oro.example`) — touches core files and will never go upstream in this form.

Mixing them on one branch makes the upstream proposal impossible to keep clean, and makes every upstream
sync a fight over unrelated conflicts.

## Decision

- `poc/orocommerce`: piece code only. Every piece PR targets it. Upstream syncs land here first.
- `poc/orocommerce_prefixed-path-install`: branched from the above; embedding and image changes only. It
must always contain everything on `poc/orocommerce`. The Oro cloud image is built from this branch and
no other — `Dockerfile.oro` exists only here.
- The invariant is checked before every release:
`git log origin/poc/orocommerce ^origin/poc/orocommerce_prefixed-path-install --oneline` must be empty.
- Bringing the image branch up to date is done by merging `poc/orocommerce` into it via a pull request to
its owner. No direct pushes, no rebases of either branch.
- Documentation about the fork (`docs/`) lives on `poc/orocommerce` unless the owner asks otherwise.

## Consequences

- The invariant was found broken on 7 Sep 2026: the image branch had not moved since 10 Aug and was 141
commits behind (an upstream sync plus 19 piece commits including webhook signing). An image built that
day would have shipped the unsigned 0.2.0 piece. The merge was prepared
(`merge/orocommerce-into-prefixed-path-5fbed5d`, fork PR #8, closed pending the owner's decision).
- Anything that is neither piece nor embedding — build tooling fixes, CI — has no obvious home. Default:
upstream if it applies there, otherwise the image branch, never `poc/orocommerce`.
- Whoever bumps the piece is responsible for opening the sync PR to the image branch in the same release;
otherwise the two lanes ship different code.
- **This repository is public.** Documentation here — including these records and pull-request text —
carries no ticket keys, internal page ids, person names, internal deployment names, hostnames or
unresolved security findings. Those stay in the internal tracker; the repo uses neutral wording.
38 changes: 38 additions & 0 deletions docs/decisions/0005-version-bump-rule-and-release-identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 5. Bump the piece version only when the current version has been installed outside a rig; a release is commit + two hashes

Date: 2026-09-07
Status: accepted
Evidence: PR #7 (0.3.1 bump) closed 7 Sep 2026; an internal run log, 7 Sep 2026

## Context

Activepieces treats `(name, version)` as the identity of an installed piece and refuses to install the same
pair twice (409) or to delete a version. During testing, two different builds were uploaded to a
developer rig under the same label `0.3.0`, which produced a local collision and a proposal to bump to
`0.3.1`. But `0.3.0` had never been installed anywhere except that laptop, so nothing outside the rig could
be confused by rebuilding it.

Separately, the version string alone does not identify what code is running, since anyone can build a
tarball labelled `0.3.0`.

## Decision

- Bump `version` in the piece's `package.json` only when the version currently at head has been installed
on an instance other than a developer rig (a testbed, a customer, an internal deployment). Rig
collisions are fixed by tearing down the rig.
- A release is identified by three values recorded together on the ticket: the fork commit, the sha256 of
the `.tgz`, and the sha256 of `package/src/index.js` inside it. The build is deterministic (verified 7
Sep 2026: rebuilding `5fbed5df94` reproduced `09194f3f…` byte-for-byte), so the outer hash is a valid
identity, and Activepieces stores the archive unchanged, so the same hash can be checked on the instance.
- Versions are plain `x.y.z`; Activepieces rejects prerelease suffixes at install.
- Tarballs are named `head-<short-sha>-<version>.tgz`. Old or superseded builds are moved out of the
release folder so exactly one file per version exists.

## Consequences

- Current release: 0.3.0 = `5fbed5df94`, `09194f3f087b46f96d88eb670c0d5128098c15491f6d653b0c9d631e541804b8`,
67 144 bytes, `src/index.js` `11ad8876e985a4886be58645474ff5a442eefe4317611ae33feed922faef6cff`.
- If the branch owner prefers a bump-per-merge convention instead, this decision is superseded; the
question was put to them on 7 Sep 2026.
- Every build must be checked for size and hash before use: the build tooling can silently produce a
~1 KB tarball with no code (see `FORK-UPDATE.md` §4).
41 changes: 41 additions & 0 deletions docs/decisions/0006-upstream-sync-via-origin-main-or-tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 6. How the fork tracks upstream Activepieces: `origin/main` or release tags

Date: 2026-09-07
Status: **open** — decision needed from the fork's owner
Evidence: an internal run log, 7 Sep 2026; `git log --merges` on `origin/poc/orocommerce`

## Context

The fork's `main` mirrors upstream. Between 29 Jan and 20 Aug 2026 there were 44 syncs into
`poc/orocommerce`, all by one maintainer, all merging `origin/main` at whatever commit it was on — never an
upstream release tag. The most recent (`cd36237260`, 20 Aug) put the branch at
`0.86.3-rc.2-451-g71dd1758dc`: near 0.88.1 but not equal to it (83 commits present that the tag lacks, 4
missing that it has).

Meanwhile the piece was proven on *stock* CE 0.88.1 images, which are built from the tag. So "the fork is
on 0.88.1" is approximate, and the image built from the fork is not the same code as the stock image the
customer lane was tested against.

`FORK-UPDATE.md` §7 describes a tag-based sync (`git fetch upstream --tags`, merge the tag). That is a
proposal; it has never been done in this fork.

## Options

1. Keep syncing from `origin/main` (current practice). Cheap, frequent, always close to upstream head;
but the fork never corresponds to a version customers run, and bugs fixed between head and the next tag
may be present.
2. Sync from upstream release tags only. The fork's version string means what it says, the image matches
the stock image the customer lane is tested on, and `FORK-UPDATE.md` §7 becomes the procedure; but syncs
are larger and less frequent, and the piece branch may lag upstream fixes.
3. Both: tags on the image branch (what ships), `origin/main` on the piece branch (what goes upstream).
Most precise, most bookkeeping.

## Decision

Not taken. Asked of the fork's owner on 7 Sep 2026.

## Consequences (of leaving it open)

- Two artefacts both called "0.88.1" — our image and the stock image — differ by ~87 commits. Any
discrepancy between cloud-lane and customer-lane behaviour must be checked against this first.
- `FORK-UPDATE.md` §7 stays marked as unverified until an option is chosen and run once.
42 changes: 42 additions & 0 deletions docs/decisions/0007-piece-package-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 7. The piece's package name

Date: 2026-09-07
Status: **open** — decision needed before upstream PR #13859 moves or anything is published to npm
Evidence: the tracking ticket description and comments of 19 Aug 2026; upstream PR
activepieces/activepieces#13859

## Context

The piece is currently `@activepieces/piece-orocommerce`, the name it would have as an official upstream
piece. It is installed under that name on every rig and in the release tarball. In Activepieces the package
name *is* the piece identity: every flow step stores it, and a piece under a different name is a different
piece — flows built with the old name keep pointing at the old one and do not follow.

Three pressures pull in different directions:

- If upstream accepts #13859, the name must be `@activepieces/piece-orocommerce`, and anything already
built under that name carries over.
- If upstream does not accept it, we do not own the `@activepieces` npm scope and cannot publish under
it; publishing would need an Oro scope (e.g. `@oroinc/…`), which is a rename.
- Until something is published, the name only matters *within an instance*, so the archive lane works
under either name today — but the day a rename happens, every existing flow is orphaned and must be
rebuilt or migrated.

## Options

1. Keep `@activepieces/piece-orocommerce`, push #13859 to a conclusion, and rename only if upstream
declines. Cheapest now; the rename risk lands later, after more flows exist.
2. Rename to an Oro scope now, before any non-rig install. Removes the risk while it is free; forfeits the
"official piece" path unless upstream accepts a scoped package (they do not).
3. Decide by a date: if #13859 has no movement by then, rename before the first real deployment.

## Decision

Not taken. Sits on the tracking ticket with the release record; must precede the first install on any instance
that will keep its flows (an internal deployment included).

## Consequences (of leaving it open)

- Every flow built on a rig today is disposable; that is fine for rigs and not fine for anything else.
- Publishing to npm is blocked regardless of the registry-install question (see ADR 1).
- `FORK-UPDATE.md` §2 carries the rename warning so nobody does it casually.
Loading