mirror of
https://github.com/sebastiandine/Card-Collection-Manager-3.git
synced 2026-08-28 17:01:02 +00:00
55ace147bc
* initial development * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * pipeline * ci/cd * ci/cd * ci/cd * ci/cd * ci/cd * ci/cd * ci/cd * pokemon * pokemon * pokemon * pokemon * pokemon * pokemon * improvements * improvements * ci/cd * ci/cd * improvements * improvements * improvements * improvements * improvements * improvements * improvements * improvements * improvements --------- Co-authored-by: sdine <sdine@sdine.com>
6.6 KiB
6.6 KiB
core/AGENTS.md
ccm_core static library — domain types, ports, services, infra adapters. Hard rule: no UI dependencies, ever. Read the root AGENTS.md first.
Layer pointers
include/ccm/domain/— POD value types:Enums,Set,MagicCard,PokemonCard,Configuration. Each hasto_json/from_jsondefined in the matchingsrc/domain/*.cpp.include/ccm/ports/— interfaces (IHttpClient,IFileSystem,ICollectionRepository<T>,ISetRepository,IImageStore,ICardPreviewSource). All seams the services depend on. Add new ports here when adding new external concerns.include/ccm/services/— high-level operations:ConfigService,CollectionService<TCard>(header-only template),SetService,ImageService,CardPreviewService,CardSorter(free functions; per-column sort comparators that mirror established table sorting behavior — UI-agnostic so they can be unit-tested directly),CardFilter(free functions; case-insensitive substring row matcher restricted to each game'stableFieldsvalueKey list). They depend only on ports.include/ccm/infra/— concrete adapters:CprHttpClient,StdFileSystem,JsonCollectionRepository<T>(header-only template),JsonSetRepository,LocalImageStore.include/ccm/games/—IGameModule+ per-game modules.IGameModuleconsolidates the per-game seams: every module owns anISetSource(required) and may own anICardPreviewSource(optional, defaultnullptr).magic/andpokemon/are the reference implementations — both expose a fully working set source + card preview source.include/ccm/util/—Result.hpp(the sum type),FsNames.hpp(filename munging ported fromutil/fs.rs).src/mirrorsinclude/ccm/for non-template implementations.
Conventions
- No throw across ports. Return
ccm::Result<T>::ok(...)/Result<T>::err("msg"). The caller propagates withif (!r) return Result<T>::err(r.error());. - JSON serde stays byte-for-byte stable. When the C++ field name differs from the JSON key (
signed_vs"signed",releaseDate,setNo,firstEdition,dataStorage,defaultGame), write hand-rolledto_json/from_jsoninstead ofNLOHMANN_DEFINE_TYPE_NON_INTRUSIVEso the alias is explicit. Round-trip tests intests/domain_json_tests.cppenforce this — extend them whenever you touch a domain type. - Filename rule for images lives in
services/ImageService.hppand matches the Rust source exactly:- new entry ->
"{set}+{name}+{idx}.{ext}" - existing ->
"{id}+{set}+{name}+{idx}.{ext}"
ImageService::buildTargetNameis the single source of truth. Don't duplicate the rule elsewhere.
- new entry ->
- Templates stay header-only (
CollectionService<T>,JsonCollectionRepository<T>). Don't add.cppfiles for them; explicit instantiation is not used. - Path strings that get persisted (e.g.
Configuration::dataStorage) usestd::filesystem::path::generic_string(), neverstring()— keeps/separators on Windows so JSON round-trips and tests stay portable. - Compiler warnings: every target in this package links
ccm_warningsPRIVATE. Treat warnings as errors locally during dev (-Werroris opt-in but encouraged). - No
wx/...includes in headers or sources here. Verify withrg "wx/" core/— must be empty. - HTTP query strings must be percent-encoded before they reach
IHttpClient::get.cpr::Urldoes not encode the URL string we hand it. SeeMagicCardPreviewSource::buildSearchUrlfor the canonical pattern (RFC 3986 unreserved-set encoder).IHttpClient::getaccepts arbitrary bytes back —Result<std::string>is a binary buffer, not text, so callers can use it for image payloads directly.
Adding a new game
The end-to-end procedure (core + UI + composition root + docs) lives in docs/adding-a-new-game.md. The core-side checklist is:
- Add
Game::<Name>plusto_string/<Name>FromString/allGames()entries ininclude/ccm/domain/Enums.hppandsrc/domain/Enums.cpp. - Create
include/ccm/games/<name>/<Name>SetSource.hpp+.cppimplementingISetSource. MirrorMagicSetSource/PokemonSetSource: expose a staticparseResponse(std::string)helper so it's unit-testable without HTTP. - (Optional) Create
include/ccm/games/<name>/<Name>CardPreviewSource.hpp+.cppimplementingICardPreviewSource. MirrorMagicCardPreviewSource/PokemonCardPreviewSource: expose staticbuildSearchUrl+parseResponsehelpers for unit testing without HTTP. - Create
include/ccm/games/<name>/<Name>GameModule.hpp+.cppimplementingIGameModule. Pick a stable lowercasedirName()— it becomes the on-disk subdirectory and must never change. The module owns its set source and (optionally) its card preview source: overridecardPreviewSource()to return&previewSource_when present (default returnsnullptr). - If the game has a card type with different fields, add a
<Name>Carddomain type with hand-rolled JSON aliases. Otherwise reuse an existing one. - Add the new
.cppfiles tocore/CMakeLists.txt(no glob). - Add tests under
tests/<name>_set_source_tests.cppandtests/<name>_card_preview_source_tests.cppmodeled on the Magic / Pokemon versions. - The composition root in
app/main.cppand the directory mapping inapp/main.cpp::dirNameForGamemust be updated too — seeapp/AGENTS.md.CardPreviewService::registerModule(*module)is the single registration call; modules whosecardPreviewSource()returnsnullptrare silently skipped.
Adding / changing a card-table column
When you add or rename a tableFields entry on a list panel (Magic or Pokemon), keep core/'s sort/filter helpers and their tests in lockstep:
- Extend
MagicSortColumn/PokemonSortColumnand add acasebranch insortMagicCards/sortPokemonCards(core/include/ccm/services/CardSorter.hpp+.cpp). - Add the new value-key column to the matching
matchesMagicFilter/matchesPokemonFilter(core/include/ccm/services/CardFilter.hpp+.cpp) — boolean-flag columns are excluded (the filtering rule only checks values equivalent to JStypeof === "string" | "number"). - Add tests under
tests/card_sorter_tests.cppandtests/card_filter_tests.cpp.
Adding a new port
- Add the interface header under
include/ccm/ports/withvirtual ~IFoo() = default;. - Implement the adapter under
include/ccm/infra/+src/infra/. Mark itfinal. - Update
core/CMakeLists.txt. Wire it into the relevant service's constructor. - Add a fake under
tests/fakes/modeled onInMemoryFileSystemand write service-level tests against it.
Commands
Build core only: cmake --build build --target ccm_core