Skip to content

Commit dc02668

Browse files
committed
docs: add system overview, integration spec, data model, and ADR index
New contributor/integrator docs under docs/ (GitHub-rendered inline Mermaid): - system-overview.md: architecture, auth/environment model, request lifecycle. - integration-spec.md: the 4 operations (endpoints, shapes, enums, errors). - data-model.md: typed core shapes + node-param to FedEx-field mapping. - adr/README.md: ADR index. README: link the new docs; replace stale inline version history with CHANGELOG.
1 parent a0ca8d4 commit dc02668

5 files changed

Lines changed: 641 additions & 15 deletions

File tree

README.md

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ The tracking number and rate details are passed through on the main JSON output.
172172

173173
FedEx error messages (`errors[].message`) are surfaced directly through n8n's error handling, and the node honors **Continue On Fail** — failed items emit an `error` entry and the workflow keeps processing the rest.
174174

175+
## Documentation
176+
177+
Deeper docs for contributors and integrators live in [`docs/`](docs/):
178+
179+
- [System Overview](docs/system-overview.md) — architecture, auth/environment model, request lifecycle (with diagrams).
180+
- [Integration Specification](docs/integration-spec.md) — endpoints, request/response shapes, enums, and error handling for all four operations.
181+
- [Data Model](docs/data-model.md) — the typed shapes the node assembles, and the node-parameter → FedEx-field mapping.
182+
- [Architecture Decision Records](docs/adr/) — why the key design choices were made.
183+
175184
## Resources
176185

177186
- [n8n community nodes documentation](https://docs.n8n.io/integrations/#community-nodes)
@@ -180,18 +189,4 @@ FedEx error messages (`errors[].message`) are surfaced directly through n8n's er
180189

181190
## Version history
182191

183-
### 0.1.3
184-
185-
Credentials: the single FedEx OAuth2 credential is split into **FedEx Track OAuth2 API** and **FedEx Shipping OAuth2 API**, each with its own connection test so n8n shows a green credential-test result. Each operation automatically uses the matching credential (Track vs Rate/Ship/Address). **Breaking:** re-create your credentials using the new types.
186-
187-
### 0.1.2
188-
189-
Documentation and packaging only: README badges, Snyk + provenance security notes, and an MIT `LICENSE` file. No functional node changes.
190-
191-
### 0.1.1
192-
193-
Supply-chain hardening, no functional node changes: npm publishing moved to keyless **OIDC trusted publishing** with signed provenance, and CI/release workflows run on the Node 24 GitHub Actions runtime.
194-
195-
### 0.1.0
196-
197-
Initial release. Shipment (Track, Get Rates, Create) and Address (Validate) operations, sandbox/production environment switch, and label-as-binary output.
192+
See [CHANGELOG.md](CHANGELOG.md) for the full, per-release history (kept current automatically on each release).

docs/adr/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Architecture Decision Records
2+
3+
These ADRs capture the non-obvious decisions behind `n8n-nodes-fedex` and why the alternatives were
4+
rejected. Each file is the durable record of one decision; later ADRs can supersede earlier ones.
5+
6+
For the synthesized picture, start with the [System Overview](../system-overview.md).
7+
8+
| ADR | Decision (one line) | Status |
9+
| --- | ------------------- | ------ |
10+
| [0001](0001-single-credential-environment-switch.md) | One `Environment` dropdown drives both the OAuth token URL and the API base URL together, defaulting to sandbox, so a request can never straddle sandbox and production. | Active for the environment switch; the "single credential" part is **partially superseded by 0004**. |
11+
| [0002](0002-declarative-node-postreceive-label-binary.md) | Keep the node declarative and turn FedEx's base64 label into n8n binary data in a `postReceive` hook, rather than going fully programmatic. | Active |
12+
| [0003](0003-pure-assembly-cores-with-unit-test-runner.md) | Do the request/response logic routing can't express in pure, n8n-free cores behind thin `preSend`/`postReceive` adapters, covered by a `vitest` unit runner. | Active |
13+
| [0004](0004-resources-mirror-fedex-projects.md) | Each resource maps 1:1 to a FedEx dev-portal project and binds that project's credential — Tracking (Track) and Shipping (Get Rates, Create, Validate) — because the two projects have disjoint entitlements. | Active; supersedes 0001's single-credential assumption. |
14+
15+
## How they relate
16+
17+
- **0001** and **0004** together define authentication: 0001 set up one environment-switched
18+
credential; 0004 split that into **two** credential types (one per FedEx project) while keeping
19+
0001's environment-switch mechanism intact.
20+
- **0002** and **0003** together define the code shape: 0002 introduced the `postReceive` carve-out
21+
for the label binary; 0003 generalized that into the pure-core pattern used by address/contact
22+
assembly, rate shaping, and label extraction.
23+
24+
## Conventions
25+
26+
- ADRs are immutable records. When a decision changes, add a new ADR and mark the old one superseded
27+
rather than rewriting history. Factual descriptions inside an ADR may be corrected with a dated
28+
note.
29+
- New ADRs are numbered sequentially (`000N-short-slug.md`).

docs/data-model.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Data Model — n8n-nodes-fedex
2+
3+
> Audience: contributors. These are the typed shapes the pure cores assemble from node parameters
4+
> and the shapes they emit. See [Integration Specification](integration-spec.md) for how each shape
5+
> sits inside a request/response, and the [System Overview](system-overview.md) for the architecture.
6+
7+
The node has no database. "Data model" here means the in-memory shapes that flow from n8n node
8+
parameters → pure cores → FedEx request bodies, and from FedEx responses → pure cores → n8n output.
9+
The typed shapes live in
10+
[cores/fedexTypes.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/cores/fedexTypes.ts);
11+
they are deliberately free of any n8n coupling so the cores stay unit-testable
12+
([ADR-0003](adr/0003-pure-assembly-cores-with-unit-test-runner.md)).
13+
14+
## Shapes
15+
16+
```mermaid
17+
classDiagram
18+
class AddressInput {
19+
+string streetLines
20+
+string city
21+
+string stateOrProvinceCode
22+
+string postalCode
23+
+string countryCode
24+
+boolean residential
25+
}
26+
class FedexAddress {
27+
+string[] streetLines
28+
+string city
29+
+string stateOrProvinceCode
30+
+string postalCode
31+
+string countryCode
32+
+boolean residential
33+
}
34+
class ContactInput {
35+
+string personName
36+
+string companyName
37+
+string phoneNumber
38+
+string emailAddress
39+
}
40+
class FedexContact {
41+
+string personName
42+
+string companyName
43+
+string phoneNumber
44+
+string emailAddress
45+
}
46+
class FedexWeight {
47+
+WeightUnit units
48+
+number value
49+
}
50+
class FedexDimensions {
51+
+number length
52+
+number width
53+
+number height
54+
+DimensionUnit units
55+
}
56+
class ShapedRate {
57+
+string serviceType
58+
+string serviceName
59+
+number negotiatedRate
60+
+number listRate
61+
+string currency
62+
}
63+
class ExtractedLabel {
64+
+Buffer buffer
65+
+string fileName
66+
+string mimeType
67+
+string trackingNumber
68+
+JsonObject json
69+
}
70+
71+
AddressInput ..> FedexAddress : toFedexAddress
72+
ContactInput ..> FedexContact : toFedexContact
73+
```
74+
75+
### Inputs versus FedEx shapes
76+
77+
`AddressInput` / `ContactInput` are the loose, flat values read from node parameters;
78+
`FedexAddress` / `FedexContact` are the cleaned shapes FedEx expects. The cores own the rules:
79+
80+
- **`toFedexAddress`** splits Street Lines on newlines (max 3), trims everything, defaults
81+
`countryCode` to `US`, includes `stateOrProvinceCode` only when present, and includes
82+
`residential` only when it was explicitly provided (it is meaningful for a recipient, omitted
83+
elsewhere).
84+
- **`toFedexContact`** always carries a trimmed `phoneNumber` and omits blank identity fields.
85+
86+
### Output shapes
87+
88+
- **`ShapedRate`** is one flattened row per service produced by `shapeRates` from
89+
`output.rateReplyDetails`. `negotiatedRate` is the account (`ACCOUNT`) price; `listRate` is the
90+
published (`LIST`) price; either can be `null`.
91+
- **`ExtractedLabel`** is produced by `extractLabel`: the decoded label `buffer`, a sanitized
92+
`fileName`, the `mimeType` from the chosen format, the `trackingNumber`, and `json` — the FedEx
93+
output with every base64 `encodedLabel` recursively stripped.
94+
95+
## Node parameter → FedEx field mapping
96+
97+
| Node parameter | FedEx field (via core) | Used by |
98+
| -------------- | ---------------------- | ------- |
99+
| `{role}StreetLines` | `address.streetLines[]` (split, max 3) | Validate, Get Rates, Create |
100+
| `{role}City` | `address.city` | Validate, Get Rates, Create |
101+
| `{role}StateOrProvinceCode` | `address.stateOrProvinceCode` (omitted if blank) | Validate, Get Rates, Create |
102+
| `{role}PostalCode` | `address.postalCode` | Validate, Get Rates, Create |
103+
| `{role}CountryCode` | `address.countryCode` (default `US`) | Validate, Get Rates, Create |
104+
| `recipientResidential` | `address.residential` (recipient only) | Get Rates, Create |
105+
| `{role}PersonName` | `contact.personName` | Create |
106+
| `{role}CompanyName` | `contact.companyName` | Create |
107+
| `{role}PhoneNumber` | `contact.phoneNumber` (required) | Create |
108+
| `{role}EmailAddress` | `contact.emailAddress` | Create |
109+
| `shippingAccountNumber` | `accountNumber.value` (required) | Get Rates, Create |
110+
| `packageWeight` / `weightUnit` | `requestedPackageLineItems[0].weight` | Get Rates, Create |
111+
| `packageLength/Width/Height` / `dimensionUnit` | `requestedPackageLineItems[0].dimensions` (sent only when all three greater than 0) | Get Rates, Create |
112+
| `serviceType` | `requestedShipment.serviceType` | Get Rates (optional), Create (required) |
113+
| `labelImageType` | `labelSpecification.imageType` + binary MIME | Create |
114+
| `labelStockType` | `labelSpecification.labelStockType` | Create |
115+
116+
`{role}` is `shipper` or `recipient`; the same builders are reused across Get Rates and Create so
117+
values carry over when switching operation.
118+
119+
## The one-Address, four-positions crux
120+
121+
The single `FedexAddress` shape lands in four structurally different request positions. This is the
122+
core reason address assembly is a pure function rather than per-field declarative routing
123+
([ADR-0003](adr/0003-pure-assembly-cores-with-unit-test-runner.md)):
124+
125+
```mermaid
126+
flowchart LR
127+
core["toFedexAddress(input)"] --> v["Validate<br/>addressesToValidate[0].address"]
128+
core --> rs["Get Rates<br/>requestedShipment.shipper.address"]
129+
core --> rr["Get Rates<br/>requestedShipment.recipient.address"]
130+
core --> cs["Create<br/>requestedShipment.shipper.address"]
131+
core --> cr["Create<br/>requestedShipment.recipients[0].address"]
132+
```
133+
134+
Two of those carry an array index, `recipient` is singular for Get Rates but a plural `recipients`
135+
array for Create, and `residential` is a user **input** for a recipient but the **output** of
136+
Validate. One pure core normalizes all of it.
137+
138+
## Traceability to repo artifacts
139+
140+
| Shape / logic | Source |
141+
| ------------- | ------ |
142+
| Typed FedEx shapes | [cores/fedexTypes.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/cores/fedexTypes.ts) |
143+
| Address assembly | [cores/toFedexAddress.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/cores/toFedexAddress.ts) |
144+
| Contact assembly | [cores/toFedexContact.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/cores/toFedexContact.ts) |
145+
| Rate shaping | [cores/shapeRates.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/cores/shapeRates.ts) |
146+
| Label extraction | [cores/extractLabel.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/cores/extractLabel.ts) |
147+
| Parameter readers | [resources/shared.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/resources/shared.ts) |
148+
| Field builders | [fields.ts](https://github.com/nodrel-dev/n8n-fedex-node/blob/main/nodes/Fedex/fields.ts) |

0 commit comments

Comments
 (0)