This is the PRE-IMPLEMENTATION design memo, kept as a record of the original intent. The app has moved past it in three ways, so do not read this file as documentation of what runs today —
README.mdis that.
This memo says What the app does no Docker, local only Dockerfile+fly.toml; deployed to fly.io, auto-deploy on pushaccounts: username + salted hash Google OIDC ( server/bookshelf/auth.clj)JSON API EDN API ( server/bookshelf/server.clj)The rest — cljw as the web server, the Rust cover-colour module, SQLite compiled to
wasm32-wasias the datastore — is accurate and is what the demo is for. Kept rather than deleted because the reasoning below (why a wasm SQLite instead of a Clojure-side store, why Ring-style) is still the reasoning.
A small "bookshelf" web app — Google-Cloud-Bookshelf-like — that runs on native
cljw (no JVM). It is the CFP's "real edge app anyone can try",
demonstrating:
- ClojureWasm as the web server. The HTTP server is
cljw.http.server/run-server(Ring-style), serving a ClojureScript SPA + a JSON API, all on the cljw binary. - Polyglot via the Wasm FFI. Two other-language wasm assets run inside the app:
- a cover-colour module (Rust →
wasm32-unknown-unknown, called withwasm/call) that deterministically computes a book's cover colour from its title — "another language's asset runs in a real app". - the datastore is real SQLite compiled to
wasm32-wasi(C → wasi-sdk), driven viawasm/runagainst a DB file in a preopened dir — a genuine DB call where the DB engine itself is a wasm module.
- a cover-colour module (Rust →
- Accounts: log in with Google (OIDC; cookie session). (The memo originally planned a local username + salted hash — see the note at the top.)
- Own shelf: CRUD books (title, author, description, labels, favourite).
- Other shelves: view read-only; copy a book from another shelf to your own.
- Search: across all books (title / author / label).
- Cover colour: computed by the Rust wasm module (stable per title).
browser ──HTTP──> cljw.http.server (run-server) ──wasm/call──> cover_color.wasm (Rust)
(cljs SPA) | routes /api/* ──wasm/run───> sqlite3.wasm (C→wasi)
| │ preopen data/
└── serves resources/public (built SPA) └─ books.db
- Backend (
server/bookshelf/*.clj, run bycljw): routing, session, thedbnamespace (wrapswasm/runon sqlite3.wasm — builds SQL, parses rows), and thecovernamespace (wrapswasm/callon cover_color.wasm). - Frontend (
src/bookshelf/*.cljs): same stack as playground-v2 — shadow-cljs, React, Mantine, phosphor, factorhouse/rfx + hsx. - No Docker, no JVM, no cloud.
data/books.dbis a local SQLite file; the SQLite engine runs as wasm. Everything starts withcljw+bb/shadow-cljslocally.
db.clj calls:
(wasm/run "wasm/sqlite3.wasm"
{:args ["sqlite3" "/data/books.db" "-json" SQL]
:dirs [["data" "/data"]]})and parses :out as JSON rows. SQL is built with parameterised escaping in Clojure
(the sqlite CLI takes one SQL string; we quote values safely). One preopened dir
(data/ → guest /data) holds the persistent DB file.
- Uses the cljw capabilities that exist today:
run-server,wasm/call, the newwasm/run(ADR-0124) with:dirspreopen. - The DB engine being a wasm module is the strongest form of the polyglot claim: not just a pure-compute kernel, but a real stateful C library running in the sandbox and persisting to a real file.
- Local-only, Docker-free, matches the user's constraint.
- Backend skeleton on cljw
run-serverwith EDN persistence (get the app working). - Frontend SPA (shelves, CRUD, search) against the JSON API.
- Swap EDN → sqlite3.wasm via
wasm/run(real DB-via-wasm). - Cover-colour Rust wasm via
wasm/call. - Verify end-to-end in Chrome (my-playwright).