Skip to content

About

Friendly prediction markets for the Microsoft developer ecosystem. Play tokens, no real money. .NET 9 + React 18 + Bicep.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

12 Commits

Folders and files

Repository files navigation

WillItShip

Friendly prediction markets for the Microsoft developer ecosystem. Bet shipcoins (play tokens) on conference announcements, product renamings, GA dates, and ship slips. No real money. No KYC. No Glücksspielgesetz exposure. Settle stakes in person, with coffee.

WillItShip — home


At a glance

  • One-shot, full-stack build. .NET 9 Minimal API + React 18 SPA + Azure infra, all in this repo.
  • LMSR-priced markets with sub-second live updates over Server-Sent Events.
  • Binary and categorical (2–8 outcome) markets share the exact same math path.
  • AI assistant drafts well-formed market suggestions and falsifiable resolution criteria via Azure OpenAI (gpt-4o-mini).
  • Disputes with 72h voting windows for the cases where the creator can't or won't resolve.
  • Mobile-first dark UI, designed for a 390-px viewport.
  • Production-shaped: optimistic concurrency on trades, RFC 7807 errors, structured Serilog → App Insights, RBAC, managed identity end-to-end.

What it looks like

Markets list Portfolio
Filterable market browser with LMSR-driven prices. Portfolio with realised + unrealised P&L.
Market detail Leaderboard
Live price chart, trade panel with slippage protection. Top players by realised + unrealised P&L.
New market Admin
Create a market with AI-suggested ideas + draft criteria. Audit log of admin force-resolve / balance / role actions.

Mobile:

Mobile home Mobile market


Architecture

┌────────────────────┐      HTTPS       ┌──────────────────────┐
│  React SPA (Vite)  │ ───────────────► │  .NET 9 Minimal API  │
│  Azure Static Web  │ ◄────── SSE ──── │  Azure App Service   │
│  Apps (West EU)    │                  │  (West EU, B1 Linux) │
└────────────────────┘                  └──────────┬───────────┘
                                                   │
                       ┌──────────────┬────────────┼──────────────┐
                       │              │            │              │
                ┌──────▼─────┐  ┌─────▼─────┐ ┌────▼────┐  ┌──────▼─────┐
                │ Azure SQL  │  │ Azure     │ │ App     │  │ Key Vault  │
                │ DB Basic   │  │ OpenAI    │ │ Insights │  │ + ACS Mail │
                └────────────┘  │ gpt-4o-   │ └─────────┘  └────────────┘
                                │ mini      │
                                └───────────┘
  • Backend (api/): three projects — BetPoint.Domain (pure math + entity models), BetPoint.Infrastructure (EF Core + AES-GCM crypto), BetPoint.Api (Minimal API + Microsoft.Identity.Web + Swashbuckle + Serilog + native SSE + background jobs).
  • Frontend (web/): React 18 + Vite + Tailwind + react-query + zustand-ready + MSAL React + @microsoft/fetch-event-source.
  • Infra (infra/): Bicep + Azure Verified Modules.
  • CI (.github/workflows/): two pipelines, OIDC federated credentials, no client secrets in repo.

The full design lives in docs/plan.md. Contributor rules and the bd-beads workflow live in CLAUDE.md.


Quickstart (dev mode, no Azure tenant required)

Prereqs: .NET 9 SDK, Node 20+, Python 3.10+ (for the LMSR reference notebook only).

# 1. Backend — builds Domain, Infrastructure, Api; runs migrations on first startup.
cd api
dotnet test BetPoint.sln                  # 107 tests should pass
dotnet run --project src/BetPoint.Api     # http://localhost:5080

# 2. Frontend — Vite + Tailwind + react-query
cd ../web
npm install
npm run dev                                # http://localhost:5173

# 3. Open http://localhost:5173 — DevAuth gives you a synthetic admin user
#    seeded with 1000 shipcoins.

Dev mode runs without MSAL — the SPA submits requests without bearer tokens, and the API authenticates them via the DevAuth policy scheme. To switch to real AAD auth, fill web/.env with your app registration ids, set VITE_DEV_AUTH=false, and set DevAuth:Enabled=false in api/src/BetPoint.Api/appsettings.json. The Production safety guard in Program.cs refuses to start if either DevAuth is on or the AzureAd ids are still placeholders.

Useful commands

# Run the LMSR Python reference (cross-validates the .NET math)
python3 docs/lmsr_reference.py

# Regenerate the OpenAPI TS types after the API contract changes
cd web && npx openapi-typescript ./openapi.json -o src/lib/api/schema.ts

# Capture fresh screenshots for the README (both servers must be running)
cd web && node scripts/screenshots.mjs

# Find available beads work and claim one
bd ready
bd update WillItShip-<id> --claim

Tests

dotnet test                          # 107 tests across Domain/Infra/Api projects

Breakdown:

  • BetPoint.Domain.Tests — 84 tests, including:
    • LMSR property tests: uniform prices for N=2/3/4/8, sum-to-one on asymmetric books, large-q stability (10000-shares without overflow), path independence, round-trip net-zero, max loss values, default liquidity.
    • LMSR cross-validation: 19 canonical values matched 1e-10 against docs/lmsr_reference.py (independent Python implementation, per plan §5).
    • Trade rules: no-shorting, slippage cap, non-finite input rejection.
  • BetPoint.Infrastructure.Tests — 10 tests: encryptor round-trip (dev fallback + configured key), tampered-payload rejection, fail-fast on non-Development without configured key, DbContext seed and Markets row-version rotation, composite-key uniqueness on Position, optimistic concurrency conflict.
  • BetPoint.Api.Tests — 12 tests with WebApplicationFactory: full trade lifecycle (cost matches Python reference), slippage 409, no-shorting 400, insufficient-balance 400, Invalid resolve refunds + zeroes positions, comment sanitisation strips <script> while keeping **bold**, AI suggest returns ≥ 3, AI quota 429, categories seed, and the load-bearing stale-RowVersion 409 concurrency test.

API surface

30 endpoints, base path /api. Bearer required except /api/health* and /api/categories. JSON throughout; errors follow RFC 7807. Full machine-readable spec at web/openapi.json.

auth        POST /api/auth/me
users       GET  /api/users/me  PATCH /api/users/me
            GET  /api/users/leaderboard  GET /api/users/{id}
markets     GET  /api/markets        POST /api/markets
            GET  /api/markets/{id}   PATCH /api/markets/{id}  DELETE /api/markets/{id}
            GET  /api/markets/{id}/trades  GET /api/markets/{id}/prices
            POST /api/markets/{id}/trade           # LMSR-priced, RowVersion-guarded
comments    GET  /api/markets/{id}/comments  POST /api/markets/{id}/comments
            PATCH/DELETE /api/markets/{id}/comments/{commentId}
resolve     POST /api/markets/{id}/resolve         # creator or admin
dispute     POST /api/markets/{id}/dispute         POST /api/markets/{id}/dispute/vote
            GET  /api/markets/{id}/dispute
me          GET  /api/me/portfolio   GET /api/me/trades
            GET  /api/me/notifications  POST /api/me/notifications/read
            GET  /api/me/activity
public ref  GET  /api/categories     GET /api/activity
ai          POST /api/ai/suggest-markets  POST /api/ai/draft-resolution-criteria
admin       POST /api/admin/markets/{id}/force-resolve
            POST /api/admin/users/{id}/adjust-balance
            POST /api/admin/users/{id}/toggle-admin
            GET  /api/admin/audit
sse         GET  /api/sse/markets/{id}             # text/event-stream
health      GET  /api/health  GET /api/health/ready

Realtime event names: connected, price-updated, trade-executed, market-resolved, market-disputed, comment-added.


Deploying to Azure

See infra/README.md for the step-by-step deployment guide. In short:

  1. Create an Entra ID app registration for the API (Single-page application redirect URIs for https://<swa-url> and http://localhost:5173, exposed scope api://<api-app-id>/access_as_user, signInAudience AzureADandPersonalMicrosoftAccount).
  2. az login, then az deployment group create --resource-group rg-willitship-prod-weu --template-file infra/main.bicep --parameters infra/parameters.prod.bicepparam (target time: under 15 minutes from scratch).
  3. Configure GitHub Actions OIDC federated credentials against the deployment principal.
  4. Fill the App Service settings with the real client id and the Production Encryption key (Encryption:LocalKey, base64 32 bytes).
  5. Push to main. The two workflows under .github/workflows/ (api.yml, web.yml) deploy the API and the SPA via OIDC.

Cost ballpark: about EUR 35–55/month for B1 App Service Plan + SQL Basic + SWA Standard + Log Analytics + a light OpenAI deployment. Optimised for a private friends-of-friends use case, not for a public product.


Status

  • ✅ Backend complete, 30 endpoints, 107 tests pass.
  • ✅ SPA complete, 11 pages, live SSE, dark default, mobile-friendly.
  • ✅ AI integration with dev-mode FakeAiClient + production Azure OpenAI client.
  • ✅ Background jobs: auto-close, market-closing notifications, stale-resolution auto-dispute, dispute tally.
  • ⚙️ Bicep + GitHub Actions: skeletons land in this build; final hardening + first end-to-end Azure deploy tracked as beads.
  • ⚙️ Open follow-ups visible via bd list --status=open (deferred architect/security findings are P2/P3 polish).

Run bd stats for the live counts.


Contributing

Read CLAUDE.md first. It encodes 12 non-negotiable invariants from the plan: LMSR as the gate, server-as-source-of-truth, slippage protection, optimistic concurrency, SSE-only on market detail, no-shorting, server-side markdown sanitisation, OpenAPI as contract, no em dashes in user-facing strings, encrypted Teams webhooks, AI budget caps. Tracking lives in bd — do not use TodoWrite/TaskCreate/markdown TODOs.


Out of scope (do not build, even if asked)

Real money. Order-book trading. Native mobile apps. M365 Copilot agent / Teams app (incoming webhook only). Multi-region, geo-redundancy. Localisation (English only). Public marketing.


Working name: WillItShip. Code namespace: BetPoint.* (Domain, Infrastructure, Api). Token: shipcoins, behind a single constant. Primary colour: violet/indigo (Tailwind ship-*).

About

Friendly prediction markets for the Microsoft developer ecosystem. Play tokens, no real money. .NET 9 + React 18 + Bicep.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages