<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: JiangGuangFeng</title>
    <description>The latest articles on Forem by JiangGuangFeng (@foggy-projects).</description>
    <link>https://forem.com/foggy-projects</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3850542%2F99483161-14d7-4ca1-bad7-1efd5d8d179d.png</url>
      <title>Forem: JiangGuangFeng</title>
      <link>https://forem.com/foggy-projects</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/foggy-projects"/>
    <language>en</language>
    <item>
      <title>Why AI Should Not Write SQL Against ERP Databases</title>
      <dc:creator>JiangGuangFeng</dc:creator>
      <pubDate>Fri, 22 May 2026 13:16:03 +0000</pubDate>
      <link>https://forem.com/foggy-projects/why-ai-should-not-write-sql-against-erp-databases-1ef8</link>
      <guid>https://forem.com/foggy-projects/why-ai-should-not-write-sql-against-erp-databases-1ef8</guid>
      <description>&lt;p&gt;Most AI + ERP demos start with the same pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect an LLM to a database.&lt;/li&gt;
&lt;li&gt;Show it the schema.&lt;/li&gt;
&lt;li&gt;Ask it to generate SQL.&lt;/li&gt;
&lt;li&gt;Execute the SQL.&lt;/li&gt;
&lt;li&gt;Summarize the rows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a toy database, this is fine.&lt;/p&gt;

&lt;p&gt;For an ERP system, it is a weak default.&lt;/p&gt;

&lt;p&gt;ERP data is not just tables and columns. It is protected by business semantics, user permissions, record rules, company boundaries, field visibility, implementation-specific conventions, and audit requirements.&lt;/p&gt;

&lt;p&gt;The question should not be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can the model generate SQL?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The better question is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can the system answer business questions while preserving the governance rules that already protect the ERP?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo path is not the production path
&lt;/h2&gt;

&lt;p&gt;The fastest demo is often the most dangerous production design.&lt;/p&gt;

&lt;p&gt;If the model sees a database schema, it can produce impressive results quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sale_order&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;res_partner&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But an ERP database schema is not the real product boundary.&lt;/p&gt;

&lt;p&gt;The real boundary lives higher up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which user is asking;&lt;/li&gt;
&lt;li&gt;which business object the user is allowed to access;&lt;/li&gt;
&lt;li&gt;which record rules apply;&lt;/li&gt;
&lt;li&gt;which companies the user can see;&lt;/li&gt;
&lt;li&gt;which fields are sensitive;&lt;/li&gt;
&lt;li&gt;which workflow states have business meaning;&lt;/li&gt;
&lt;li&gt;which metric definition is correct;&lt;/li&gt;
&lt;li&gt;which query should be rejected instead of guessed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A generated SQL string does not naturally carry that context.&lt;/p&gt;

&lt;p&gt;This is why "LLM writes SQL against the ERP database" is a useful demo technique, but a poor default architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raw SQL skips too many boundaries
&lt;/h2&gt;

&lt;p&gt;When an AI client generates raw SQL against an ERP database, several boundaries become fragile.&lt;/p&gt;

&lt;p&gt;First, user permissions are usually not encoded in the schema. A table name does not tell the model which user can see which records, which company boundary applies, or which fields are hidden by business policy.&lt;/p&gt;

&lt;p&gt;Second, business semantics are not obvious from column names. A field called &lt;code&gt;state&lt;/code&gt; might mean a sales lifecycle state, an invoice state, a delivery state, an approval state, or a local customization.&lt;/p&gt;

&lt;p&gt;Third, audit becomes weak. If the main artifact is a generated SQL query, the system still has to explain why that query was allowed, what business model it mapped to, which permission rules were applied, and whether the returned result was within the user's access boundary.&lt;/p&gt;

&lt;p&gt;Fourth, the interface tends to expand in the wrong direction. Once arbitrary SQL is accepted, users will ask for joins, subqueries, CTEs, window functions, unsupported tables, and "just one more column." The capability looks stronger on paper, while the safety boundary becomes less clear.&lt;/p&gt;

&lt;p&gt;For ERP AI, "supports arbitrary SQL" is not the strongest promise.&lt;/p&gt;

&lt;p&gt;A better promise is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The system can answer useful business questions through governed query paths, and it can clarify or reject requests when the boundary is not safe.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ERP AI needs semantic models
&lt;/h2&gt;

&lt;p&gt;A governed semantic layer changes the shape of the problem.&lt;/p&gt;

