<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged tencentedgeone</title>
<link>https://coderlegion.com/tag/tencentedgeone</link>
<description>Powered by Question2Answer</description>
<item>
<title>I Almost Shipped a Broken Database on Tencent EdgeOne Makers. Here's What Fixed It</title>
<link>https://coderlegion.com/27136/i-almost-shipped-a-broken-database-on-tencent-edgeone-makers-heres-what-fixed-it</link>
<description>&lt;p&gt;Here's a mistake I bet a lot of developers coming from traditional hosting will make on their first serverless edge project: assuming a local database file will just... work.&lt;/p&gt;
&lt;p&gt;I made that mistake building &lt;strong&gt;OptiQ&lt;/strong&gt;, a sales-tracking app for small optical shops, on &lt;strong&gt;Tencent EdgeOne Makers&lt;/strong&gt;. This post is less &quot;here's a polished tutorial&quot; and more &quot;here's the debugging path I took,&quot; because I think the reasoning matters more than the final answer.&lt;/p&gt;
&lt;h3 id=&quot;the-project-briefly&quot;&gt;The Project, Briefly&lt;/h3&gt;
&lt;p&gt;Small optical shops have a messy sales pattern that most POS templates don't handle well. A customer might buy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Just a frame&lt;/li&gt;
&lt;li&gt;Just a lens&lt;/li&gt;
&lt;li&gt;A complete pair (frame + lens)&lt;/li&gt;
&lt;li&gt;Softlens&lt;/li&gt;
&lt;li&gt;Small accessories (cleaning solution, frame screws) — no prescription needed&lt;br&gt;
On top of that, the shop needs to track refraction data (OD/OS, cylinder, axis) per customer, and &lt;em&gt;sometimes&lt;/em&gt; link it to a sale — but not always. OptiQ is my answer to that: a small, relational, low-cost app built specifically around that flexibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Low-cost was non-negotiable here. I'm the only IT person at my company, so I don't get to justify infrastructure spend for a side project — it has to run on free tiers, or it doesn't ship.&lt;/p&gt;
&lt;h3 id=&quot;mistake-1-treating-an-edge-function-like-a-regular-server&quot;&gt;Mistake #1: Treating an Edge Function Like a Regular Server&lt;/h3&gt;
&lt;p&gt;For context, EdgeOne Makers is the rebrand of EdgeOne Pages (as of June 2026) — it grew from &quot;frontend hosting&quot; into a full-stack platform for Web and AI Agent apps, with support for React, Vue, Next.js, Astro, and a few agent frameworks. That expanded scope is what made it worth using for something beyond a static site.&lt;/p&gt;
&lt;p&gt;My plan was simple: static frontend on Pages, API logic on Pages Functions, SQLite file for storage. Deploy was smooth — genuinely, push-to-live in minutes, no CDN or SSL setup needed.&lt;/p&gt;
&lt;p&gt;Then I hit the wall: &lt;strong&gt;edge functions are stateless.&lt;/strong&gt; There's no persistent filesystem, and a given request might get routed to a different edge instance than the last one. A &lt;code&gt;.db&lt;/code&gt; file written on one request could be gone — or inconsistent — by the next. This isn't an EdgeOne-specific limitation; it's true of serverless edge compute generally. But it's an easy thing to &lt;em&gt;forget&lt;/em&gt; if your mental model still comes from VPS-style deployments.&lt;/p&gt;
&lt;p&gt;Lesson: figure out your state strategy before you write a single API route, not after your first weird bug report.&lt;/p&gt;
&lt;h3 id=&quot;mistake-2-almost-picking-a-database-that-sleeps-when-you-need-it-awake&quot;&gt;Mistake #2 (Almost): Picking a Database That Sleeps When You Need It Awake&lt;/h3&gt;
&lt;p&gt;Once I accepted I needed a managed database, I evaluated three options:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1 — EdgeOne's native KV store.&lt;/strong&gt; Fast, simple, and built in. But it's key-value only — no joins, no relational queries. For OptiQ, that would mean hand-rolling indexes for every access pattern (&lt;code&gt;transactions by customer&lt;/code&gt;, &lt;code&gt;transactions by date range&lt;/code&gt;) and computing monthly totals by pulling records into app code and summing manually. It works, but it's the kind of thing that quietly turns into technical debt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2 — Supabase.&lt;/strong&gt; Full Postgres, generous free tier, great DX. Then I read the fine print: free projects &lt;strong&gt;pause after ~7 days of inactivity&lt;/strong&gt; and need a manual restore to wake back up. A shop that doesn't sell something every single day could open the app to a database that's asleep. That's a bad failure mode for a business tool, even a small one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 3 — Turso.&lt;/strong&gt; SQLite (libSQL), but run as a managed service and queried over HTTP — which means it works fine from a stateless edge function, unlike a local file. Real SQL (joins, constraints, aggregates), no idle-pause behavior. This is what I went with, and the schema I'd already sketched needed almost zero changes to work with it.&lt;/p&gt;
&lt;h3 id=&quot;the-part-of-the-schema-that-actually-matters&quot;&gt;The Part of the Schema That Actually Matters&lt;/h3&gt;
&lt;p&gt;Most of OptiQ's schema is unremarkable — customers, products, transactions, transaction line items. The one decision worth calling out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE transactions (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  customer_id INTEGER REFERENCES customers(id),
  refraction_id INTEGER REFERENCES refractions(id), -- nullable, on purpose
  total REAL NOT NULL
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;refraction_id&lt;/code&gt; is nullable. That's the whole trick. Without it, I'd have needed separate transaction tables (or awkward sentinel values) for &quot;sale with a prescription attached&quot; vs &quot;sale without one&quot; — like buying a bottle of lens cleaner shouldn't require a fake prescription record just to satisfy a NOT NULL constraint. One nullable foreign key instead of a schema fork.&lt;/p&gt;
&lt;h3 id=&quot;where-edgeone-makers-full-stack-positioning-actually-paid-off&quot;&gt;Where EdgeOne Makers' Full-Stack Positioning Actually Paid Off&lt;/h3&gt;
&lt;p&gt;The thing I didn't expect going in: not having to stitch together three separate vendors. Static hosting, edge API functions, and (once I wired it up) the database connection all lived in one deploy pipeline. If you've ever debugged a CORS or env-var mismatch between a frontend host, a serverless function provider, and a database vendor that don't share tooling, you'll get why that's worth mentioning.&lt;/p&gt;
&lt;h3 id=&quot;if-you-re-about-to-build-something-similar&quot;&gt;If You're About to Build Something Similar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Decide your state/database approach &lt;em&gt;before&lt;/em&gt; your first API route — not as a fix after deploying.&lt;/li&gt;
&lt;li&gt;Check what happens to your database on &lt;em&gt;inactivity&lt;/em&gt;, not just under load. &quot;Free tier&quot; often hides a failure mode in the fine print.&lt;/li&gt;
&lt;li&gt;Use nullable foreign keys deliberately when your domain has &quot;sometimes this relationship exists, sometimes it doesn't&quot; — it's cheaper than modeling every variant as a separate table.&lt;br&gt;
OptiQ is live at &lt;a rel=&quot;nofollow&quot; href=&quot;https://optiq.logota.biz.id/&quot;&gt;optiq.logota.biz.id&lt;/a&gt; — built on Tencent EdgeOne Makers as part of Codepolitan's DevHandal 2026 Batch 2.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;#TencentEdgeOne #EdgeOneMakers #CODEPOLITAN #EdgeOne&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27136/i-almost-shipped-a-broken-database-on-tencent-edgeone-makers-heres-what-fixed-it</guid>
<pubDate>Mon, 14 Sep 2026 09:21:13 +0000</pubDate>
</item>
</channel>
</rss>