Skip to content

Instantly share code, notes, and snippets.

@jakmaz
Created April 30, 2026 15:04
Show Gist options
  • Select an option

  • Save jakmaz/d4bf57edd4b9faba5ee938ae1e8a36b5 to your computer and use it in GitHub Desktop.

Select an option

Save jakmaz/d4bf57edd4b9faba5ee938ae1e8a36b5 to your computer and use it in GitHub Desktop.

What You're Building

A personal backend platform — a self-hosted system that collects, stores, and serves your personal data through a unified API. Single-user only (yours). Think of it as your own private backend that powers a web UI, mobile apps, browser extensions, and an AI assistant that can query and modify your data.

Core idea: Instead of scattered scripts and one-off tools, you have one extensible system that owns all your data.


Architecture

The system has three layers:

  • Backend — API server handling all business logic and data persistence. Runs on its own port.
  • Frontend — Web UI for interacting with your data. Runs independently, communicates with the backend via HTTP.
  • Database — Stores all your data. Single file, zero config.

You can serve the frontend from the backend, run them as separate processes, or deploy them independently. Whatever works for you.

Background workers run on a schedule to fetch external data (prices, feeds, APIs) and write to the database.


Core Principles

  1. Minimal — Start simple, add only what's needed
  2. Iterative — Improve incrementally, don't build advanced features at once
  3. Simple code — Favor readability over cleverness. Plain functions over abstractions.
  4. Single-user — No auth, no roles, no multi-tenancy. It's your data.
  5. Own your data — Everything lives in your database. No SaaS lock-in.

Backend

Routing

Use a lightweight routing approach. Map "METHOD /path" strings to handler functions. Support :id style params. No heavy framework needed.

Example pattern:

GET  /api/books          → list all books
GET  /api/books/:id      → get single book
POST /api/books          → create book
PUT  /api/books/:id      → update book
DELETE /api/books/:id    → delete book

Route Organization

Group routes by domain. Each route file exports a map of "METHOD /path" → handler. A central router matches incoming requests to the right handler.

Background Workers

Use a simple cron scheduler. Workers run at scheduled times, fetch external data, and write to the database. On failure, send a notification (push notification, email, etc.).


Database

Approach

  • Use SQLite for simplicity (single file, zero config, backups are just file copies)
  • Use an ORM with codegen (like Drizzle ORM) for type-safe queries
  • Start with a few tables, add more as you need them
  • No migration system needed initially — just update the schema and restart

Example Tables

book           — Personal library (title, author, status, rating, genre, notes)
movie          — Movie collection (title, year, director, actors, rating, metadata)
game           — Game library (title, platform, playtime, tags, purchase_date)
subscription   — Recurring costs (name, amount, billing_cycle, next_billing, active)
workout        — Exercise log (type, duration, distance, notes, date)

Pick what matters to you. The point is: your data, your schema.


Frontend

Structure

  • Single-page application
  • One layout component with a sidebar for navigation
  • Each domain gets its own page (books, movies, games, etc.)
  • Use a component library or build simple primitives (button, card, input, dialog)

Design

  • Clean and minimalist
  • Consistent page wrappers with loading states
  • Keyboard shortcuts for common actions

Data Fetching

  • Simple typed API client
  • In-memory cache with invalidation on mutations
  • No need for complex state management — keep it simple

AI Assistant

Build an AI chat interface that can query and modify your database.

Architecture

Use an AI SDK (like Vercel AI SDK) with function calling / tool use. Provide two tools:

  1. queryDatabase — Read-only SELECT queries. Validates that the query only reads from known tables. Returns results as JSON.

  2. executeWrite — INSERT/UPDATE/DELETE queries. Requires explicit user confirmation in the UI before execution. Never auto-execute writes.

System Prompt

Give the AI assistant:

  • The full database schema
  • Guidelines for writing safe queries
  • Context about what the data represents
  • Instructions to be helpful and conversational

Chat UI

  • Render tool calls inline (show the SQL being executed)
  • Show Confirm/Cancel buttons for write operations
  • Stream the AI response
  • Keep conversation history

This lets you chat naturally: "Show me my unread books" or "Add a new movie: Inception, 2010" — and the AI handles the database operations.


Adding New Features

The pattern for adding any new domain:

  1. Add a table to the database schema
  2. Create a route file with CRUD endpoints
  3. Build a page in the frontend
  4. (Optional) Add a worker if it fetches external data
  5. Update the AI system prompt so it knows about the new table

That's it. Each new feature follows the same pattern.


Tech Stack Suggestions

These are what I use, but choose whatever you're comfortable with:

Layer My Choice Why
Runtime Bun Fast, built-in bundler, Bun.serve() for HTTP
Database SQLite Single file, zero config, easy backups
ORM Drizzle ORM Type-safe, codegen, lightweight
Frontend React Familiar, great ecosystem
Styling TailwindCSS Utility-first, fast
AI Vercel AI SDK Clean API, streaming, tool use
Scheduling Croner Simple cron expressions
Notifications ntfy.sh Self-hosted push notifications
Linting Biome Fast, single config for all code

What to Build First

Start with these three things:

  1. One table — Pick something simple (books, movies, workouts)
  2. CRUD endpoints — GET, POST, PUT, DELETE for that table
  3. A page — List + create + edit UI

Once that works, add:

  • A second table
  • The AI chat endpoint with queryDatabase tool
  • Background worker for one external data source
  • More pages

Don't overthink it. Build the simplest thing that works, then iterate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment