Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
e7484e6
feat: add redesign animation keyframes and design tokens
heyradcode Jun 21, 2026
cdea83d
feat: add ambient shell background layer
heyradcode Jun 21, 2026
10e7fd5
feat: introduce redesigned collapsible app shell
heyradcode Jun 21, 2026
974f3f9
feat: redesign /main as the full-width idle gallery
heyradcode Jun 21, 2026
0658de5
feat: restyle interaction chrome with per-view washes
heyradcode Jun 21, 2026
6169ac1
refactor: remove orphaned hub, layout, and route helper
heyradcode Jun 21, 2026
b05bad6
style: unify interaction CTAs with the mock accent button
heyradcode Jun 21, 2026
13c86eb
feat: add pet showcase to the level-up panel
heyradcode Jun 21, 2026
e9df270
feat: add live name preview to the rename panel
heyradcode Jun 21, 2026
801a244
feat: add pet status card to the training panel
heyradcode Jun 21, 2026
bb9f72b
feat: add marriage benefits banner; fix panel test mocks
heyradcode Jun 21, 2026
0a7f027
refactor: extract shared PetShowcase ring-avatar hero
heyradcode Jun 21, 2026
43531ae
feat: add parent preview to the breed panel
heyradcode Jun 21, 2026
82f1737
fix: address code-review findings in gallery, ambient, panels
heyradcode Jun 21, 2026
b7bce0c
ui: remove ambient scanline sweep
heyradcode Jun 21, 2026
a3ad6b5
fix: keep wallet control in the header flow
heyradcode Jun 21, 2026
738b751
feat: add DNA helix + compatibility ring to breeding lab
heyradcode Jun 21, 2026
dfd4326
feat: enrich redesign panels toward the Crypto Pets mock
heyradcode Jun 21, 2026
e1cee64
feat: add Gallery to the sidebar nav
heyradcode Jun 21, 2026
5f4effb
feat: use Claude-Design nav icons in the sidebar
heyradcode Jun 21, 2026
cfb416d
feat: reshape battle fight/result to the design layout
heyradcode Jun 21, 2026
0ab5da1
fix: add padding to the pet gallery
heyradcode Jun 21, 2026
ada51bb
feat: reshape battle setup into the design showdown
heyradcode Jun 25, 2026
4e2c1d5
fix: consistent padding around routed content
heyradcode Jun 25, 2026
98b6385
fix: unify interaction panel width with battle
heyradcode Jun 25, 2026
3189f37
fix: keep tall interaction panels within the viewport
heyradcode Jun 25, 2026
34b563e
feat: cycle breed parents instead of dropdowns
heyradcode Jun 25, 2026
84f67f0
fix: shorten the breed panel
heyradcode Jun 25, 2026
ce3bb3e
ui: simplify breed cards to match the design
heyradcode Jun 25, 2026
7c351f7
feat: move breed action to center, drop trait prediction
heyradcode Jun 25, 2026
d39628d
style: flatten the breed panel card
heyradcode Jun 25, 2026
d3cfc5c
refactor: remove the breed .interface wrapper
heyradcode Jun 25, 2026
12a329f
ui: shorten the breed parent cards
heyradcode Jun 25, 2026
0b2b700
ui: remove the radar rings around the showcase avatar
heyradcode Jun 25, 2026
8abbb9f
chore: remove dead code left by the redesign
heyradcode Jun 25, 2026
26618df
chore: remove dead battle-setup CSS
heyradcode Jun 25, 2026
a26553e
refactor: prune unused battle-setup props and dead hook internals
heyradcode Jun 25, 2026
3f5efc2
refactor: delete the legacy CSS variable alias block
heyradcode Jun 25, 2026
38259b7
refactor: merge --neon-* color tokens into --cp-*
heyradcode Jun 25, 2026
e912d65
refactor: unify remaining global CSS tokens under --cp-
heyradcode Jun 25, 2026
f535e94
refactor: convert neon-card to a CSS Module
heyradcode Jun 25, 2026
204809e
refactor: convert transaction-status to a CSS Module
heyradcode Jun 25, 2026
0ea3c45
refactor: convert toast to a CSS Module
heyradcode Jun 29, 2026
992c44a
refactor: convert Icon to a CSS Module + noGap prop
heyradcode Jun 29, 2026
79cbdb1
refactor: convert top-bar to a CSS Module
heyradcode Jun 29, 2026
e48beaf
refactor: convert sidebar to a CSS Module
heyradcode Jun 29, 2026
7bfd315
refactor: move shared loading/error styles to messages.css
heyradcode Jun 29, 2026
2c5361c
refactor: convert send-pet-modal to a CSS Module
heyradcode Jun 30, 2026
82613fa
refactor: convert train panel local styles to a CSS Module
heyradcode Jun 30, 2026
b15237a
refactor: convert breed panel local styles to a CSS Module
heyradcode Jun 30, 2026
fda65bc
refactor: convert marriage panel local styles to a CSS Module
heyradcode Jun 30, 2026
31e0f56
refactor: convert battle panel local styles to a CSS Module
heyradcode Jun 30, 2026
8b2ce5f
refactor: convert pet-search-dropdown to a CSS Module
heyradcode Jul 4, 2026
4f01f20
refactor: convert account-dropdown internals to a CSS Module
heyradcode Jul 4, 2026
f94326b
refactor: convert account-dropdown internals to a CSS Module
heyradcode Jul 4, 2026
20106a9
refactor: convert network-switcher to a CSS Module
heyradcode Jul 4, 2026
3cb3844
chore: remove dead global CSS orphaned by the modules migration
heyradcode Jul 4, 2026
9363eaf
refactor: convert pet-showcase to a CSS Module; drop global cp-float
heyradcode Jul 4, 2026
de3b36b
test: repair tests broken by the CSS Modules migration
heyradcode Jul 4, 2026
b8ef791
test: repair tests broken by the CSS Modules migration
heyradcode Jul 4, 2026
b6dfedd
chore: run the CSS naming guard in the pre-commit hook
heyradcode Jul 8, 2026
1c26521
chore: error on explicit any instead of warning
heyradcode Jul 8, 2026
7042aa8
test: realign tests/ to mirror src/ structure
heyradcode Jul 8, 2026
72ba03d
refactor: extract useAccountTokenBalances from account-dropdown
heyradcode Jul 8, 2026
533894f
refactor: extract pure view derivations from useBattlePanel
heyradcode Jul 8, 2026
dd2e9a1
refactor: rename layout/index.tsx to Layout.tsx; document barrel conv…
heyradcode Jul 12, 2026
8415d03
docs: add CLAUDE.md with basic project architecture
heyradcode Jul 12, 2026
8621187
docs: add behavioral working guidelines to CLAUDE.md
heyradcode Jul 12, 2026
907b16a
docs: add loops-and-autonomy guidance to CLAUDE.md
heyradcode Jul 12, 2026
586b5b0
docs: add AGENTS.md root coordination contract
heyradcode Jul 12, 2026
f88ad85
docs: import AGENTS.md into CLAUDE.md so Claude Code loads both
heyradcode Jul 12, 2026
1d68add
fix: add top margin above Change Name button on rename panel
heyradcode Jul 13, 2026
63cdeb3
refactor: rename CSS module import alias from `s` to `styles`
heyradcode Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pnpm lint:fix && git add -u
pnpm lint:fix && git add -u && pnpm --filter frontend lint:css
50 changes: 50 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# AGENTS.md

