Skip to content

Add the uniques services to the dev env (search API + demo UI + format filters) — needs uniques-search-api#1 first#2

Open
alexandrewavelet wants to merge 12 commits into
Altered-Community:mainfrom
alexandrewavelet:feat/uniques-rust-cards-api
Open

Add the uniques services to the dev env (search API + demo UI + format filters) — needs uniques-search-api#1 first#2
alexandrewavelet wants to merge 12 commits into
Altered-Community:mainfrom
alexandrewavelet:feat/uniques-rust-cards-api

Conversation

@alexandrewavelet

@alexandrewavelet alexandrewavelet commented Jun 11, 2026

Copy link
Copy Markdown

⚠️ MERGE ORDER — read first: the uniques / uniques-ui services build from, and the format wiring reads from, Altered-Re-Union/uniques-search-api#1 (docker/dev/, demo-ui/docker/dev/, formats/). That PR must be merged to uniques-search-api's main before this one — a fresh ./run.sh clones that repo's main (depth-1), so without those files the image build / format loading fails. Do not merge this PR until #1 is on main.

What

Adds two local services to the Aspire dev env, both from Altered-Re-Union/uniques-search-api (the Altered-Re-Union fork of Taum/rust-cards-api):

  • uniques (altered-uniques-api) — a Rust in-memory search engine over the Altered Unique cards (/api/v2/*).
  • uniques-ui (altered-uniques-ui) — the repo's demo-ui/, a Vite + React SPA for that API.

Standalone. The API is not the prod cards API (different contract, Unique characters only), so it doesn't replace ALTERED_CORE_URL / CARDS_API_URL. No DB, no Keycloak, no seed, nothing in DbGate.

uniques — the search API

  • Dev image (upstream) — built from the repo's docker/dev/Dockerfile; the AppHost bind-mounts the workspace at /app, runs cargo run -p uniques-http-api --release, cargo cache in the altered-uniques-api-target volume. Host 8003 → container 8080.
  • Index — the ~270 MB prebuilt index is downloaded once into the altered-uniques-index volume by the entrypoint; the loader reads the .tar.zst archive directly. Index path comes from the app's default.toml.

uniques-ui — the demo SPA

  • Built from the repo's demo-ui/docker/dev/Dockerfile; Vite dev server (HMR), demo-ui/ bind-mounted, node_modules in a volume.
  • Browser-only: the SPA calls the API directly (the API sets CorsLayer::permissive()), VITE_API_BASE_URL=http://localhost:8003. Vite's port is published directly (-p, like Keycloak) on 8004 so the HMR websocket lines up. Open at http://localhost:8004.
  • Declares a graph relationship to altered-uniques-api (edge only, no startup gating).

Formats (format= filter)

Wires the /api/v2 format filters via a dev-env-owned uniques/local.toml bind-mounted over the service's config/local.toml: enables [formats] (disk source /app/formats = the repo's committed formats/ dir) with hot-reload polling every 5 s.

  • ?format=frontier → the include format (300 cards, 50 per faction → &faction[]=AX returns 50).
  • ?format=living-legend → exclude CORE/COREKS + 60 refs.
  • Hot-reload triggers on a manifest version bump (bump it in both the format file and its manifest.json row).

Config & toggles

  • Toggles Services:uniques:Enabled and Services:uniques-ui:Enabled (both default true).
  • uniques config: env (PORT) + the app's default.toml (index) + the bind-mounted local.toml (formats). uniques-ui: env only.

Test

./run.sh
curl 'http://localhost:8003/api/v2/cards?limit=1'                               # search
curl 'http://localhost:8003/api/v2/cards?format=frontier&faction[]=AX&limit=1'  # iter.total == 50
# open http://localhost:8004 in a browser → demo UI (searches hit the API directly)

Also

  • chore: make run.sh executable; ignore .idea/.

🤖 Generated with Claude Code

alexandrewavelet and others added 3 commits June 11, 2026 02:53
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New standalone 'uniques' service: Altered-Re-Union/uniques-search-api (fork of
Taum/rust-cards-api), a Rust in-memory search engine over the Altered Unique cards
(/api/v2/*). Distinct from the prod cards API — no DB, no Keycloak, no seed, nothing
in DbGate.

- uniques/Dockerfile + docker-entrypoint.sh: dev image (the repo's own Dockerfile is
  prod-only and COPYs an uncommitted deployment/production.toml). Source is
  bind-mounted and 'cargo run'; the ~270 MB prebuilt index is downloaded once into a
  volume by the entrypoint (the binary loads it from disk, source=disk).
- apphost.cs: repoUrls entry + altered-uniques-api resource (host 8003 -> container
  8080), target/index volumes, PORT/INDEX_PATH env, dashboard URL. No WaitFor/seed.
- appsettings(.Local.json.example): uniques toggle (enabled by default).
- README: service row + 'uniques (uniques-search-api)' section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandrewavelet alexandrewavelet marked this pull request as draft June 11, 2026 00:56
alexandrewavelet and others added 2 commits June 11, 2026 03:05
…is gated)

Earlier wording wrongly implied /api/v2/effects needs formats; it serves from the
index (effects_body). Only the format= filter on /api/v2/cards is gated by the
formats artifact, which the prebuilt index bundle doesn't ship and the repo doesn't
generate. Add a dedicated Formats paragraph explaining what's left to wire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Runs uniques-search-api/demo-ui (Vite 6 + React 19 SPA) via the Vite dev server
(HMR). Browser-only: the SPA calls the API directly (the API sets permissive CORS),
so VITE_API_BASE_URL points at the browser-reachable API (localhost:8003) and no
proxy / CORS work is needed.

- uniques-ui/Dockerfile + docker-entrypoint.sh: node:22 dev image; demo-ui/ is
  bind-mounted, node_modules in a volume (npm ci on first start), npm run dev.
- apphost.cs: altered-uniques-ui resource; Vite port published directly (-p, like
  Keycloak) on the same internal/external port (8004) so the HMR websocket lines up.
  Declares a graph relationship to altered-uniques-api (edge only, no startup gating) —
  the dependency is browser-side, so WaitFor would needlessly block the UI behind the
  API's long first build.
- appsettings(.Local.json.example): uniques-ui toggle (enabled by default).
- README: service row + 'uniques-ui (demo-ui)' section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandrewavelet alexandrewavelet changed the title Add uniques-search-api (Rust Unique-cards search) to the dev env Add the uniques services to the dev env (Rust search API + demo UI) Jun 11, 2026
- apphost.cs: drop the redundant INDEX_PATH env override — default.toml already
  points at ./build/full_index.tar.zst (-> /app/build/...), so setting it again just
  logged config.rs's 'prefer index.path in config' warning on every start. (L1)
- apphost.cs: fix the uniques comment — CORS is already CorsLayer::permissive in the
  app's http.rs, so browser-direct callers (the demo-ui) work without adding anything. (M2)
- uniques/docker-entrypoint.sh: guard against a 0-byte/truncated index download being
  promoted (then skipped forever on restart) — abort if the .partial file is empty. (M1)
- README: warn against shadowing VITE_API_BASE_URL with a blank value in a demo-ui/.env*,
  which would route calls through Vite's unused :8234 proxy. (H1)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandrewavelet alexandrewavelet marked this pull request as ready for review June 12, 2026 07:28
Comment thread uniques-ui/docker-entrypoint.sh Outdated
@@ -0,0 +1,16 @@
#!/bin/sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best if the dockefiles lives in the original repo if they are not too specific for this usecase.
It seems these can be migrated in the original repo.

…service

The dev Dockerfile + entrypoint now live in the uniques-search-api repo under
docker/dev/ (separate from its prod root Dockerfile), so the AppHost points the uniques
resource at that Dockerfile and drops its local uniques/ copy.

REQUIRES Altered-Re-Union/uniques-search-api#1 to be merged to main FIRST: a fresh
clone pulls uniques-search-api's main, so docker/dev/ must be there or the image build
fails. (uniques-ui is unchanged — its dev image still lives here.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandrewavelet alexandrewavelet changed the title Add the uniques services to the dev env (Rust search API + demo UI) Add the uniques services to the dev env (Rust search API + demo UI) — needs uniques-search-api#1 first Jun 12, 2026
alexandrewavelet and others added 2 commits June 12, 2026 21:08
The demo-ui dev Dockerfile + entrypoint now live in uniques-search-api at
demo-ui/docker/dev/ (alongside the API's docker/dev/), so the AppHost points the
uniques-ui resource at that path and drops its local uniques-ui/ copy. Same merge-order
requirement: uniques-search-api#1 must land on main first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hot-reload

Bind-mounts a dev-env-owned uniques/local.toml over the uniques service's
config/local.toml, enabling [formats] (disk source = /app/formats = the repo's committed
formats/ dir) with 5s hot-reload polling. README Formats section updated.

Depends on Altered-Re-Union/uniques-search-api#1 (which ships formats/) being on main —
same merge-order requirement already flagged in this PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandrewavelet alexandrewavelet changed the title Add the uniques services to the dev env (Rust search API + demo UI) — needs uniques-search-api#1 first Add the uniques services to the dev env (search API + demo UI + format filters) — needs uniques-search-api#1 first Jun 12, 2026
julesduroux and others added 2 commits June 13, 2026 13:34
…e_modules volume

Build the demo-ui dev image from the repo's docker/dev/Dockerfile (context = demo-ui)
now that deps are baked at build time. The node_modules volume only un-shadows the baked
deps under the source bind-mount and is seeded from the image (no runtime install). Its
name is keyed to a hash of package-lock.json so a dependency change auto-uses a fresh
(re-seeded) volume; the AppHost prunes stale ones at startup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@Taum Taum left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this locally, LGTM except for the port clashes.
Thank you for adding this 🙏

Comment thread apphost.cs Outdated
// restarts. Same idea as decks/collection's vendor/ volume.
.WithVolume("altered-uniques-api-target", "/app/target")
.WithVolume("altered-uniques-index", "/app/build")
.WithHttpEndpoint(port: 8003, targetPort: 8080, name: "http")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8003 is claimed by Ownership since #3 landed (see https://github.com/Altered-Community/altered-dev-environment/pull/3/changes#diff-2669681c9c043163ece8811559ad1ba38a6a5e4f18d3e949ebcd09389a080a02R80). You'll probably need to re-number this to 8005.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I've updated it thanks!

PR Altered-Community#3 (ownership) landed on main and publishes on host port 8003; the uniques API also
grabbed 8003 -> the two Aspire endpoints would collide. 8004 is uniques-ui, so the API
moves to 8005 (endpoint + dashboard URL + the demo-ui's VITE_API_BASE_URL + README). The
internal alias altered-uniques-api:8080 is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants