ADR 0015: Knowledge Pipeline — COS SPOT to Serve via BFFs¶
Status¶
Proposed
Date¶
2026-08-12
Context¶
OVES needs a universal Single Point of Truth (SPOT) for all knowledge — products, articles, training materials, bot responses, media, and more. Knowledge must be general, unstructured, ad-hoc, and headless. It does not serve frontends directly.
The pipeline pattern is consistent regardless of knowledge type:
Source (COS SPOT) ──tag event──► Curation (SCF) ──► Produce (BFF mutation) ──► Serve (CDN)
Source: COS stores raw knowledge — markdown, PDFs, images, data files. COS native object tags provide metadata and routing. No folders, no custom schemas.
Curation: SCF (Serverless Cloud Function) triggered by COS events. Reads tags to determine which BFF to call. Reads content to build the mutation payload. Transforms unstructured knowledge into BFF-compatible structured input.
Produce: BFF mutation APIs create or update structured objects in the target system. BFFs are the sole write path — never touch Odoo or other backends directly.
Serve: The target system serves frontends via CDN, API, or social media — unchanged from current state.
Why This Pattern¶
| Benefit | How |
|---|---|
| COS owns data | Universal, headless, no lock-in to any backend |
| No schema duplication | BFF schema is consumer concern, not SPOT concern |
| Multi-dimensional relevance | Tags: type=product, bff=product, parent=pet-3, region=cn |
| Single propagation mechanism | One SCF handles all knowledge types via tag-driven routing |
| Extensible | New knowledge types add tags + BFF mutations, no new pipelines |
Rejected Alternatives¶
| Approach | Why rejected |
|---|---|
| Odoo as SPOT + COS as cache | Defeats the goal — COS should own the data |
| Bidirectional sync | Odoo demoted to read-only projection; no conflicts |
| YAML card files | Redundant — COS native tags provide the same capability |
| SMH (Smart Media Hosting) | Media-hosting oriented; revisit when comparing to Cloudinary |
| Folder-based categorization | Forces rigid hierarchy; tags provide multi-dimensional relevance |
COS Layout¶
Flat namespace under knowledge/ prefix. No folders. Files related by name prefix.
knowledge/
pet-3.md # product knowledge body
pet-3-spec-sheet.pdf # product asset
pet-3-hero.jpg # product asset
battery-48v.md # product knowledge body
battery-48v-datasheet.pdf # product asset
oves-e-mobility.md # article knowledge body
case-whitepaper.md # article knowledge body
onboarding-guide.md # training knowledge body
product-expert-bot.md # bot knowledge body
COS Object Tags (max 10 per object)¶
Routing Tags (drive the propagation)¶
| Tag Key | Values | Purpose |
|---|---|---|
type |
product, article, training, bot, media |
Knowledge category |
bff |
product, article, lexiang, edgeone, cloudinary |
Which BFF to call |
updated |
ISO date 2026-08-12 |
Change tracking for propagation trigger |
parent |
pet-3 |
Links asset to parent knowledge object |
asset-type |
datasheet, image, manual |
What kind of asset |
Metadata Tags (consumed by BFF mutations)¶
| Tag Key | Maps to |
|---|---|
name |
BFF name field |
slug |
BFF slug field |
product-class |
BFF productClass field |
is-sellable |
BFF isSellable field |
author |
BFF author field |
Tag Limit Mitigation (max 10)¶
- Tags hold routing + identity metadata only
- Rich content goes in the object body (markdown, JSON, PDF)
- Complex metadata goes in a
metadata.jsonsibling file withparenttag
Propagation — SCF Implementation¶
COS PutObject event on knowledge/ prefix
│
▼ Read object tags
├── bff=product → product-bff mutation
├── bff=article → article-bff mutation
├── bff=lexiang → Lexiang MCP tool
├── bff=edgeone → EdgeOne CDN push
└── bff=cloudinary → Cloudinary API
│
▼ Read object content
├── Markdown → extract structured fields → BFF mutation payload
├── PDF → CI extract text → BFF mutation payload
└── Image → CI OCR / thumbnail → CDN URL → BFF mutation payload
│
▼ Call BFF mutation
└── Odoo updated (or other backend)
Knowledge Type Instances¶
Products (first instance)¶
SPOT: knowledge/{product-name}.md + tagged assets
BFF: product-bff (createProduct, updateProduct mutations)
Odoo: ov.product_profile + related models (read-only projection)
Serve: decks.omnivoltaic.cn, websites via BFF query
Tags: type=product, bff=product, product-class=VEHICLE, is-sellable=true, name=PET-3
Articles (second instance)¶
SPOT: knowledge/{article-slug}.md
BFF: article-bff (createArticle, updateArticle mutations)
Odoo: blog.post collections (read-only projection)
Serve: Websites via BFF query, Lexiang AI Q&A
Tags: type=article, bff=article, author=Admin, tags=e-mobility,electric-vehicles
Future Instances¶
| Knowledge Type | BFF | Target System |
|---|---|---|
| Training materials | EdgeOne CDN | training.omnivoltaic.cn |
| Bot responses | Lexiang MCP | AI 问答 via Lexiang knowledge set |
| Media assets | Cloudinary API | Social media, marketing channels |
| Memos | EdgeOne CDN | memo.omnivoltaic.cn |
| Presentations | EdgeOne CDN | decks.omnivoltaic.cn |
Odoo Demotion¶
Odoo Product and Article custom models become read-only projections. SCF is the exclusive writer. No human Odoo UI editing for these models. Odoo remains the persistence layer behind BFFs — we don't know or care how BFFs persist internally.
Implementation Phases¶
| Phase | Deliverable |
|---|---|
| 1 | COS knowledge/ prefix, tag conventions, SCF skeleton |
| 2 | Product instance: SCF → product-bff mutation pipeline |
| 3 | Article instance: SCF → article-bff mutation pipeline |
| 4 | Migrate existing Odoo Products/Articles → COS knowledge/ |
| 5 | Training + Media instances |
Consequences¶
Benefits¶
- COS owns all knowledge — universal, headless, multi-dimensional via tags
- One propagation pipeline serves all knowledge types
- BFFs remain the interface — frontends don't change
- Odoo demoted but functional — no breaking changes to serving layer
- Tag-driven routing eliminates schema duplication
- SMH evaluation deferred — revisit for Cloudinary comparison
Trade-Offs¶
- COS tag search requires list + filter (no native query index)
- 10-tag limit per object — sufficient for routing, not for rich metadata
- BFF mutations must exist (may need to be built in dirac-fed)
- Two-step propagation adds latency (COS event → SCF → BFF)