&lt;p&gt;Instead of exposing physical tables, the system exposes query models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;business fields with human-readable meaning;&lt;/li&gt;
&lt;li&gt;dimensions and measures;&lt;/li&gt;
&lt;li&gt;supported filters and aggregations;&lt;/li&gt;
&lt;li&gt;known relationships;&lt;/li&gt;
&lt;li&gt;metric definitions;&lt;/li&gt;
&lt;li&gt;permission and field boundaries;&lt;/li&gt;
&lt;li&gt;safe execution routes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model no longer needs to discover the ERP from raw schema. It receives a controlled business interface.&lt;/p&gt;

&lt;p&gt;For example, in an Odoo context, a user should ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Show me the top 5 customers by total sales revenue in the last 30 days.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system should route that through a governed sales query model, apply the effective Odoo user's permissions, execute within the supported query capability, and return structured results with evidence.&lt;/p&gt;

&lt;p&gt;The model should not be invited to use raw tables as its primary interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP is useful, but protocol is not enough
&lt;/h2&gt;

&lt;p&gt;MCP gives AI clients a standard way to call tools. That is valuable.&lt;/p&gt;

&lt;p&gt;But MCP alone does not make a tool safe.&lt;/p&gt;

&lt;p&gt;An MCP tool can expose raw SQL. It can ignore permissions. It can leak internal errors. It can return data the user should never see.&lt;/p&gt;

&lt;p&gt;For enterprise data, governance has to live inside the tool boundary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication and tenant context;&lt;/li&gt;
&lt;li&gt;user or service-principal binding;&lt;/li&gt;
&lt;li&gt;permission projection from the host system;&lt;/li&gt;
&lt;li&gt;semantic model selection;&lt;/li&gt;
&lt;li&gt;query validation;&lt;/li&gt;
&lt;li&gt;result sanitization;&lt;/li&gt;
&lt;li&gt;audit evidence;&lt;/li&gt;
&lt;li&gt;fail-closed behavior when scope is unclear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, the tool should not simply be a protocol wrapper around database access.&lt;/p&gt;

&lt;p&gt;It should be a governed execution boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Odoo is a good case study
&lt;/h2&gt;

&lt;p&gt;Odoo makes the problem concrete.&lt;/p&gt;

&lt;p&gt;An Odoo user is not just a PostgreSQL user. Odoo controls access through model permissions, record rules, company access, and field boundaries.&lt;/p&gt;

&lt;p&gt;If an AI tool bypasses Odoo and directly queries PostgreSQL, it risks bypassing the system that administrators actually use to govern data access.&lt;/p&gt;

&lt;p&gt;The safer route is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP clients connect through Odoo-issued access.&lt;/li&gt;
&lt;li&gt;Query model visibility follows Odoo-side access boundaries.&lt;/li&gt;
&lt;li&gt;Odoo rules are applied before query execution.&lt;/li&gt;
&lt;li&gt;Multi-company boundaries are preserved.&lt;/li&gt;
&lt;li&gt;Field boundaries are handled before results reach the AI client.&lt;/li&gt;
&lt;li&gt;Raw database access is kept out of the model's hands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important point is not that Odoo is the only target.&lt;/p&gt;

&lt;p&gt;The important point is that the host system should remain the authority for permissions and business context.&lt;/p&gt;

&lt;p&gt;That same principle applies to other business systems as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capability should be layered, not unlimited
&lt;/h2&gt;

&lt;p&gt;Another mistake is to measure progress by asking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How much SQL can the AI generate?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For governed business data, a more useful question is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which classes of business questions can the system answer safely, and where does it clarify or reject?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Foggy, the query capability is intentionally layered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;standard DSL-style queries for detail rows, filters, aggregations, TopN, and trends;&lt;/li&gt;
&lt;li&gt;controlled expression-style queries for comparisons, validations, and audit checks;&lt;/li&gt;
&lt;li&gt;staged query patterns for ratios, cumulative contribution, SLA-style checks, and funnel-like calculations;&lt;/li&gt;
&lt;li&gt;governed small-result secondary analysis;&lt;/li&gt;
&lt;li&gt;clarification when time range, metric definition, grain, or business rule is missing;&lt;/li&gt;
&lt;li&gt;rejection when the request asks for prediction, causal claims, physical table access, permission bypass, or write-back actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a more honest contract than "the model can write any SQL."&lt;/p&gt;

&lt;p&gt;It allows useful business analysis while keeping unsupported requests visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for Odoo
&lt;/h2&gt;

&lt;p&gt;I am applying this design through Foggy Odoo Bridge.&lt;/p&gt;

