asopi tech
asopi techIndie Developer

Asopitech With · Note app

Notion with Alopex DB

Notion is a note app that organizes notes and documents into pages and blocks. How would we make it with Alopex DB?

Updated: Oct 12, 2026

What the service does

In a Notion-like note app, everything on a page is a block. Text, images and tables are stacked as blocks, any block can be turned into another type, and blocks are rearranged by drag and drop. The data is workspaces, the page hierarchy, the order and content of blocks, and search across pages.

Where the data lives

  • SQL tables: workspaces, pages and blocks live in tables. Each block points to its parent, so blocks form a tree, and a recursive CTE walks a page from top to bottom. Attributes that differ by block type go in a JSON column.
  • Vectors: each block’s embedding sits in a vector column of the same table. A question such as “the part of last month’s minutes about pricing” is answered through an HNSW index.
  • Full-text search: headings and proper names are found through a full-text index. Meaning-based and word-based search are combined in the same SQL.

The app creates the embeddings. When a block changes, the app computes a new embedding and commits the text and the vector in the same transaction. Search results always point at the current text.

Deployment

Each workspace is a single .alopex file. Alopex DB is embedded in the desktop app, so reading, writing and searching all happen on the device, with or without a network. Copying or handing over a workspace is a file copy. A shared team workspace is the same file opened by the Alopex DB server and reached over HTTP or gRPC.

Why Alopex DB fits

A note app is built around tree-shaped documents and search across them. Alopex DB handles tables, JSON, full-text search and vectors in one file and one transaction. The notes and their search index always describe the same moment.

See it in code

Page blocks form a tree via parent_id, and a recursive CTE walks them top to bottom. Just the core of assembling a document.

import alopex

# ワークスペースごとに1つの .alopex ファイル
db = alopex.Database.open("notion.alopex")

# ページとブロックを持つ。ブロックは parent_id で木になる
db.execute_sql("""
    CREATE TABLE IF NOT EXISTS blocks (
        id INTEGER PRIMARY KEY,
        page_id INTEGER,
        parent_id INTEGER,
        pos INTEGER,
        kind TEXT,
        body TEXT
    )
""")

# あるページのブロックを書き込む(見出しの下に段落、その下にネスト)
blocks = [
    (1, 1, None, 0, "heading", "議事録"),
    (2, 1, 1, 0, "text", "価格の方針を決めた"),
    (3, 1, 1, 1, "text", "次回までに見積もり"),
    (4, 1, 2, 0, "text", "基準は原価の1.5倍"),
]
for b in blocks:
    db.execute_sql("INSERT INTO blocks (id, page_id, parent_id, pos, kind, body) VALUES (?, ?, ?, ?, ?, ?)", list(b))

# 再帰CTEで、ページの中身を上から順に、入れ子の深さつきでたどる
page = db.execute_sql("""
    WITH RECURSIVE tree AS (
        SELECT id, parent_id, pos, body, 0 AS depth
        FROM blocks WHERE page_id = ? AND parent_id IS NULL
        UNION ALL
        SELECT b.id, b.parent_id, b.pos, b.body, t.depth + 1
        FROM blocks AS b JOIN tree AS t ON b.parent_id = t.id
    )
    SELECT depth, body FROM tree ORDER BY depth, pos
""", [1])

for row in page:
    print("  " * row["depth"] + row["body"])

The recursive CTE walks nested blocks with their depth, so a tree-shaped document lines up in one SQL query.

For a note app, we recommend Alopex DB, which keeps blocks and semantic search in one .alopex file. You can try it from the quickstart.