<?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>DEV Community: Deepak Thomas</title>
    <description>The latest articles on DEV Community by Deepak Thomas (@thinkdj).</description>
    <link>https://dev.to/thinkdj</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%2F747561%2F814c0279-fe34-4f5a-b770-d6235781b8c0.png</url>
      <title>DEV Community: Deepak Thomas</title>
      <link>https://dev.to/thinkdj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thinkdj"/>
    <language>en</language>
    <item>
      <title>I built a Cloudflare-first batteries-included SaaS OSS framework for Solo Founders - Ottabase</title>
      <dc:creator>Deepak Thomas</dc:creator>
      <pubDate>Wed, 15 Apr 2026 16:28:45 +0000</pubDate>
      <link>https://dev.to/thinkdj/i-built-a-cloudflare-first-batteries-included-saas-oss-framework-for-solo-founders-ottabase-110l</link>
      <guid>https://dev.to/thinkdj/i-built-a-cloudflare-first-batteries-included-saas-oss-framework-for-solo-founders-ottabase-110l</guid>
      <description>&lt;p&gt;Every solo founder I know wastes the first 2-4 weeks (sometimes, months) of a new SaaS project doing the same setup dance: wire up auth,&lt;br&gt;
implement multi-tenancy, configure RBAC, pick a queue solution, add a blog engine and only &lt;em&gt;then&lt;/em&gt; actually build the product.&lt;/p&gt;

&lt;p&gt;I got tired of it and built &lt;strong&gt;Ottabase&lt;/strong&gt;: an open-source monorepo you clone and own. Once you fork it, the code is yours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fog02ps6roqb13jp8yvr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fog02ps6roqb13jp8yvr7.png" alt=" " width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The repo&lt;/strong&gt;: &lt;a href="https://github.com/thinkdj/ottabase" rel="noopener noreferrer"&gt;github.com/thinkdj/ottabase&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;pnpm workspaces + Turborepo&lt;/strong&gt;, deploying to &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;. All infrastructure is Cloudflare-native - D1 (SQLite at the edge), KV, R2, Queues, Durable Objects. No Docker, no separate database servers etc.&lt;/p&gt;

&lt;p&gt;Frontend is &lt;strong&gt;Vite + TanStack Router&lt;/strong&gt;. &lt;br&gt;
Backend is a &lt;strong&gt;Cloudflare Worker&lt;/strong&gt; running on the same repo.&lt;/p&gt;


