[HN Gopher] Show HN: SnackBase - Open-source, GxP-compliant back...
___________________________________________________________________
Show HN: SnackBase - Open-source, GxP-compliant back end for Python
teams
Hi HN, I'm the creator of SnackBase. I built this because I work
in Healthcare and Life Sciences domain and was tired of spending
months building the same "compliant" infrastructure (Audit Logs,
Row-Level Security, PII Masking, Auth) before writing any actual
product code. The Problem: Existing BaaS tools (Supabase,
Appwrite) are amazing, but they are hard to validate for GxP (FDA
regulations) and often force you into a JS/Go ecosystem. I wanted
something native to the Python tools I already use. The Solution:
SnackBase is a self-hosted Python (FastAPI + SQLAlchemy) backend
that includes: Compliance Core: Immutable audit logs with
blockchain-style hashing (prev_hash) for integrity. Native Python
Hooks: You can write business logic in pure Python (no webhooks or
JS runtimes required). Clean Architecture: Strict separation of
layers. No business logic in the API routes. The Stack: Python
3.12 + FastAPI SQLAlchemy 2.0 (Async) React 19 (Admin UI) Links:
Live Demo: https://demo.snackbase.dev Repo:
https://github.com/lalitgehani/snackbase The demo resets every
hour. I'd love feedback on the DSL implementation or the audit
logging approach.
Author : lalitgehani
Score : 54 points
Date : 2026-01-13 12:27 UTC (10 hours ago)
(HTM) web link (snackbase.dev)
(TXT) w3m dump (snackbase.dev)
| dkoy wrote:
| Briefly checked out the repo and demo, looks neat!
|
| Bookmarked to keep a tab on for future reference.
|
| I noticed that SQLAlchemy (an ORM) is part of the stack, and that
| "Postgres support" is in the roadmap. For people coming from
| Supabase and the like which is Postgres-first, some upfront
| clarification around which database is already supported, would
| be helpful.
| lalitgehani wrote:
| Thanks for the kind words and the bookmark!
|
| You're right. Since I use SQLAlchemy, the core is already
| database agnostic. Swapping the connection string to Postgres
| actually works for most features right now.
|
| I listed it as "Roadmap" only because I haven't finished the
| full end-to-end test suite for Postgres yet, and I wanted the
| default "Quick Start" to be a zero dependency SQLite setup. I
| am also working on native read/write splitting so that the
| system can properly leverage scaling architectures (like Amazon
| Aurora's single-writer / multi-reader clusters) out of the box.
|
| I'll make sure to clarify in the docs that it's currently
| "experimental" rather than missing. Appreciate the feedback!
| mring33621 wrote:
| I'm not sure the AGPL license is a good choice for this.
|
| None of Django, Rails, Pocketbase or Supabase, which I think
| count as competitors, use AGPL.
|
| Unless you can clarify that custom hooks and schemas are outside
| of the AGPL license, SnackBase may be a non-starter for
| commercial use.
| lalitgehani wrote:
| Fair point.
|
| Honestly, I picked AGPL mainly to prevent "cloud wrapping". I
| definitely don't intend for your business logic to get infected
| by it.
|
| In my view, the custom hooks and schemas are
| "content/configuration" rather than derivative works, but I get
| that running in-process makes that legally murky.
|
| To clear that up, I'll add a specific linking exception (like
| the Classpath Exception) to explicitly exempt user-defined
| hooks from the license. I want this to be safe for commercial
| teams to self-host, just not safe for cloud providers to
| resell.
| notpushkin wrote:
| This is really cool. I probably won't be using it directly, but
| will definitely study some architecture and implementation
| decisions.
|
| > Compliance Core: Immutable audit logs with blockchain-style
| hashing (prev_hash) for integrity.
|
| Had this in the back of my mind for a while now, too. In terms of
| prior art, Keybase had been doing something similar, but with
| Merkle trees.
|
| > I'd love feedback on the DSL implementation
|
| Could you tell in a bit more detail why you decided to go with
| your own DSL here? :)
| lalitgehani wrote:
| Great question!
|
| Keybase's Merkle approach is elegant for their use case
| (efficient proofs without revealing the full chain), but I went
| simpler with a linear chain because:
|
| 1. Audit trails are inherently sequential - they're ordered by
| time and typically read/written in order. Merkle trees shine
| for unordered data where you need efficient inclusion proofs.
| 2. Verification simplicity - with a linear chain, integrity
| verification is just "walk the sequence and check that each
| entry's previous_hash matches the prior entry's checksum." O(n)
| and dead simple. 3. Storage efficiency - each entry stores two
| SHA-256 hashes as strings. No tree overhead. 4. Regulatory fit
| - for GxP/CFR Part 11 compliance, the requirement is tamper
| detection, not zero-knowledge proofs. A linear chain detects
| any modification equally well.
|
| That said, if I ever need selective verification (prove entry
| #500 is valid without transmitting the full chain), I'd revisit
| Merkle. The implementation is in src/snackbase/infrastructure/p
| ersistence/repositories/audit_log_repository.py if you're
| curious.
|
| On the custom DSL: This was the biggest architectural decision
| in SnackBase. Here's the honest breakdown:
|
| Why not just use existing options? >Approach: Python eval()
| >>Why I didn't choose it: Security nightmare - can't safely let
| users store arbitrary code in the database
|
| >Approach: CEL (Google's Common Expression Language) >>Why I
| didn't choose it: Battle-tested, but heavy dependency and less
| control over semantics
|
| >Approach: JEXL/JSONLogic >>Why I didn't choose it: Another
| runtime to learn, harder to integrate with my macro system
|
| >Approach: Pure JSON rules >>Why I didn't choose it: Becomes
| unreadable for complex expressions
|
| What drove the decision:
|
| 1. Permissions are database-storable - rules live as strings in
| the permissions table, editable via API and admin UI. I needed
| something safe to parse and evaluate at runtime. 2. Sandboxed
| execution - the DSL only exposes specific operations (==, in,
| @has_role(), etc.). No imports, no file access, no arbitrary
| code. Even if someone compromises the admin UI, they can only
| express logic within the vocabulary I provide. 3. Syntax for
| non-programmers - "@has_role('admin') and @owns_record()" is
| more approachable than Python lambdas when you're building
| permissions in a web UI. 4. Macro integration - the @ prefix
| ties into my SQL macro system, letting users define reusable
| business logic like @is_department_head() that executes
| database queries.
|
| The trade-off:
|
| It's 700+ lines of lexer/parser/evaluator code I have to
| maintain. Every edge case (null handling, type coercion, short-
| circuit evaluation) needs explicit test coverage. Debugging a
| failed rule means returning syntax errors at position X rather
| than a stack trace.
|
| If I were starting fresh today, I'd give CEL harder
| consideration. But since permissions are a core differentiator
| for SnackBase, having full control over the semantics has been
| worth it--especially for field-level access control and the
| wildcard collection system.
|
| Implementation files if you're interested in it: -
| src/snackbase/core/rules/lexer.py - tokenizer -
| src/snackbase/core/rules/parser.py - recursive descent - AST -
| src/snackbase/core/rules/evaluator.py - async evaluation with
| short-circuiting
|
| Happy to go deeper on any of this!
| nodesocket wrote:
| This looks fantastic. I'm working on a project I wrote in plain
| Flask. Wish I had seen this previously. I spent an ungodly amount
| of time on organizations, users, permissions, 2fa, password
| reset, organization invites.
| threecheese wrote:
| So much of new open source code feels like folks just sharing
| their Claude tokens with each other, after the fact. I'm having
| fun just gluing stuff together with _my_ Claude tokens.
|
| It's unfortunate that so many of these projects just whither
| away, blasts of commits with hundreds of files but nothing
| changed in months.
___________________________________________________________________
(page generated 2026-01-13 23:00 UTC)