&lt;p&gt;The current Odoo direction is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Odoo 17 Community and Enterprise;&lt;/li&gt;
&lt;li&gt;Odoo.sh or On Premise as the practical deployment targets;&lt;/li&gt;
&lt;li&gt;Community edition for lightweight MCP / semantic-query evaluation;&lt;/li&gt;
&lt;li&gt;Pro edition for the in-Odoo AI Chat experience, curated query models, audit/export workflows, and supported production adoption;&lt;/li&gt;
&lt;li&gt;standalone MCP access without requiring OpenAI or Anthropic SDKs in the Odoo environment;&lt;/li&gt;
&lt;li&gt;optional built-in AI Chat when an administrator chooses to configure an LLM provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The intended message is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI directly queries the Odoo database.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The intended message is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI clients query Odoo business data through governed semantic tools while Odoo permissions remain in control.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The safe default
&lt;/h2&gt;

&lt;p&gt;For ERP AI, I think the safe default should be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not expose unrestricted database schema to the model.&lt;/li&gt;
&lt;li&gt;Do not make model-generated SQL the primary interface.&lt;/li&gt;
&lt;li&gt;Expose governed semantic tools instead.&lt;/li&gt;
&lt;li&gt;Preserve host-system permissions before query execution.&lt;/li&gt;
&lt;li&gt;Return structured results with evidence.&lt;/li&gt;
&lt;li&gt;Clarify or reject when the governance boundary is not clear.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is not to make AI look powerful in a demo.&lt;/p&gt;

&lt;p&gt;The goal is to make AI data access usable inside real enterprise boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;Foggy Odoo Bridge Community:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.odoo.com/apps/modules/17.0/foggy_mcp" rel="noopener noreferrer"&gt;https://apps.odoo.com/apps/modules/17.0/foggy_mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Foggy Odoo Bridge Pro:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.odoo.com/apps/modules/17.0/foggy_mcp_pro" rel="noopener noreferrer"&gt;https://apps.odoo.com/apps/modules/17.0/foggy_mcp_pro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Community repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/foggy-projects/foggy-odoo-bridge" rel="noopener noreferrer"&gt;https://github.com/foggy-projects/foggy-odoo-bridge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Product page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://odoo.foggysource.com" rel="noopener noreferrer"&gt;https://odoo.foggysource.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://foggy-projects.github.io/foggy-data-mcp-docs/" rel="noopener noreferrer"&gt;https://foggy-projects.github.io/foggy-data-mcp-docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am especially interested in feedback from Odoo implementers, ERP engineers, and developers building MCP tools for business data.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>odoo</category>
      <category>erp</category>
    </item>
    <item>
      <title>Foggy Odoo Bridge: Governed MCP Access to Odoo Data with Permission Preservation</title>
      <dc:creator>JiangGuangFeng</dc:creator>
      <pubDate>Mon, 30 Mar 2026 04:53:08 +0000</pubDate>
      <link>https://forem.com/foggy-projects/foggy-odoo-bridge-governed-mcp-access-to-odoo-data-with-permission-preservation-3bd</link>
      <guid>https://forem.com/foggy-projects/foggy-odoo-bridge-governed-mcp-access-to-odoo-data-with-permission-preservation-3bd</guid>
      <description>&lt;p&gt;I just open-sourced Foggy Odoo Bridge.&lt;/p&gt;

&lt;p&gt;It is an Odoo addon that gives AI clients governed MCP access to Odoo data while preserving Odoo permission rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Most "AI + ERP" demos stop at connectivity. Foggy Odoo Bridge focuses on governed access instead — it keeps authentication, model visibility, and row-level rules inside Odoo before the query reaches the engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API-key auth from Odoo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ir.model.access&lt;/code&gt; based model visibility&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ir.rule&lt;/code&gt; conversion into query filters before execution&lt;/li&gt;
&lt;li&gt;Multi-company isolation&lt;/li&gt;
&lt;li&gt;Built-in semantic models for common Odoo objects&lt;/li&gt;
&lt;li&gt;Built-in AI Chat inside Odoo&lt;/li&gt;
&lt;li&gt;Support for embedded Python engine or external Foggy Python / Java services&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment Options
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Embedded Python engine inside Odoo&lt;/li&gt;
&lt;li&gt;External Foggy Python service&lt;/li&gt;
&lt;li&gt;External Foggy Java service&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dependency Notes
&lt;/h2&gt;

&lt;p&gt;If you only use it as a standalone MCP service, you do not need &lt;code&gt;openai&lt;/code&gt; or &lt;code&gt;anthropic&lt;/code&gt; in the Odoo environment. Those SDKs are only optional dependencies for the built-in AI Chat feature.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/foggy-projects/foggy-odoo-bridge" rel="noopener noreferrer"&gt;https://github.com/foggy-projects/foggy-odoo-bridge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>odoo</category>
      <category>mcp</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
