Set the Zoo (200200) and Pars (494949) addresses (bounty/escrow/reputation + karma, + Pars governor) to the newly deployed DAO-Safe-owned work-market, superseding the smoke set the boards read today. Owner/governor unchanged. Lux + Hanzo untouched. Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Work Board
White-label on-chain community work platform — a DAO's "Dework". It reads a live Bounty / Escrow / Reputation / Karma work-market directly over JSON-RPC (no subgraph) and renders the full Dework surface: Overview (org header + time-to- payment / total-paid stats + Bounties category grid), Board (To Do / In Progress / In Review / Done kanban), Open Tasks, Leaderboards (Top Contributors / Reviewers; Task Points = global Karma), Community Suggestions, Combined Board, per-Space tabs, a task detail with the real on-chain activity log + apply flow, and a cross-org Explore. The differentiator is portable reputation: per-DAO Reputation + global soul-bound Karma travel with the worker's address, not the platform. Mobile-first (390px up); every view also renders from a fixture with no wallet/chain, so it is always screenshot-able.
One repo, one Dockerfile. A build-time brand (VITE_BRAND, default zoo)
selects the white-label profile — chain, addresses, owner label, header/title,
and the RPC host baked into the CSP — from src/brands.ts:
| Brand | Chain | Site |
|---|---|---|
zoo |
200200 | https://work.zoo.network |
pars |
494949 | https://work.pars.network |
Run
npm install
npm run dev # http://localhost:5173 (proxies /rpc -> 127.0.0.1:9631 port-forward)
npm run build # tsc --noEmit && vite build -> dist/
npm run preview # serve the production build
Point the dev proxy at any node instead of the local port-forward, and select a brand:
RPC_TARGET=https://api.pars.network npm run dev
VITE_BRAND=pars VITE_RPC_URL=https://api.pars.network/v1/bc/C/rpc npm run build
If the RPC is unreachable, the board renders a faithful fixture of that brand's live bounty #0 (behind the same render path) so the UI stays verifiable; the source badge shows FIXTURE.
Config
Brand-varying values live in one map: src/brands.ts; src/config.ts selects
the active brand from VITE_BRAND. To add a board, add a brand profile — it's a
data change, not a code change.
Deploy
CI (.github/workflows/docker.yml) builds on every push to main on luxfi's
in-cluster ARC pool (lux-build-amd64) and pushes to ghcr.io/luxfi/work-board
— never built locally. A brand matrix stamps one immutable tag per brand from
the same Dockerfile:
zoo→:sha-<commit>→ zoo-k8s, namespacezoo-mainnet(manifests ink8s/)pars→:pars-<commit>→ pars-k8s, namespacepars(manifests ink8s/pars/)
Each deployment.yaml + service.yaml runs 2 replicas serving dist on :3000,
Service :80 → :3000; pin the Deployment to the CI tag then kubectl apply. Each
route.yaml is the Traefik dynamic-config router (host → Service, TLS via the
ingress's built-in ACME resolver); hanzoai/ingress routes every public host
through a @file ConfigMap (zoo: zoo-system/zoo-dynamic; pars:
hanzo/pars-dynamic), not Ingress objects — merge the fragment in (see the
header in each route.yaml).
Data source
Zoo 200200
| Contract | Address |
|---|---|
| Bounty | 0x3EDb4a0104614b4aC12D5babCE984291aE8BE8E7 |
| Escrow | 0x095E68282aea751Cc70A2Be565270f1B6AB0229C |
| Reputation | 0xed976852e8c2b1283e4F475845046B679224460D |
| owner | 0x229599f227231d8C90fcF1a78589F5DC4b7A6962 (Zoo DAO Safe) |
Pars 494949
| Contract | Address |
|---|---|
| Bounty | 0x316B41c886c7D4B4e38cBB08a243776Ed977cf1F |
| Escrow | 0xD5890D32d603a04E35ec7dBAbDCD0CA400f07E92 |
| Reputation | 0x155d1363c23467929FB709FCFa0afC51F3497aB6 |
| owner | 0x4CEA4ac1C874a340B06e0422E77a477463C3a542 (Pars DAO Safe) |
bountyCount() + bounties(i) give the current struct; BountyProposed /
WorkSubmitted logs give issueRef / deliverableRef; Reputation.completedOf /
earnedOf give the worker's score. ABIs are copied into src/abi.ts (no cross-repo import).