Commit Graph

9 Commits

Author SHA1 Message Date
funman300 a034e74c16 style(core): apply cargo fmt across routes, services, models, tests
CI / Build, lint & test (push) Successful in 2m19s
Pure rustfmt reflow (import grouping, array/match-arm/call-arg wrapping,
alphabetized module decls, comment realignment). No semantic change:
full-diff and `git diff -w` both confirm logic byte-identical to 271c363;
workspace builds and all 74 core tests pass. Retained pre-existing WIP
brought forward after verification.
2026-08-20 16:05:41 +00:00
funman300 637a21eac1 fix(economy): quick-selling a squadded card failed with a FOREIGN KEY error
Found while implementing sale settlement, and reproduced before fixing:

  sell_item(pool, "club", "item-x", 250)
    -> Database(SqliteError { code: 787, message: "FOREIGN KEY constraint failed" })

squad_players.owned_card_id is a FK onto owned_cards(id) and db.rs enables
foreign_keys, so DELETEing an item that sits in any lineup is refused outright.
services::economy::sell_item never cleared the lineup, and this is the LIVE FIFA 17
quick-sell path (host economy_store -> econ.sell_item -> POST /economy/sell-item).
Selling a card that happens to be in your squad is ordinary, not an edge case.

sell_item now evicts the item from every lineup first, inside its existing
transaction, so a wrong-owner sale rolls the eviction back with everything else
(asserted, not assumed).

Also folds routes/cards.rs::delete_owned_card into the same authority. It
hand-rolled DELETE + club::add_coins directly on the pool, which had BOTH defects:
no transaction, so a failed credit destroyed the card for nothing, and the same
missing squad eviction. Its response shape is unchanged and the pre-existing route
test still passes.

Tests: selling_a_squadded_item_succeeds_and_frees_the_slot (the repro) and
a_rejected_quick_sell_leaves_the_lineup_intact. Core 55 lib + 123 integration pass,
clippy clean.

Not deployed — production is mid live-test.
2026-08-18 01:01:13 +00:00
funman300 6acae54f80 feat(club): semantic owned-item query + FIFA17 filter/pagination fix
Game-independent owned-inventory query (services::inventory::{OwnedItemQuery,
apply_query} + a Quality tier) that filters (AND) -> orders deterministically
(effective_overall desc, owned_card_id asc) -> paginates, wired into
GET /collection. Fixes the FIFA17 My Squad search: the Python oracle applied
only league+team and ignored level/rare/position/nation/start/count (proven by
response sha256 identity across pages -> the request-amplification bug); Core
now applies all proven filters and paginates. rare=SP left UNKNOWN.

Tests: +9 inventory unit, +14 /collection integration (full matrix incl. the
repeated-first-page regression); 9 mutations killed.

Isolated from an unrelated dirty working tree via a clean worktree at eab522a;
touches only the 5 slice files, no unrelated reformatting.
2026-08-11 21:38:16 +00:00
funman300 8c8a4116bf wip: checkpoint multi-game core work 2026-08-07 12:03:21 -07:00
funman300 19c7b9989d Phase 10: card upgrade system (chemistry styles, position change, training)
CI / Build, lint & test (push) Failing after 1m37s
- GET /chemistry-styles — lists 18 FUT-style chemistry styles with stat boost breakdowns
- POST /collection/:id/chemistry-style — apply a style (Shadow, Hunter, Anchor, etc.)
- POST /collection/:id/position — override a player's position for 500 coins
- POST /collection/:id/training — add +1/+2/+3 OVR training bonus (max +3 total)
- GET /collection now includes chemistry_style, position_override, training_bonus,
  effective_overall and effective_position fields per owned card
- Migration 0007 adds three columns to owned_cards with safe defaults
- 10 new integration tests — all 55 pass, clippy clean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 17:02:44 -07:00
funman300 bfd6de6896 Phase 8 (Core): stateful draft, quick-sell, objectives by ID, market listings
CI / Build, lint & test (push) Failing after 1m21s
Draft v2 — stateful FUT-style pick sessions:
  - POST /draft/start?difficulty=<> — creates session, returns 5
    candidates for GK slot (position order: GK RB CB CB LB CDM CM CAM RW ST LW)
  - POST /draft/sessions/:id/pick { card_id } — validates candidate,
    advances to next position; on last pick grants coins+pack reward
    (avg OVR ≥84 → gold pack + 2000 coins, ≥78 → silver + 1000, else 400)
  - GET /draft/sessions/:id — session state with per-pick cards
  - POST /draft/sessions/:id/abandon — cancel without reward
  - Migration 0005_draft_sessions.sql

Quick-sell:
  - DELETE /collection/:owned_card_id — removes card, credits coins based
    on overall (85+ → 1500, 80-84 → 900, 75-79 → 600, 65-74 → 300, <65 → 150)

Objectives:
  - GET /objectives/:id — single objective with progress
  - POST /objectives/:id/claim — claim reward by URL param (complement to
    existing POST /objectives/claim body-param endpoint)

Market:
  - GET /market/my-listings — active listings posted by current club
  - DELETE /market/listings/:id — cancel a listing, returns card to collection

Tests: 9 new integration tests (37 total, all passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:41:55 -07:00
funman300 8fa125cfd6 Phase 7 (Core): chemistry v2, expanded card pool & search filters
CI / Build, lint & test (push) Failing after 1m46s
- Chemistry v2: FUT-style link scoring with per-player breakdown
  (club +3/link cap 6, league +1/link cap 4, nation +1/link cap 3;
   player cap 10, team cap 100); chemistry response now includes
   per-player breakdown with club/league/nation link counts and pts
- Card pool: 34 new cards across Premier League, La Liga, Bundesliga
  with overlapping clubs/nations for meaningful chemistry testing
- Card search: extended GET /cards with nation, league, club,
  min_overall, max_overall, limit query params; results sorted by
  overall descending
- Match opponent: added "ultimate" difficulty band (85+ OVR);
  random formation selection from 6 tactical formations; falls back
  to lower OVR pool when not enough cards at the requested band
- Tests: 9 new integration tests (28 total, all passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:31:56 -07:00
funman300 34bce2ce75 feat: Phase 1 — core game loop complete
New endpoints:
- GET  /cards/:card_id       single card lookup
- POST /packs/buy            purchase pack with coins
- POST /objectives/claim     claim completed objective reward
- GET  /matches              match history (limit/mode query params)
- GET  /sbc/:sbc_id          single SBC lookup

Card pool expanded:
- Bronze: 11 → 30 cards (19 nations)
- Silver: 0 → 20 cards (20 nations)
- Rare Gold: 0 → 10 cards (10 nations)

SBC pool expanded:
- Added 5 new SBCs (tri_nations, silver_to_gold, league_loyalty,
  african_stars, gold_standard)

Infrastructure:
- SQLite WAL mode enabled on pool init
- Foreign key enforcement enabled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 15:25:30 -07:00
funman300 1ffe0ffa9f Initial commit: OpenFUT Core
Offline Ultimate Team backend — game-independent REST API.

- 19 API endpoints: auth, profiles, clubs, cards, packs, squads,
  objectives, SBCs, match rewards, NPC market, statistics
- Axum + SQLite + SQLx with full migrations
- Weighted pack generator, SBC validation engine
- JSON-driven mod data (cards, packs, objectives, SBCs)
- 5 integration tests passing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 14:54:51 -07:00