Fenavia is a multi-tenant B2B platform that runs an aviation parts trader's entire commercial cycle — inbound RFQ, supplier sourcing, quote, sales order, invoice and airworthiness paperwork — with an AI email pipeline doing the reading and a confidence gate keeping a human on every decision that reaches a customer.
Client context
The first tenant is an aviation parts trading company that buys, repairs and resells rotable and consumable aircraft components. Its customers are airlines, MRO shops and other brokers; its suppliers are the same population, reached mostly through the ILS and PartsBase marketplaces. The company name is withheld here; the platform is described by its product name.
The platform began as a single-tenant internal system for that company and was re-architected into a multi-tenant SaaS product, with the original operator becoming tenant number one. That migration is the spine of the whole engagement: every module had to keep working for a live business while the data model grew a tenant boundary underneath it.
The operational challenge
Parts trading is a speed business with a compliance tail. Four things made it hard to run on spreadsheets and a shared mailbox:
- Demand arrives as unstructured text. A request for quote is an email — sometimes a marketplace notification, sometimes three lines of free text, sometimes a scanned PDF. Whoever answers first with a credible price usually wins the order. Reading and re-typing that traffic by hand is both the bottleneck and the error source.
- Sourcing is a many-to-many broadcast. Answering one customer request means asking twenty suppliers, then reconciling replies that arrive in every conceivable format, days apart, against the request that triggered them.
- Supplier identity is disposable. Every marketplace search surfaces suppliers who are then forgotten, so the same discovery work is repeated forever instead of compounding into an asset.
- The paperwork is regulated. A shipped part needs traceability and an ATA 106 form. Documents assembled by hand at the end of the process are where deals stall.
Product strategy and approach
Three decisions shaped the product more than any framework choice.
Email is the integration surface, not a feature. Counterparties will not adopt a portal. So the platform subscribes to the tenant's own Microsoft 365 mailbox and treats every message as a candidate business event — an inbound RFQ, a supplier quote, or noise — rather than expecting anyone to change how they work.
Automate the reading, not the deciding. The language model classifies and extracts; it never independently commits to a customer. A per-tenant confidence gate decides whether an RFQ earns an automatic draft quote or an acknowledgement plus a human queue entry. Every automated reply is bounded by rules the tenant sets: minimum confidence, inventory-match and price-source requirements, quiet hours, an hourly reply ceiling and a kill switch.
Assume the model will be wrong and build for that. Every parse is logged with its model, prompt version, latency and verbatim output, and is reviewable and correctable in the UI. That is what makes the AI part of the product operable rather than a demo.
The core solution
The platform ships as one application with distinct operating surfaces:
| Surface | What it covers |
|---|---|
| Commercial pipeline | RFQs, quotes, sales orders, invoices, credit memos |
| Supply side | Purchase orders, repair orders, receiving, supplier sourcing campaigns |
| Inventory | Part-number master, stock with a dual physical/business status model, traceability history |
| Finance | Receivables, payables, payments, multi-currency with FX caching, profitability reporting |
| Compliance | ATA 106 generation with signature capture, full-trace paperwork, complete document packages |
| Administration | 47 granular permissions across 6 role templates, per-tenant branding, mailbox onboarding, AI behaviour settings, email templates |
| Platform operations | Tenant management, parse-log review, service health, cross-tenant AI defaults |
A companion Chrome extension bridges the two marketplaces that have no usable public API for this workflow, syncing inventory and capturing supplier data from search results under the operator's own logged-in session.
Primary workflows
Inbound RFQ → quote. A message arrives in the tenant mailbox. A Microsoft Graph webhook acknowledges it in milliseconds and enqueues a durable parse job — a delta-query poller backstops any notification the webhook misses. A worker classifies the message, extracts part number, condition, quantity and delivery terms, and escalates image-only or scanned attachments to a vision model. Sender rules suppress known non-business traffic before any model call. The RFQ is matched against inventory and part history; if it clears the tenant's gate it becomes a draft quote and a threaded reply with a branded PDF, otherwise the customer gets an acknowledgement and the request lands in a human queue with the reason it was held.
Sourcing campaign → best offer. When nothing is in stock, the RFQ is raised into a market-search campaign. The platform ranks candidate suppliers from its own accumulated graph — response rate, recency and win rate — and dispatches by email where a verified address is known, falling back to the marketplace lane for net-new discovery. Supplier replies come back into the same mailbox and are matched to the originating request through a layered matcher: marketplace reference, then sender address, then part-number overlap, then fuzzy name. Every response records its match confidence, the reason it matched and a link to the source email, and a misfiled reply can be reassigned. The result is a best offer per condition code, convertible to a customer quote in one action.
My role
Sole product engineer: discovery with the operator, product and data-model design, all implementation, test strategy, deployment and production operations. The work included the multi-tenant migration of a live system, the AI ingestion pipeline end to end, the browser extension, and the observability needed to run all of it.
Technical approach
Next.js App Router with a strict server/client split, PostgreSQL and Prisma. Tenant isolation is enforced in the data layer: a scoped Prisma client injects tenantId on every query, with a second owner-scope layer for per-user record visibility, so isolation cannot be forgotten at the route level. Email ingestion is queue-backed so a slow model call can never stall a webhook acknowledgement. Documents are generated server-side and stored behind an abstracted storage layer. Deployment is Docker on Coolify with wildcard subdomain routing per tenant. Scale of the codebase: 86 Prisma models, 97 migrations, 215 API routes, 92 portal screens, 165 test files.
Outcomes and evidence
Claims here are limited to what the codebase supports:
- One pipeline, no re-typing. Marketplace and email demand, supplier replies and manual entry all converge on the same records, with the source of every row visible.
- Automation with a documented brake. Automated customer replies are gated, rate-limited, quiet-hour aware and individually attributable to a model and prompt version.
- Supplier discovery compounds. Marketplace searches permanently enrich the supplier graph — in the change that introduced plain-text email extraction, contact capture on a live results page went from 0 to 13 of 24 suppliers.
Model accuracy is deliberately not claimed as a percentage: the human-labelled ground truth is too sparse to support one, and building that evaluation set is the current priority — which is itself the honest state of most production LLM systems.
Confidentiality
The operator is anonymized. Screenshots are taken against a development environment with company names replaced; no customer, supplier or pricing data is published.
Need a similar product or workflow? If you run a business where the real interface is a mailbox — quotes, RFQs, orders, claims — the same pattern applies: durable ingestion, extraction with a confidence gate, an audit trail, and a human on the decisions that matter.