&lt;h2&gt;
  
  
  What's included (45+ packages)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Data &amp;amp; Infrastructure
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottaorm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fat model ORM for auto-migrations, CRUD API, RLS, relationships, TanStack Query hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drizzle D1 driver (&lt;code&gt;createD1Driver&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/auth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auth.js v5 — OAuth (Google, GitHub), Credentials, Magic Link, D1 adapter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/rbac&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Role-based access control with per-org permission caching in KV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/audit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Audit logging with field-level change tracking and RBAC context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/queue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Laravel-style job queue — dispatch, handlers, deduplication, chaining, priority&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/cron&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cron handlers — static code-defined and DB-driven scheduler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/cf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cloudflare service wrappers — D1, KV, R2, Queues, Rate Limiting, read-through KV cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/cf-realtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WebSocket pub/sub built on Durable Objects (Pusher alternative)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/analytics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cloudflare Analytics Engine (WAE) — write events, query, funnel analysis, top-K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/logger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Structured logging with Console, HTTP, Sentry, Memory, and Buffer transports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;App config, env var helpers, storage key utilities&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Brand, Layout &amp;amp; Content
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/brand-engine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Design tokens, preset expansion, CSS injection, per-tenant theming, email branding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/brand-engine-react&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;BrandProvider&lt;/code&gt;, &lt;code&gt;LayoutResolver&lt;/code&gt;, and &lt;code&gt;useBrand()&lt;/code&gt; React bindings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottalayout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Layout types, 10 built-in presets, path resolver, React slot system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottablog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full blog/CMS — Post, Category, Tag, Series, Version models + Blog Studio editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email sending via Resend, SES, MailChannels, or SMTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/notifications&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multi-channel notifications — email and WebSocket push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/shortlinks&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL shortener with interstitial pages and WAE analytics tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/referrals&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Referral tracking with first-touch attribution and WAE analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  UI Components
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-shadcn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;shadcn/ui component library with &lt;code&gt;ShadcnProviders&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-mantine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mantine provider with pre-built themes, more like a POC of third party ui lib integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-tailwind&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tailwind config and shared design tokens. Core UI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-datatable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Advanced data table — TanStack Table v8, server-side sort/filter/pagination, bulk actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-components&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shared components — DarkModeToggle, Logo, and more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-code-highlight&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code syntax highlighting component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-split-pane&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resizable split pane&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ui-cropper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vanilla JS image cropper (~3–4 KB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/spotlight&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Command palette (&lt;code&gt;Ctrl+K&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Developer Experience
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/forms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-generated CRUD forms and list views from OttaORM model definitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottaeditor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EditorJS wrapper with 15+ block plugins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottarenderer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EditorJS block renderer for display&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottaupload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File uploads to R2 or Cloudflare Images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/ottaselect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Headless select/combobox component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Global state via Jotai — theme, user, sidebar atoms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/i18n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;i18next wrapper with en, es, fr, de built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/api&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Type-safe fetch wrapper for internal API calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/utils&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tree-shakeable utilities — timezone, string, URL, currency, file helpers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/scripts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI tools — &lt;code&gt;cf:login&lt;/code&gt;, &lt;code&gt;cf:setup&lt;/code&gt;, &lt;code&gt;cf:validate&lt;/code&gt;, &lt;code&gt;clean:*&lt;/code&gt;, &lt;code&gt;db:*&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/docs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Markdown doc viewer component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ottabase/migrate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Migration utilities&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  The core idea: *&lt;em&gt;fat *&lt;/em&gt; models, not controllers
&lt;/h2&gt;

&lt;p&gt;Business logic lives in the model. One place, auditable, no indirection maze.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todosTable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From one model definition you get: auto-migrations, a full REST CRUD API at &lt;code&gt;/api/ottaorm/todos&lt;/code&gt;, and TanStack Query&lt;br&gt;
hooks — all generated for free. Adding a field means updating the schema and hitting one endpoint to migrate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-tenancy and RLS built in from day one
&lt;/h2&gt;

&lt;p&gt;Every query automatically enforces tenant isolation via the OttaORM RLS engine. Provide context once at app init&lt;br&gt;
(&lt;code&gt;organizationId&lt;/code&gt;, &lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;appId&lt;/code&gt;) and queries are scoped automatically. Cross-tenant data leaks are prevented at&lt;br&gt;
the ORM layer — not left as a discipline exercise.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get running in 5 minutes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/thinkdj/ottabase.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ottabase
pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm build:pkg
&lt;span class="nb"&gt;cp &lt;/span&gt;apps/otta-web/.env.example apps/otta-web/.env.local
&lt;span class="c"&gt;# Fill in AUTH_SECRET, MIGRATION_SECRET, BOOTSTRAP_OWNER_SECRET&lt;/span&gt;
pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3003&lt;/code&gt;. If the platform isn't bootstrapped, it redirects you to a setup wizard — create tables,&lt;br&gt;
seed roles, create your owner account, finalize. No manual SQL, no curl commands needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned building this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Edge-first forces cleaner code.&lt;/strong&gt; No &lt;code&gt;fs&lt;/code&gt;, no &lt;code&gt;child_process&lt;/code&gt;, no Node-only APIs. Once that's the constraint, you stop reaching for heavy server-side dependencies and write leaner workers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fat models beat service layers for solo projects.&lt;/strong&gt; When a team of one has to find where a bug lives, "it's in the model" beats "it could be in the service, the controller, the middleware, or the helper."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-tenancy cannot be bolted on.&lt;/strong&gt; Every project I've tried to retrofit tenant isolation into was a nightmare. Having RLS enforced at the ORM level from the start means I never have to think about it again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monorepos pay off fast.&lt;/strong&gt; Turborepo's incremental build cache means full rebuilds only happen once. After that, changing one package rebuilds only what depends on it.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Ottabase Repo: &lt;a href="https://github.com/thinkdj/ottabase" rel="noopener noreferrer"&gt;github.com/thinkdj/ottabase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quick Start: &lt;a href="https://github.com/thinkdj/ottabase/blob/main/QUICKSTART.md" rel="noopener noreferrer"&gt;QUICKSTART.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Architecture: &lt;a href="https://github.com/thinkdj/ottabase/blob/main/ARCHITECTURE.md" rel="noopener noreferrer"&gt;ARCHITECTURE.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discussions: &lt;a href="https://github.com/thinkdj/ottabase/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Homepage (yeah, why not): &lt;a href="https://ottabase.com/" rel="noopener noreferrer"&gt;ottabase.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Would love your feedback, especially on the fat model pattern vs service layers debate, and anything you'd want added to the package list. Happy to answer questions in the comments. &lt;/p&gt;

&lt;p&gt;PS: I'm serious about package additions&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>typescript</category>
      <category>showdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
