Devices no longer connect to the backend directly. The /wallet Socket.io namespace is removed from realtime.ts; a new services/relay-client.ts connects to the standalone Temetro Network relay's /hub namespace (RELAY_TOKEN-auth), emitToWallet delegates to its sendToWallet, and device responses + wallet:online replay are handled there via the same wallet-share/wallet-updates services. - Add RELAY_URL + RELAY_TOKEN env (env.ts, .env.example, docker-compose.yml); the wallet-import QR (resolveRelayUrl) now points at RELAY_URL. - Add socket.io-client dependency. - Document the Temetro Network folder/service in root + backend CLAUDE.md. - Bump root/backend/frontend to 0.7.0; CHANGELOG entry. The relay service itself lives in github.com/temetro/temetro-network. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project
temetro — an open-source clinical tool that acts as an AI middleman between clinicians and
patient data. Clinicians use a natural-language AI chat to retrieve and organize patient information,
displayed as rich record cards.
The distinguishing idea is a patient-owned data model. Instead of (or alongside) living in a doctor's own database, a patient's record can be stored on the patient's own device. When a clinician adds or changes data, they sign it (blockchain-style); the change is written to the patient's record and cannot be modified until the patient approves it through a companion app. temetro can also read existing patient databases and present them in the same organized card UI.
This repository is a monorepo: the frontend/ and backend/ apps live side by side in one git
repository (published as temetro).
Status: the backend is built.
backend/is a TypeScript + Express + Postgres API (Drizzle ORM) with authentication and multi-tenant clinics via Better Auth, plus an org-scoped patient records API. Thefrontend/chat is wired to it: real auth (login/signup/reset/onboarding), route protection, clinic switching, and patient data fetched over the API — the old in-memory fixture is gone (frontend/lib/patients.tsnow calls the backend).Now built (thin slice): a patient wallet app (
~/Desktop/temetro-app, sibling repo — see "Patient wallet app" below) and an end-to-end encrypted share / patient-approval flow: clinics hold a real Ed25519 signing key (Settings → Signing,backend/src/services/signing.ts), and "Import from a patient app" on the Patients page relays an encrypted request to the wallet over the Temetro Network relay (see below), the patient approves on their phone, and the sealed record is imported (with optional temporary share + auto-delete). Clinic→wallet record-update push and QR pairing are built too. Seebackend/src/routes/{signing,patients-wallet}.ts.Still vision, not built: in-app record editing and cryptographic time-boxing of temporary shares. The AI chat is still mock replies. Email verification is wired but currently not enforced at sign-in (see
backend/CLAUDE.md).
Patient wallet app (sibling repo ~/Desktop/temetro-app)
The patient companion app is its own git repo on the Desktop (not in this monorepo): an Expo
SDK 56 app whose UI must be built with HeroUI Native (heroui-native + Uniwind/Tailwind) — a
hard requirement; the one exception is the native tab bar, which uses expo-router NativeTabs. See
its CLAUDE.md. It stores the patient's record encrypted on-device,
the patient's identity is an Ed25519 keypair whose public key (base58check, tmw_…) is their
wallet number, and it shares records by sealing them to a clinic's ephemeral key over the
backend relay. The crypto wire format mirrors backend/src/lib/wallet-crypto.ts exactly. "Decentralization"
here means keys + data live on the patient's device and the relay only ever forwards ciphertext — it
is not a literal blockchain (records are off-chain, which is also what lets a temporary share be
deleted). Commit/push that app inside its own repo, separately from this one.
Temetro Network (sibling repo/folder ~/Desktop/Temetro-network)
The relay that connects this backend to patient wallet apps. It is its own git repo on the
Desktop (folder ~/Desktop/Temetro-network, pushed to github.com/temetro/temetro-network), not
in this monorepo — a standalone Rust + Axum + socketioxide service meant to run always-on (e.g.
on Railway). It replaces the old flaky Cloudflare quick-tunnel that used to expose the backend's
embedded /wallet Socket.io namespace to phones.
It is a dumb, stateless pipe: two Socket.io namespaces — /wallet for devices
(challenge/Ed25519-signature auth, room keyed by wallet number) and /hub for this backend
(RELAY_TOKEN-authenticated). Devices and the backend both connect to it; it forwards sealed
ciphertext verbatim and never opens bundles or touches a database. Its only crypto is verifying a
device's auth signature (mirrors backend/src/lib/wallet-crypto.ts). The backend connects to it as a
/hub client via backend/src/services/relay-client.ts (its sendToWallet is what emitToWallet
now calls); configure with RELAY_URL + RELAY_TOKEN. Commit/push that service inside its own repo,
separately from this one.
Note: in this sandbox the
~/Desktop/Temetro-networkfolder blocks directory enumeration (ls/getcwd/git inside it return EPERM) though plain file writes work. Develop/build/commit it in an accessible copy and mirror the tree in withtar; drive git there viaGIT_DIR/GIT_WORK_TREEfrom an accessible cwd.
Layout
frontend/ and backend/ were previously separate per-folder git repos; they have been merged
into this single monorepo with full history of both preserved.
The marketing landing page is not in this monorepo — it lives in the sibling Desktop folder
../temetro/landing-page (/Users/khalidabdi/Desktop/temetro/landing-page), right next to the
../temetro/docs site. It is its own git repository (a Next.js app with the marketing
components/landing/); edit and commit it there, separately from this repo.
frontend/— the Next.js product app (the AI chat UI). This is where almost all current work happens. It has its ownCLAUDE.md— readfrontend/CLAUDE.mdfor the stack, commands, architecture, and gotchas.backend/— the TypeScript + Express + Postgres API (Drizzle ORM + Better Auth). Built and Dockerised. Has its ownCLAUDE.md(andREADME.md) — read it for the auth/schema workflow and gotchas.
frontend/ and backend/ are independent apps, each with its own package.json /
node_modules. Run npm commands from inside the relevant app directory, not from this root.
Documentation (very important)
The project documentation lives outside this repo, in the sibling Desktop folder
../temetro/docs (/Users/khalidabdi/Desktop/temetro/docs) — a Fumadocs (Next.js) site with
user guides (content/docs/guides/), an API reference (content/docs/api/), admin docs, and a
roadmap (content/docs/roadmap.mdx). It is its own git repository.
Whenever you make a significant change here — a new feature, endpoint, page, or behavior
change — update the affected docs pages in the same work session so the documentation stays
accurate (e.g. a new backend route needs an content/docs/api/*.mdx entry; a UI feature belongs
in the matching guide; status changes belong in the roadmap). Commit docs changes inside that
repo, separately from this one.
Every release must also get a dated entry in the docs changelog
(content/docs/changelog.mdx, newest first) — not just the monorepo CHANGELOG.md. When you cut a
version (see "Always release after pushing"), add a matching, user-facing section to that page in the
same session so ../temetro/docs never falls behind the shipped version.
Running the stack
From backend/: ensure a .env exists (cp .env.example .env, then set BETTER_AUTH_SECRET via
openssl rand -base64 32), then docker compose up --build → frontend :3000, backend :4000,
Postgres. Compose builds the sibling ../frontend app, which works because they remain siblings in
the monorepo. See backend/README.md.
Port note: if another Postgres already holds host port 5432, set
POSTGRES_PORT(e.g.5433) inbackend/.env— the app still talks to Postgres internally ondb:5432; only the published host port changes.
For local dev without Docker, run npm run dev in backend/ and frontend/ separately (the
frontend reads NEXT_PUBLIC_API_URL, default http://localhost:4000).
Version control (single monorepo)
This root is one git repository (temetro). The old per-folder .git repos are gone —
frontend/ and backend/ are plain subdirectories now.
Commit after every change. When you finish a task, commit from the repo root
(git add -A && git commit). Keep each commit focused on one logical change, and prefix the subject
with the area when useful (e.g. frontend: / backend:). End commit messages with the
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> trailer.
.env files are git-ignored (only .env.example is tracked) — never commit real secrets.
Always release after pushing
When you finish a unit of work and push to main, you must also cut a release — temetro
ships as prebuilt Docker images, so an un-released change never reaches a self-hosted clinic. After
the push:
- Bump the version to the new
X.Y.Zin all threepackage.jsonfiles (root,backend/,frontend/) — they must stay in sync (GET /api/versionreports it). - Update
CHANGELOG.md(moveUnreleasednotes under a dated## [X.Y.Z]heading). - Publish the images to Docker Hub as
khalidxv/temetro-backendandkhalidxv/temetro-frontend, taggedX.Y.Zandlatest. The tag-triggeredreleaseworkflow does this automatically (git tag vX.Y.Z && git push origin main --tags).
See RELEASING.md for the full checklist. Never consider work "done and
pushed" without the version bump + image publish.
Customized Next.js (frontend)
The frontend/ app runs a customized Next.js 16 whose APIs/conventions differ from public docs.
Before writing Next.js code, read the relevant guide under
frontend/node_modules/next/dist/docs/01-app/.
Root tooling
.mcp.jsonregisters the shadcn MCP server, and the rootpackage.jsonpins theshadcnCLI — used to browse/add registry components into the apps. There is nothing to build or run at this root level.