01 The Problem & The Bet
Atleo is a cloud-based Product Lifecycle Management (PLM) and compliance SaaS aimed at the food & beverage, flavor & fragrance, and personal/health-care industries. In those markets a finished product's data β formulas, ingredients, supplier and manufacturer records, safety documentation, regulatory dossiers, change-control history β is normally scattered across a handful of disconnected systems and stitched together over email and shared drives. Traceability and accuracy leak out at every hand-off.
Atleo is a single digital workstream: R&D drafts a formula, gets early compliance and regulatory pre-checks before launch, manages supplier authorization, and tracks change control after launch with "where-used" material replacement.
The thing I'm proudest of architecturally is what's underneath Atleo. The product isn't a bespoke PLM app β it's a fully declarative configuration layered on top of a general platform I built called WorkPath (branded internally as the WrkEngine): a schemaless, object-oriented system of record with a workflow engine, a permission model, and a scripting layer. Atleo is "just" a client definition on top of it β swap the object/workflow definitions and the same engine fits a different industry's data model.
02 Two Layers: the Engine and the Client
The codebase splits cleanly into the reusable WorkPath platform and a thin client definition that turns that platform into Atleo. Everything Atleo "is" β its objects, properties, states, forms, menus, roles, and workflows β is authored in code as a versioned deployment (Version1 β Version3), then pushed to a tenant through the API driver. New capability is added by writing a new version builder, not by changing the engine.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ATLEO (client definition β src-clients/DemoPLM) β
β ProductLifeMgmt / Version1 Β· Version2 Β· Version3 β
β ObjectBuilder Β· WorkflowBuilder Β· FormBuilder Β· MenuBuilder β
β AccessBuilder Β· ViewBuilder Β· ObjectQueryBuilder β
βββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β declared over REST via AtleoApiClient
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WORKPATH (WrkEngine platform β src/) β
β β
β DynamicObjects Workflow Permissions Searching β
β (schemaless (phase/step (role/feature (Elastic/NEST)β
β templates) engine) access) β
β β
β Services Β· Messaging (OpenCqrs/ServiceBus) Β· Reporting β
β DataAccess.MongoDb Β· Forms Β· Blazor Β· Www (host) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
MongoDB (records + GridFS docs) Β· Elasticsearch
Stack: C# / .NET Core 3.1 Β· MongoDB + GridFS Β· Elasticsearch via NEST Β· Jint embedded JavaScript Β· OpenCqrs over Azure Service Bus Β· ASP.NET Core MVC/Razor with Blazor in progress Β· Serilog.
03 The Dynamic Object Model
WorkPath's core is the dynamic object template β a runtime-defined, schemaless entity stored in MongoDB. Atleo's entire PLM data model is declared through these templates.
BaseIngredient (abstract parent)
ββ Formula ββ< Ingredients >ββ IngredientList >ββ Ingredient
ββ Ingredient (junction: quantity, UoM) β
ββ Supplier (M:N)
Supplier ββ< Supplier Ingredients (M:N) >ββ Ingredient β
KnowledgeBase (regulatory restrictions: CAS #, limits) ββ
Each object also carries a state machine (Draft β Pending Review β Approved β Obsoleted) and role-based feature permissions (Engineer, Reviewer, Data Steward, System Administrator, Admin) controlling read/write per object and per state.
04 Properties That Do Work
Template properties are richer than plain fields. Beyond strings, doubles, booleans, choice-lists, text, and document attachments, a property can be:
- Auto-increment β e.g. Formula Id as F00000000.##, Chemical Id as I00000000.##.
- Formula (computed) β a Jint script evaluated against the record. Atleo uses these for ingredient roll-ups: a formula's Cost iterates its IngredientList children, multiplying each ingredient cost by quantity; Total Ingredients sums the weights.
- Reference / many-to-many β typed relationships (FormulaβIngredientListβIngredient, SupplierβIngredient) with configurable search/display fields and inline-form vs. modal rendering.
- Query / constraint β a live bound query. The Ingredient.Regulations property runs a regex over the KnowledgeBase by CAS number, so every ingredient automatically surfaces the regulations that touch it.
05 The Workflow Engine
The other half of the platform is a phase-and-step workflow engine. A workflow binds to an object type; it's made of phases, each containing ordered steps, with steps branching to a next phase based on outcomes. Step types include Object State Change, Object Task (a human task assigned to a role, with outcome conditions), Object Formula (an in-process Jint script), plus Approval, Form, Email/Alert, Fulfillment Task, and Status.
DRAFT ββ(submit)βββΊ [Object State: Pending Review]
β
βΌ
[Task: "Review Formula"] (role: Reviewer)
β β β
Rejected Approved Approved With Conditions
β β β (require Reviewer Comments)
βΌ βΌ βΌ
βΊ Draft βΊ Approved βΊ Approved With Conditions
Mapped onto the product, these primitives compose into the full set of PLM workflows: Formula Creation, Formula Sampling (study β samples β results β review), Supplier Authorization (audit β site approval), Compliance KB Check, Dossier Preparation / Registration, Material Where-Used (impact analysis β replacement job), and Ingredient Label Generation.
06 Early Compliance: the Heart of the Pitch
Atleo's selling point is catching regulatory problems during R&D instead of after launch. That's not a feature bolted on β it falls out of the object model plus a workflow formula step. Ingredients are bound to the regulatory KnowledgeBase by CAS number; the Run Regulatory Assessment workflow then iterates a formula's ingredients against each restriction.
Formula βββΊ for each restriction in KnowledgeBase:
for each ingredient (matched by CAS #):
pass = ingredient.quantity < restriction.target_value
βββΊ emit regulatory_assessment_result
{ success, cas, restriction, ingredient_value }
βββΊ SUCCESS / FAILED βββΊ state change
Every check writes an auditable result object, so a clearance assessment leaves a trail rather than a yes/no. When a new regulation passes (the worked example is New York's 1,4-dioxane limit), the same machinery answers which products are impacted and feeds the where-used replacement flow β all inside one system instead of a migrate-and-email scramble across four.
07 Reflections
The bet that paid off was refusing to write Atleo as an application. By pushing every product-specific decision β the Formula/Ingredient/Supplier/KnowledgeBase model, the roll-up math, the approval flows, the role matrix β into declarative builders run through an API, the engine itself stayed industry-agnostic. The Version1 β Version3 progression shows it working: the data model grew from formulas-and-ingredients to suppliers, regulatory knowledge bases, and live compliance assessments without the platform underneath changing shape.
The flip side is the cost of generality β a schemaless dynamic-object engine with an embedded JS layer is a lot of machinery to carry, and the configuration-in-C# approach trades a visual admin UI for developer-authored deployments. For a regulated, multi-industry PLM where every customer's data model is different, that trade has been the right one.