-
Notifications
You must be signed in to change notification settings - Fork 0
Business Shapes
Forge leads with job shops, and that is the honest primary audience. It is not the only shape the same binary carries. The capability catalog holds a full professional-services area and a full retail/marketplace commerce layer, each with its own entities, endpoints and screens, each selected by preset at setup rather than by running a different build.
This page covers the two shapes beyond the job shop: what they model, why they model it that way, and what is thin. The canonical list of what exists is the catalog itself — docs/functional-reference/capabilities.md, and behind it forge.api/Capabilities/CapabilityCatalog.cs in forge-api. Neither shape has a reference doc of its own yet; this page is the documentation.
Both shapes arrive the same way: a preset flips a capability set and then applies the bundles it carries — terminology, roles, kanban track types and their stages, reference data, report visibility, workflow definitions, a cloud-storage folder map. Nothing is forked, patched or compiled differently. The mechanism is the one described on Capability Gating; this page is about what the two non-manufacturing presets do with it.
The discovery wizard forks on this at the very first question — products, services, or both. Services short-circuits to the Pro Services preset, both to Hybrid, products falls through to the manufacturing questions. A later question re-checks the answer against what the business actually does, so ticking services alongside a product line routes to Hybrid regardless of the opening answer.
The PS area covers engagement modelling, a billable/non-billable time split, per-resource and per-role bill rates, engagement costing across time-and-materials, fixed-bid and retainer models, retainer burn-down, and utilization reporting. Applying the Pro Services preset turns those on and removes the manufacturing spine — parts, BOM, routing, work centers, receiving, pick/pack/ship, work-order release, material issue, shop floor, inventory. A services firm is never asked about a bill of materials.
The single most important modelling fact: an engagement is a Job on a services track type, not a new record type. The catalog says it in the capability text and the code says it in the entity — the engagement axis fields (engagement type, project phase, billing model, retainer hours, retainer balance, the linked statement of work) are columns on Job, and the billable flag, bill rate and activity type are columns on TimeEntry. Both sets are write-anytime at the database level and gated at the UI and API surface by CAP-PS-ENGAGEMENT and CAP-PS-TIME-BILLABLE.
That choice is why the rest of the system keeps working. An engagement gets the kanban board, time tracking, activity log, file attachments, subtasks, scheduling, custom fields and reporting that Jobs already have, and every query that joins to a Job still joins. A separate Engagement entity would have meant a parallel implementation of all of it.
The terminology bundle renames the vocabulary rather than translating it: Job becomes Engagement, Work Center becomes Consultant, Planning Cycle becomes Sprint, the jobs list reads Tasks and the customers list reads Clients (the entity itself stays Customer — dominant usage in the industry). Terminology is one of three separate wording mechanisms; see Customizing an Install for how it differs from label overrides and translation.
Roles are seeded add-only — Practitioner, Engagement Manager, Account Manager, Delivery Lead — so re-applying a preset never strips a permission someone already granted. Reference data seeds the services groups: engagement types, project phases, billable status, activity types, deliverable types, service units of measure, engagement status, retainer status, client segments.
The track bundle seeds an agile-flavoured set of task types — Epic, Story, Bug, Spike, and a default Project track that is the one carrying the money. Its stages run Proposal → Won → Discovery → Active Delivery → In Review → Delivered → Invoiced → Paid, with Won pinned to a sales order, Invoiced to an invoice and Paid to a payment, and the last two marked irreversible so a card cannot be dragged back out of a booked document. The other four tracks are internal-work lifecycles with no accounting hooks.
A deliverable is the artifact a client actually receives — a report, code, a design, documentation, training. It hangs off the engagement (that is, off the Job), carries a due date, a status from draft through delivered, and points either at stored file attachments or at a linked folder on a connected cloud provider. It deliberately does not go through the part/inventory/shipment chain: a consulting deliverable is not a stock item, and forcing it through that machinery would demand a part number for a PDF. It is gated by CAP-O2C-DELIVERABLE and has its own endpoints under api/v1/deliverables.
Percentage-based milestones on a payment schedule are how fixed-bid and deposit-driven services work get billed. The schedule is defined on the quote and re-linked rather than cloned to the sales order at conversion, so both views read one source of truth. Percentages are authoritative and amounts derive from the live document total — except that a milestone freezes its derived amount the first time it is invoiced or paid. A later edit to the quote or order cannot retroactively change a deposit you already collected. This is a general order-to-cash mechanism rather than a PS-only one — it rides on the quoting capability — but it is what makes fixed-bid engagements bill correctly.
A shop that both makes things and sells services applies the Hybrid preset, which keeps the manufacturing baseline and layers the PS capabilities on top. It carries the same terminology, reference data, track types, roles and folder map as the services preset, and the track bundle upserts by code, so the manufacturing tracks an install already has are left untouched while the services tracks are added alongside.
Be clear-eyed about the state. The engagement fields, deliverables, payment milestones, the preset and its bundles are live. Rate cards, retainer billing and the utilization dashboard exist as catalog capabilities without dedicated endpoints of their own yet — the columns they need are on Job and TimeEntry, and the reporting surfaces that consume them are not all built. Turn them on to declare intent; check the Feature Reference and the catalog before assuming a screen is behind one.
The commerce layer answers a different question: how do you sell to consumers, and to marketplaces that sell to consumers on your behalf, without wrecking a data model built for account business?
Every sales order belongs to exactly one sales channel, and the channel's type is what the order pipeline branches on — whether the credit gate runs, whether a quote is expected upstream, who is liable for sales tax, and what settlement looks like. There are three types: Direct B2B (classic account business, where the customer on the order is the buyer), Direct Retail (consumer sales where you are the merchant of record — your own storefront, point of sale, trade shows, phone orders), and Marketplace (a third-party platform that collects and remits the tax and pays you net of fees on its own cycle).
Enabling channels alone changes nothing operationally. Every install gets a single DIRECT channel of type Direct B2B and behaves exactly as it did before; that is why CAP-O2C-CHANNELS is on by default. Exactly one channel may be the default, enforced by a filtered unique index, and an order with no channel resolves to it. Every order-creating path goes through a single resolver rather than reading the channel off the order, so the "null means default" fallback lives in one place instead of being forgotten in one handler out of a dozen.
Because retail splits the counterparty. The pre-channel model had one party per order: the customer both owed the money and received the goods. On a marketplace the platform owes you the money while a consumer receives the goods, and no boolean on a customer record expresses that.
The channel names the arrangement and holds the house account that carries the receivable — "Web Direct", or the marketplace's own account. It is required on retail and marketplace channels and null on Direct B2B, where the order's own customer is the sold-to. The result is that AR, statements, aging and accounting sync keep working untouched, because every order still points at a real customer. A retail channel with no house account configured fails loudly at order creation rather than quietly booking a consumer's order against whichever customer happened to be handy.
A consumer who buys through a retail or marketplace channel is recorded as a retail buyer, a thin record holding the channel's own buyer identifier, a display name, contact details, marketing consent and order counts. It is deliberately not a Customer, for three reasons:
A customer is a B2B account. Credit limits and holds, tax-exemption certificates, price lists, portal logins, regulatory flags, credit-review cadence — none of it applies to somebody who bought one item.
Volume would bury the real accounts. Minting a customer per consumer puts thousands of one-shot rows into every picker, every segment and every "sales by customer" report, alongside the few hundred accounts that matter.
Deletion has to be scoped. Marketplace data-protection terms require buyer personal data to be deletable on request and retained no longer than needed to fulfil. Because buyers live in their own table, that is a purge job that clears the name, email and phone past a retention date while leaving the row, the order history and the analytics intact — with a purge timestamp recorded so the job is idempotent and auditable. There is also an on-demand purge endpoint for a specific buyer. Scrubbing consumers out of the customer master instead would mean deleting rows that other records point at.
Matching is on the channel's buyer identifier, never on email: on most marketplaces the contact address is a rotating anonymised relay, useful for routing and worthless as an identity key. Manual walk-in entry mints a synthetic identifier per order rather than collapsing every walk-in onto one blank key.
Ship-to addresses follow the same logic. A retail order carries a frozen per-order ship-to rather than a foreign key into the customer address book — because the address belongs to the consumer, not the house account, and because a buyer can ship somewhere different on every order and must not have a past shipment retroactively rewritten when they later edit their profile.
Manual entry and channel importers both go through one command. That is deliberate: it is what stops an importer from assembling orders directly in the integrations layer and bypassing validation, activity logging and capability gating. A retail order enters Confirmed rather than Draft — payment was captured at checkout, so there is no quote to accept, no credit to approve, and credit terms and customer PO stay empty by construction, with the marketplace order number standing in as the buyer's reference. Replaying the same external order number on the same channel returns the existing order rather than minting a duplicate, so an importer can safely retry a failed batch.
A channel listing maps one saleable listing on a channel — its listing id and seller SKU — to the part it fulfils from. It is a table rather than a JSON blob because inventory sync has to answer the reverse question ("which listings publish this part, and what quantity did we last push?") and triage has to answer "which listings have no part yet?" Neither is a lookup; both are queries.
An unmapped listing does not drop the order. Orders still import, and their lines land with no part and a free-text description, so nothing is silently lost. Unmapped listings are the triage queue: an explicit list of things to map, rather than a gap you discover at month-end.
Account business settles per document — invoice out, payment in, applied one to one. Marketplaces do not. They pay on their own cycle, in one lump, net of referral fees, fulfilment fees, postage, refunds and account charges, and those components arrive on a different cadence than the orders that caused them. Without a settlement record the deposit matches no invoice in the system and the tie-out is manual forever.
A channel settlement is one payout batch: the period, the reported net amount, the currency, the deposit date, the raw payload kept so a dispute can be re-derived from source, and the component lines. Forge computes the net from those lines and exposes the variance against what the channel says it paid, with a status that distinguishes a batch that ties out from one whose accepted variance carries a written reason. The external settlement id is unique per channel, which makes re-import idempotent.
Settlement is an operational reconciliation record in every accounting mode. What changes by mode is where the resulting journal lands — see Accounting Modes.
The catalog names both storefronts and marketplaces under the e-commerce capability. Only the storefront connectors are registered: Shopify and WooCommerce are real HTTP connectors; the marketplace connectors are not built, because each needs a developer account and an OAuth app registered with that marketplace first. Asking the factory for an unregistered platform raises a clear error naming what is registered, rather than a stub that pretends to poll and returns nothing.
None of that blocks the model. A channel can exist with no integration at all — orders keyed in by hand or loaded from a file — which is exactly what point of sale, trade shows, phone orders and an unconnected marketplace need. And in the mock integration posture a connector is registered per platform, so an evaluation exercises the real multi-channel shape on fabricated data. Check your install's readiness report before believing any of it is live — see Configuration and Integrations.
| Capability | What it gives you |
|---|---|
CAP-O2C-CHANNELS |
Sales channels. On by default; the spine the rest depends on |
CAP-O2C-RETAIL |
Retail buyers, frozen ship-to, the consumer order path |
CAP-O2C-SETTLEMENT |
Marketplace payout reconciliation. Requires retail |
CAP-EXT-ECOMMERCE |
Storefront and marketplace connectors, listing mapping, inventory push. Requires retail |
CAP-O2C-DELIVERABLE |
Client deliverable tracking |
CAP-PS-ENGAGEMENT |
Engagement axis fields on Job and the services track surfaces |
CAP-PS-TIME-BILLABLE |
Billable/non-billable split and activity types. Independent of engagements |
CAP-PS-RATE-CARDS, CAP-PS-PROJECT-COST, CAP-PS-RETAINER, CAP-PS-UTILIZATION
|
Bill rates, engagement costing, retainer burn-down, utilization reporting |
Everything above except channels is off by default. A shop that only sells B2B never sees a retail surface; a manufacturer never sees an engagement field. The dependency resolver refuses combinations that would leave an install incoherent, and a disabled capability yields a clean 403 with a header naming the capability rather than a broken screen — Capability Gating has the mechanics, API Access has the error contract.
The straightforward route is not to hand-pick codes at all: run the discovery wizard, take the preset it recommends, and adjust afterwards. Presets are re-appliable and each bundle has its own conflict policy, so a later re-apply does not stamp over terminology an admin hand-edited or strip a role someone granted.
Capability Gating for the substrate and the presets · Accounting Modes for where settlement journals land · Configuration and Integrations for which connectors your box is actually running · Customizing an Install for terminology versus labels versus translation · Feature Reference for the per-screen index · Access and Roles for who may do what once a shape is enabled.
Forge · Apache 2.0 · built by Armory Works — this wiki maps the docs; the authoritative detail lives in docs/.
Evaluating
Running it
- Installation
- First Week
- Configuration and Integrations
- Hardening a Production Install
- Backup and Restore
- Upgrades and Rollback
- Accounting Modes
Using it
- App Surfaces
- Shop Floor Kiosk
- Mobile and Offline
- Access and Roles
- Customizing an Install
- Feature Reference
- UI Flows
Building on it
- API Access
- Architecture
- Capability Gating
- Workflow, Gates and Approvals
- Data Ownership and Export
- Glossary
Contributing
Repo wikis