Root coordination contract for AI and human contributors in this repo. Detailed architecture and working guidelines live in [CLAUDE.md](./CLAUDE.md); this file states the non-negotiables and where to look.

## Scope

- Applies to the whole monorepo: `frontend/`, `backend/`, `mobile/`, `website/`, `shared/`, `contracts/ethereum/`, `contracts/solana/`, `indexer-go/`, `proto/`.
- No nested `AGENTS.md` files exist yet. If one is added under a package, it may tighten rules for that subtree but must not relax the rules here.

Normative language: `MUST`/`MUST NOT` are mandatory. `SHOULD`/`SHOULD NOT` are expected by default; deviations should be explained in the PR. `MAY` is optional.

## Non-Negotiables

- `MUST NOT` edit the golden test vectors in `contracts/test-vectors/{battle,xp}.json` to make a failing test pass. If a vector fails, the Go or Rust port has drifted from the Solidity contract; fix the drifted port, never the vector.
- `MUST` update all three combat-simulator ports together (`contracts/ethereum/src/CombatSim.sol`, Solana's `combat.rs`, `indexer-go/internal/combat/`) when changing combat logic. Never patch one leg alone.
- `MUST NOT` assume a shared cross-chain TypeScript interface exists in `shared/`. EVM and Solana logic are intentionally duplicated side by side in `frontend/src/chains/{ethereum,solana}/`.
- `MUST` match the license of the package being edited when adding new files: `contracts/ethereum`, `contracts/solana`, `indexer-go`, and `proto` are MIT; everything else is PolyForm Noncommercial 1.0.0 (root `LICENSE`). See the table in `README.md`.
- `MUST NOT` treat the v1 contract gaps documented in `contracts/plan-contract-upgrade.md` (no battle authorization, the `changeDna` cheat, client-supplied Solana starter-pet DNA) as bugs to silently patch. They are the known baseline the v2 rewrite is designed around.
- `MUST` run the smallest scoped lint/test/build command for the package you touched (see Command Baseline below), not a full monorepo run, unless the change is broad.
- `SHOULD NOT` trust `DEVELOPMENT.md`, `contracts/ethereum/README.md`, or the root `eth:deploy` / `eth:vrf:watch` scripts at face value. Several reference commands removed in a past refactor; see CLAUDE.md's Commands section for what is actually current.

## Command Baseline

- Install: `pnpm install` (root), or `pnpm install:all` (root + frontend + website + backend + mobile + contracts/ethereum)
- Dev: `pnpm dev:fe` / `pnpm dev:be` / `pnpm dev:mobile` / `pnpm dev:web`, or `pnpm fe:eth:local` / `pnpm fe:sol:local` for a full local chain + backend + frontend stack
- Lint: `pnpm lint` (covers frontend, shared, website, mobile only, not backend or contracts/ethereum)
- Test: `pnpm test` (equals `contracts/ethereum` test only; per-package test commands are in CLAUDE.md)
- Build: `pnpm build`

Full per-package lint/test/build matrix and single-test syntax: see [CLAUDE.md](./CLAUDE.md#commands).

## Where To Look

- Behavioral guidelines and full architecture: [CLAUDE.md](./CLAUDE.md)
- Data flow and component map: [docs/architecture.md](./docs/architecture.md)
- Test suite conventions: [docs/testing.md](./docs/testing.md)
- Backend API surface: [backend/API.md](./backend/API.md)
- Indexer internals: [indexer-go/README.md](./indexer-go/README.md)
- Contract v1-to-v2 migration plan: [contracts/plan-contract-upgrade.md](./contracts/plan-contract-upgrade.md)
- Contribution workflow: [CONTRIBUTING.md](./CONTRIBUTING.md)
- Reporting vulnerabilities: [SECURITY.md](./SECURITY.md)

## Enforcement

Mechanical checks over prose, where they exist:

- ESLint per package (`frontend`, `shared`, `website`, `mobile`), plus a custom CSS-naming check in `frontend` (`lint:css`).
- Golden test vectors (`contracts/test-vectors/{battle,xp}.json`), run by Hardhat, Anchor, and `indexer-go`'s `combat_golden_test.go`, are the cross-language enforcement for combat-simulator parity.
- CI coverage workflow (`.github/workflows/coverage.yml`) runs frontend/backend/shared vitest coverage on every PR and posts a combined comment.
- There is no repo-wide `agents:check` or module-boundary lint yet. Rely on the per-package commands above and the golden vectors until one exists.
129 changes: 129 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

@AGENTS.md

The import above pulls in the cross-tool non-negotiables and command baseline from [AGENTS.md](./AGENTS.md), shared with other coding agents (Cursor, Codex, etc.). Everything below is Claude Code specific.

## What this is

`do-not-stop` (product name **cryptopets**) is a pnpm monorepo for a Web3 pet-battling game deployed on both Ethereum (Hardhat/Sepolia) and Solana (local validator/devnet). Live demo: https://cryptopets.vercel.app.

## Working Guidelines

**Think before coding.** State assumptions explicitly rather than silently picking between interpretations. If a request is ambiguous, or a simpler approach exists than the one implied, say so before implementing, especially around the chain-parity and licensing boundaries documented below, where a wrong guess is expensive to unwind.

**Simplicity first.** No speculative abstractions, no unrequested configurability, no error handling for scenarios that can't occur at the call site. If a change could be half the size, make it that size.

**Surgical changes.** Touch only what the task requires; match each file's existing style even where you'd choose differently. When your edit makes an import, variable, or function unused, remove it, but leave pre-existing dead code alone and just flag it. Never drive-by "fix" one leg of the combat simulator (Solidity/Rust/Go) without updating the other two and rerunning the golden vectors (see Architecture).

**Goal-driven execution.** For multi-step work, state a short plan with a verification step per item, e.g. "port fix to indexer-go, then verify with `go test ./internal/combat -run TestName` against the golden vector." Use the smallest per-package command from the table below that actually exercises the change, not the whole suite, unless the change is broad.

**Loops and autonomy.** "Done" means the relevant command from the table above passes, not "looks right." Work on a branch so changes are easy to revert. Autonomous or `/loop`-driven runs need an explicit stop condition (a passing test, a clean lint run) and an iteration cap; don't loop indefinitely on judgment calls like game-balance tuning or design decisions, those are a human call. If you hit the cap or get stuck, stop and report what you tried and what's blocking, rather than thrashing or guessing further.

**Text.** In commit messages, PR descriptions, and docs written for this repo: no em-dashes, no filler ("it's worth noting," "essentially"), no LLM tells ("it's not just X, it's Y," "delve"). Reread before finishing and cut anything that doesn't earn its place.

**Commit messages.** After any set of file changes, automatically draft and show a Conventional Commits message (`feat:`, `fix:`, `docs:`, `chore:`, etc., matching this repo's history) in a copyable code block, without waiting to be asked. Scope it to the actual uncommitted change set (check `git status`) and call out any unrelated modified files so they can be excluded. Do not run `git commit` yourself; the user commits manually unless they explicitly ask you to.

## Commands

Run from repo root unless noted. Package manager is **pnpm** (`packageManager: pnpm@9.15.9`).

### Install / dev
```bash
pnpm install # root only
pnpm install:all # root + frontend + website + backend + mobile + contracts/ethereum
pnpm dev:fe # frontend only
pnpm dev:be # backend only
pnpm dev:mobile # mobile only
pnpm dev:web # website only
pnpm eth:node # local Hardhat network
pnpm eth:deploy # deploy contracts to it
pnpm sol:docker # start Solana validator (docker-compose)
pnpm sol:inject-ngrok # tunnel local Solana RPC for mobile/device testing
pnpm fe:eth:local # HH node + deploy + VRF watcher + backend + frontend, concurrently
pnpm mobile:eth:local # same, with mobile instead of frontend
pnpm fe:sol:local # backend + frontend + Solana docker/ngrok, concurrently
```
> `pnpm eth:deploy` and `pnpm eth:vrf:watch` currently reference `deploy:inject` and `vrf:watch` scripts that **no longer exist** in `contracts/ethereum/package.json` (that package was refactored to `scripts/deploy.ts` plus Hardhat Ignition). If these fail, deploy directly with `pnpm --prefix contracts/ethereum deploy` (or `deploy:sepolia` / `deploy:base-sepolia`) instead of chasing the root wrapper script. `DEVELOPMENT.md` and `contracts/ethereum/README.md` also document a few commands (`pnpm dev`, `pnpm clean`, `pnpm vrf:watch`) that don't exist in the current root/package scripts, so treat those docs as partially stale and trust `package.json` scripts blocks over prose.

### Lint / test / build (root aggregates)
```bash
pnpm lint # frontend lint:check + @shared/core lint + website lint + mobile lint
pnpm lint:fix
pnpm test # equals contracts/ethereum test (Hardhat/Mocha), NOT a full monorepo test run
pnpm build # compile contracts + build backend + frontend + website
```
**`pnpm lint` and `pnpm test` do not cover every package.** `backend` has no lint script at all, and neither `backend` nor `contracts/ethereum` are in the root `lint` aggregate. Run per-package commands below when touching those.

### Per-package commands
| Package | lint | test | build | single test |
|---|---|---|---|---|
| `frontend` | `pnpm --filter frontend lint:check` (`eslint . --max-warnings 0` + CSS naming check) | `pnpm --filter frontend test` (vitest) | `pnpm --filter frontend build` (`tsc -b && vite build`) | `pnpm --filter frontend exec vitest run <path>` or `-t "<name>"` |
| `backend` | *(none)* | `pnpm --filter backend test` (vitest) | `pnpm --filter backend build` (`prisma generate && tsc`) | `pnpm --filter backend exec vitest run <path>` |
| `shared` (`@shared/core`) | `pnpm --filter @shared/core lint` | `pnpm --filter @shared/core test` (vitest) | *(none, consumed as raw TS)* | same vitest pattern |
| `mobile` | `pnpm --filter mobile lint` | `pnpm --filter mobile test` (jest) | *(none, RN, use `android`/`ios` scripts)* | `pnpm --filter mobile exec jest <path>` or `-t "<name>"` |
| `website` | `pnpm --filter website lint` (`next lint`) | *(no test script)* | `pnpm --filter website build` | n/a |
| `contracts/ethereum` | *(none)* | `pnpm --prefix contracts/ethereum test` (`pnpm hh test`) | `pnpm compile` (`pnpm hh compile --force`) | `pnpm --prefix contracts/ethereum hh test test/<File>.test.ts` |
| `contracts/solana/cryptopets` | n/a | Anchor test suite (see package README) | `anchor build` | n/a |
| `indexer-go` | `go vet ./...` | `go test ./...` (unit only; Postgres tests are gated on `TEST_DATABASE_URL` and **truncate tables**, scratch DB only) | `go build -o bin/indexer ./cmd/indexer` | `go test ./internal/combat -run TestName` |

`*_test:coverage` scripts exist for frontend/backend/shared (`vitest run --coverage`); CI runs these in `.github/workflows/coverage.yml` and posts a combined PR comment. Coverage requires `@vitest/coverage-v8` to match the installed `vitest` major version, or coverage collection breaks repo-wide.

## Architecture

### Component map
| Component | Stack | Role |
|---|---|---|
| `frontend` | React 19, Vite, Wagmi, Viem, TanStack Query | Web app, wallet integration |
| `backend` | Node.js, Express, TypeScript, Prisma, JWT | REST + GraphQL + gRPC API server |
| `mobile` | React Native | Cross-platform client |
| `website` | Next.js | Marketing/docs site |
| `indexer-go` | Go | Optional cross-chain indexer (EVM pull + Solana push) |
| `contracts/ethereum` | Solidity, Hardhat | EVM contracts + subgraph |
| `contracts/solana/cryptopets` | Rust, Anchor | Solana programs |
| `shared` (`@shared/core`) | TypeScript | Common utils/types/hooks, consumed as raw TS (no build step), shared by frontend + mobile |
| `proto` | Protobuf/Buf | gRPC contract (`GameDataService`) between `indexer-go` and `backend` |

### Data flow
On-chain events (EVM via subgraph watermark polling, Solana via WebSocket push + backfill) are mirrored into Prisma-owned Postgres (`pet_roster`, `battle_history`) by **two parallel indexers**: the backend's built-in Node `RosterIndexer`, and the optional Go `indexer-go`. The Node indexer is the source of truth in local dev; `indexer-go` is promotable later and can additionally stream settled battles straight to the backend over gRPC (`StreamLiveBattles`, defined in `proto/cryptopets.proto`). If `indexer-go` is down, the backend circuit-breaks back to reading Postgres directly (`ROSTER_READ_SOURCE` env var controls `grpc` vs `postgres`). Frontend, mobile, and website all talk to the backend via REST + GraphQL; none of them read chain state directly. See `docs/architecture.md`, `backend/API.md`, `indexer-go/README.md`.

Note: `docs/README.md` and `docs/architecture.md` link to `indexer-go/ARCHITECTURE.md`, which doesn't exist. The real doc is `indexer-go/README.md`.

### No shared cross-chain interface: logic is duplicated per chain, deliberately
There is **no** shared TypeScript abstraction that both chains implement. `frontend/src/chains/ethereum/` (wagmi + in-tree ABI JSONs: `combatSimAbi.json`, `gameConfigAbi.json`, `gameLogicAbi.json`, `petCoreAbi.json`) and `frontend/src/chains/solana/` (Anchor wallet/provider/signer) sit side by side and are wired independently. Don't assume a generic `ChainAdapter`-style interface exists in `shared/`; check the concrete chain directory instead.

### Combat simulator is ported three times: golden vectors keep them in sync
The battle/combat logic is implemented independently in `contracts/ethereum/src/CombatSim.sol`, Solana's `combat.rs`, and pure Go in `indexer-go/internal/combat/`. All three are validated against the same golden test vectors at `contracts/test-vectors/{battle,xp}.json`, run by Hardhat, Anchor, and `combat_golden_test.go` respectively. Hashing uses **legacy Keccak-256** (`keccak256(abi.encodePacked(...))` byte layout); a SHA3-vs-Keccak mismatch fails every vector.
**If a golden vector test fails, the Go (or Rust) implementation has drifted from the Solidity contract. Fix the drifted port, never edit the vector.**

### VRF / randomness
- EVM breeding uses Chainlink VRF v2.5 (async commit, coordinator fulfills). Locally this needs a VRF watcher process (`vrf-fulfill-watcher.ts` used to provide this; see the stale-script note in Commands above). `pnpm fe:eth:local` was designed to run it automatically.
- Solana breeding uses Switchboard On-Demand (commit then settle), also async.
- EVM in-battle randomness (`battle()`/`attack()`) currently uses `Utils.randMod` (keccak of timestamp/sender/nonce). This is a known-predictable v1 weakness, not a hidden bug; see `contracts/plan-contract-upgrade.md` for the v2 redesign (stat-based combat, no more on-chain pseudo-randomness for battles).

### Known v1 contract limitations (design context, not regressions to "fix")
`contracts/plan-contract-upgrade.md` documents intentional v1 gaps that v2 is designed around: no battle authorization (anyone can call `battle()`/`attack()` on anyone's pets), an EVM `changeDna` cheat that lets a level-20 pet set arbitrary DNA, and a Solana `create_starter_pet` that accepts client-supplied dna/rarity. v2 plan: EVM moves to UUPS proxies (`PetCoreProxy` + `GameLogicProxy`, with `CombatSimV1` deployed as a separate contract to stay under the 24KB bytecode ceiling); Solana adds versioned/reserved-space accounts and migrates pets to Metaplex Core NFTs. This is a plan doc; check current contract source before assuming any of it is implemented.

### Hardhat specifics worth knowing
- Contract sources live in `contracts/ethereum/src/` (not `contracts/`): `PetCore.sol`, `GameLogic.sol`, `GameConfig.sol`, `CombatSim.sol`, `DnaLib.sol`, `TestDeployer.sol`.
- Both compiler profiles (`default` and `production`) are pinned to `viaIR` explicitly. Hardhat Ignition silently drops viaIR/optimizer settings from a flat config, and `CombatSim.sol` hits "stack too deep" without it.
- The `localhost` network hardcodes the 5 standard Hardhat dev private keys; only live networks (Sepolia, Base Sepolia, see `scripts/networks.ts`) read `PRIVATE_KEY` from env.
- Deployment is Hardhat Ignition-based (`ignition/modules/CryptoPetsV2Live.ts`); use `pnpm --prefix contracts/ethereum deploy:status` / `deploy:visualize` to inspect.

### Solana local setup
`contracts/solana/docker-compose.yml` runs two services: `solana-dev` (the validator itself, ports 8899/8900/9900) and an **ngrok tunnel** service exposing the local RPC (needs `NGROK_AUTHTOKEN`, ngrok web UI on 4040). This is how mobile/on-device testing reaches a local validator (`pnpm sol:inject-ngrok`), and it isn't documented in `DEVELOPMENT.md`.

### indexer-go internals
Two chain adapters (Solana WS push, EVM subgraph pull) behind a `ChainIndexer` interface feed a single version-guarded pgx batch writer into Postgres, plus a gRPC push path. Layout: `cmd/indexer` (binary, supports `-scan-once`), `internal/{indexer,evm,solana,store,combat,battlebus,grpcsrv}`, `pb/` (buf-generated). An optional in-memory read cache (`ROSTER_CACHE_ENABLED`) is write-through and version-guarded; it's only coherent while `indexer-go` is the sole writer, so it should stay off during shadow-mode (dual-indexer) operation and only be enabled at promotion.

### Auth
Backend auth is nonce, then wallet-signature, then JWT (`backend/README.md`), guarding a single `/graphql` endpoint; the authenticated wallet becomes the matchmaking `caller` context (`backend/API.md`). Roster/battle reads are read-only projections of what the indexer(s) wrote; the backend no longer decodes contract events itself. `winEstimate` returns `null` (not an error) when unavailable, so treat that as a degraded UI state, not a failure.

### Testing conventions
See `docs/testing.md` for the full per-package suite table. Test work is expected to land on dedicated branches per test type/area (e.g. `test/frontend-modules`), not mixed into feature branches, with coverage reported after each change.

## Licensing

This monorepo has split licensing; see the table in `README.md`. `contracts/ethereum`, `contracts/solana`, `indexer-go`, and `proto` are MIT; everything else (`frontend`, `backend`, `mobile`, `website`, `shared`) is PolyForm Noncommercial 1.0.0 (root `LICENSE`). Match the license of whichever package you're editing when adding new files.
2 changes: 1 addition & 1 deletion frontend/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default tseslint.config(
'import/no-duplicates': 'error',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-empty-object-type': 'off',
'react-refresh/only-export-components': 'off',
'prefer-const': 'error',
Expand Down
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"prebuild": "node ./scripts/ensure-workspace-link.mjs",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint:check": "eslint . --max-warnings 0",
"lint:check": "eslint . --max-warnings 0 && node ./scripts/check-css-naming.mjs",
"lint:css": "node ./scripts/check-css-naming.mjs",
"format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx,css}\"",
"preview": "pnpm vite preview",
Expand Down
Loading
Loading