|
| 1 | +# LoraDB Playground |
| 2 | + |
| 3 | +In-browser IDE for the LoraDB graph database. Runs entirely client-side — |
| 4 | +the WASM engine, the Cypher editor, the graph canvas, and the result grid |
| 5 | +all live in your browser tab. No backend, no server actions, no `/api` |
| 6 | +routes. Data persists locally via IndexedDB and `localStorage`. |
| 7 | + |
| 8 | +## Development |
| 9 | + |
| 10 | +```bash |
| 11 | +yarn workspace @loradb/play dev |
| 12 | +``` |
| 13 | + |
| 14 | +Open <http://localhost:3000>. |
| 15 | + |
| 16 | +Other useful scripts: |
| 17 | + |
| 18 | +```bash |
| 19 | +yarn workspace @loradb/play typecheck # strict tsc, --noEmit |
| 20 | +yarn workspace @loradb/play lint # next lint |
| 21 | +yarn workspace @loradb/play build # static export → apps/play.loradb.com/out |
| 22 | +``` |
| 23 | + |
| 24 | +If you change any of the workspace dependencies |
| 25 | +(`@loradb/lora-wasm`, `@loradb/lora-query`, `@loradb/lora-graph-canvas`), |
| 26 | +rebuild them first so the Next bundler picks up fresh artefacts: |
| 27 | + |
| 28 | +```bash |
| 29 | +yarn workspace @loradb/lora-wasm build |
| 30 | +yarn workspace @loradb/lora-query build |
| 31 | +yarn workspace @loradb/lora-graph-canvas build |
| 32 | +``` |
| 33 | + |
| 34 | +## Architecture summary |
| 35 | + |
| 36 | +- `app/` — Next 15 App Router shell, Mantine providers, root layout, and |
| 37 | + the playground page. |
| 38 | +- `app/_components/` — Dockview panel layout, query editor wrapper, |
| 39 | + graph canvas wrapper, result grid, etc. |
| 40 | +- `lib/` — client-only utilities (history, saved-queries, settings, |
| 41 | + snapshot import/export, worker plumbing for `@loradb/lora-wasm`). |
| 42 | +- `shims/empty.mjs` — webpack alias target used by `next.config.mjs` to |
| 43 | + drop `loader-node` from the client bundle (see config for rationale). |
| 44 | +- `public/` — static assets served verbatim, plus `_headers` and |
| 45 | + `_redirects` consumed by Cloudflare Pages at deploy time. |
| 46 | + |
| 47 | +The build is a fully static export: `yarn build` writes |
| 48 | +`apps/play.loradb.com/out/` with self-contained HTML, JS, CSS, and WASM |
| 49 | +assets that any object store / CDN can serve as flat files. |
| 50 | + |
| 51 | +## Production deploy |
| 52 | + |
| 53 | +### Recommended host: Cloudflare Pages |
| 54 | + |
| 55 | +The Docusaurus site at `apps/loradb.com` already occupies the single |
| 56 | +GitHub Pages site allowed per repo, so the playground deploys to |
| 57 | +Cloudflare Pages instead. The `.github/workflows/play-loradb.yml` |
| 58 | +workflow builds the static export on every push to `main` that touches |
| 59 | +the app or its workspace deps and uploads the result to Cloudflare via |
| 60 | +`cloudflare/wrangler-action@v3`. |
| 61 | + |
| 62 | +One-time setup: |
| 63 | + |
| 64 | +1. **Create the Pages project.** In the Cloudflare dashboard go to |
| 65 | + _Workers & Pages → Create → Pages → Create using Direct Upload_ and |
| 66 | + name it `play-loradb`. Do not connect a Git source — this repo |
| 67 | + deploys via GitHub Actions, not Cloudflare's built-in builder. |
| 68 | + (If you _do_ connect to Git, disable auto-builds; otherwise CF will |
| 69 | + try to run `next build` itself and fight the workflow.) |
| 70 | +2. **Attach the custom domain.** In the project page open |
| 71 | + _Custom domains → Set up a custom domain_ and enter |
| 72 | + `play.loradb.com`. Cloudflare prints a CNAME target like |
| 73 | + `play-loradb.pages.dev`. Add a `CNAME` record at your DNS provider |
| 74 | + for `play.loradb.com` pointing at that target, then wait for the |
| 75 | + custom-domain status in the dashboard to flip to "Active". TLS is |
| 76 | + issued automatically. |
| 77 | +3. **Provision repo secrets.** In GitHub go to _Settings → Secrets and |
| 78 | + variables → Actions → New repository secret_ and add: |
| 79 | + - `CLOUDFLARE_API_TOKEN` — create at |
| 80 | + <https://dash.cloudflare.com/profile/api-tokens> with the |
| 81 | + _Pages — Edit_ permission scope (Account → Cloudflare Pages → |
| 82 | + Edit). No other permissions are needed. |
| 83 | + - `CLOUDFLARE_ACCOUNT_ID` — visible in the right sidebar of any |
| 84 | + Cloudflare dashboard page. |
| 85 | + The deploy job runs a pre-flight check that fails with a clear |
| 86 | + `::error::` message if either secret is missing. |
| 87 | +4. **Trigger the first deploy.** Either push a change under |
| 88 | + `apps/play.loradb.com/` to `main`, or run the workflow manually: |
| 89 | + ```bash |
| 90 | + gh workflow run play-loradb |
| 91 | + ``` |
| 92 | + Once it completes the site is live at <https://play.loradb.com>. |
| 93 | + |
| 94 | +`wrangler.toml` at the app root pins `pages_build_output_dir = "out"` |
| 95 | +and the project name `play-loradb`, so you can also run an ad-hoc |
| 96 | +deploy from a workstation: |
| 97 | + |
| 98 | +```bash |
| 99 | +yarn workspace @loradb/play build |
| 100 | +npx wrangler pages deploy apps/play.loradb.com/out \ |
| 101 | + --project-name=play-loradb --branch=main |
| 102 | +``` |
| 103 | + |
| 104 | +### Alternative: Vercel |
| 105 | + |
| 106 | +Vercel is fully supported as a static host for the same `out/` |
| 107 | +directory. Workflow: |
| 108 | + |
| 109 | +1. Install the Vercel CLI globally (`npm i -g vercel`). |
| 110 | +2. From `apps/play.loradb.com`, run `vercel link --project play-loradb` |
| 111 | + to bind the directory to a new Vercel project. |
| 112 | +3. In the project settings on vercel.com configure: |
| 113 | + - Framework preset: **Next.js**. |
| 114 | + - Build command: `yarn workspace @loradb/play build`. |
| 115 | + - Install command: `yarn install --immutable` (run from the repo |
| 116 | + root — the project root must therefore be the repo root, not |
| 117 | + `apps/play.loradb.com`). |
| 118 | + - Output directory: `apps/play.loradb.com/out`. |
| 119 | +4. Add the custom domain `play.loradb.com` under _Domains_ and update |
| 120 | + the DNS `CNAME` to the Vercel target that the dashboard prints. |
| 121 | +5. If you want CI-driven deploys (rather than Vercel's own Git |
| 122 | + integration), add a workflow that runs `vercel deploy --prebuilt` |
| 123 | + after building. Not included by default — the Cloudflare workflow |
| 124 | + in this repo is the canonical path. |
| 125 | + |
| 126 | +There is **no** committed workflow for Vercel; this section is provided |
| 127 | +purely as a fallback. |
| 128 | + |
| 129 | +### Caveats |
| 130 | + |
| 131 | +- The app is fully static. There are no API routes, no server actions, |
| 132 | + no edge functions, no ISR — it _must_ be hosted as flat files behind |
| 133 | + a CDN. |
| 134 | +- The WASM payloads must be served with |
| 135 | + `Content-Type: application/wasm`. The bundled `public/_headers` file |
| 136 | + handles that on Cloudflare Pages; replicate the rule if you host |
| 137 | + elsewhere. |
| 138 | +- IndexedDB and `localStorage` are origin-scoped. Saved queries, |
| 139 | + snapshots, settings, and history are local to the user's browser |
| 140 | + and the active origin — switching origins (e.g. |
| 141 | + `play.loradb.com` ↔ a staging URL) does not migrate user data. |
| 142 | +- `@loradb/lora-wasm` ships its own Web Worker. Cross-origin isolation |
| 143 | + (`COOP`/`COEP`) is **not** required, but caching the worker and its |
| 144 | + WASM payload as `immutable` (handled by `public/_headers`) keeps |
| 145 | + reloads fast. |
| 146 | + |
| 147 | +## Build verification locally |
| 148 | + |
| 149 | +```bash |
| 150 | +yarn workspace @loradb/play build |
| 151 | +# Static export lands in apps/play.loradb.com/out |
| 152 | +npx serve apps/play.loradb.com/out -l 5000 |
| 153 | +# Visit http://localhost:5000 |
| 154 | +``` |
| 155 | + |
| 156 | +The static export is genuinely static — there is no `next start`. If |
| 157 | +something only works under `next dev` and breaks under `next build`, it |
| 158 | +is almost certainly an SSR-vs-static-export issue (e.g. a top-level |
| 159 | +`window` reference inside a module imported by a Server Component) and |
| 160 | +needs a `"use client"` boundary. |
| 161 | + |
| 162 | +## Known issues |
| 163 | + |
| 164 | +- **Hash-route reload via direct URL.** Deep links that encode state in |
| 165 | + the URL hash (`#q=...`) refresh cleanly because `_redirects` falls |
| 166 | + back to `index.html`; deep links that rely on a path that Next did |
| 167 | + not statically render at build time will 404. Keep new state in the |
| 168 | + hash, not the pathname, until we revisit routing. |
| 169 | +- **WASM mime on non-Cloudflare hosts.** Vercel and most CDNs serve |
| 170 | + `.wasm` correctly out of the box; bespoke object-store setups (e.g. |
| 171 | + raw S3 + CloudFront) need a manual MIME override or the browser |
| 172 | + refuses to instantiate via streaming. |
| 173 | +- **Workspace dep rebuilds.** The CI workflow rebuilds `lora-wasm`, |
| 174 | + `lora-query`, and `lora-graph-canvas` before building `@loradb/play`. |
| 175 | + Locally, after pulling, run the workspace builds shown in the |
| 176 | + Development section or `next build` may load stale `dist/` output. |
0 commit comments