with one click
repository-cache-keeper
// Maintain Repository classes — REST endpoints, route vars, cache coherence, typed collections, and persistence boundaries. Use when changing repository CRUD, cache behavior, or endpoint bindings.
// Maintain Repository classes — REST endpoints, route vars, cache coherence, typed collections, and persistence boundaries. Use when changing repository CRUD, cache behavior, or endpoint bindings.
| name | repository-cache-keeper |
| description | Maintain Repository classes — REST endpoints, route vars, cache coherence, typed collections, and persistence boundaries. Use when changing repository CRUD, cache behavior, or endpoint bindings. |
Use this skill when work touches src/Discord/Repository/**/*.
This is cache-and-REST boundary skill. Load it when a change affects how parts are collected, fetched, persisted, cached, or routed to endpoints.
Keep repositories as:
Not as service dumping ground.
src/Discord/Repository/AbstractRepository.phpsrc/Discord/Repository/AbstractRepositoryTrait.phpsrc/Discord/Parts/PartTrait.php sections for getRepositoryAttributes(), getCreatableAttributes(), getUpdatableAttributes()src/Discord/Helpers/CacheWrapper.php and cache config code if cache behavior matterssrc/Discord/Repository/GuildRepository.phpsrc/Discord/Repository/Guild/ChannelRepository.phpsrc/Discord/Repository/Channel/MessageRepository.phpsrc/Discord/Repository/Interaction/GlobalCommandRepository.phpsrc/Discord/Repository/Guild/GuildCommandRepository.phpEvery repository centers on same shape:
AbstractRepository$class to the concrete part family$endpoints$discrim$vars route context from parent part or callerIf a method no longer feels like typed collection + route-aware persistence, it probably belongs elsewhere.
$classConcrete part family allowed in this repository. If wrong, hydration, type checks, and cache writes all become unsafe.
$endpointsRoute templates keyed by operation name. Typical keys:
allgetcreateupdatedeleteNot every repository supports every operation. Missing endpoint is an intentional capability statement.
$varsRoute-binding context. This is how nested repos know where they live:
guild_idchannel_idapplication_id, message_id, or other parent route piecesWhen repo behavior looks wrong, inspect parent part getRepositoryAttributes() first.
$discrimCollection key field, usually id. Only change when payload family genuinely keys on a different field.
$cachePer-repository cache wrapper. It is not optional frosting. Repo methods should keep it coherent with in-memory items.
create(array|object $attributes = [], bool $created = false)Builds local typed part using repository context plus attributes. No REST call. No remote persistence. Use it for drafts or hydration helpers.
save(Part $part, ?string $reason = null)Generic persistence path:
$part->created is false$part->created is truePart-level save() may wrap or redirect this when semantics demand it.
delete($part, ?string $reason = null)Remote delete plus cache removal. Accepts part or identifier. Keep typed return contract.
fetch(string $id, bool $fresh = false)Resolve from memory, then cache, then REST unless forced fresh. This is one of main async entry points. Keep it Promise-based.
fresh(Part $part, array $queryparams = [])Refresh a known created part from REST and update cache.
freshen(array $queryparams = [])Bulk refresh repository contents from REST. This is repo-wide sync tool, not a one-item fetch.
Repositories are hybrid objects:
get(), find(), first(), last()cacheGet(), cachePull(), fetch(), freshen()That dual nature is intentional. Do not flatten repository into only async map or only plain collection.
items can hold real parts, WeakReference, or null placeholdersEndpoint and bound varsRepository methods should bind route vars through Endpoint/Endpoint::bind(), not manual string interpolation spread across code.
If child repository starts losing route info, fix parent part getRepositoryAttributes() or repo constructor normalization, not random callers.
If a repo needs to clean or enrich vars for route correctness, constructor override is fine. Example patterns already exist:
MessageRepository unsets thread_id for thread message routingGuildCommandRepository injects bot application idAdd repo-specific methods when operation is broader than generic CRUD and naturally belongs to collection/route boundary.
Good examples:
GuildRepositoryGuildRepositoryChannelRepositoryBad examples:
$part->save() or $part->someAction()If code needs to know "is this current member or generic member", "is this webhook message or normal message", or "does bot need manage_messages here", that usually belongs on part side first.
$class$endpoints$discrimgetRepositoryAttributes()@method helpers if family uses themSome repos are intentionally small:
GlobalCommandRepositoryMessageRepositoryThat is okay. Not every repo needs custom methods.
If nested route shape is tricky, normalize vars in constructor instead of forcing every caller to know internals.
Methods like fetch() and get() preserve performance by preferring in-memory/cache before REST. Keep that bias unless correctness requires bypass.
Repositories are often updated from gateway events, not only from their own REST methods. When changing repository keying or cache semantics, inspect matching event handlers. If repository expectations change but event cache writes do not, the repo will look "randomly stale".
Common families to cross-check:
Stop if you see:
save()items updated but cache wrapper ignored, or reverse$class, $endpoints, $discrim, $vars still describe repo correctlygetRepositoryAttributes() still supplies needed route varsRepository code in this repo should feel boring in right way: typed, route-aware, cache-coherent, and predictable. If a repository starts making domain decisions or returning untyped transport data, pull it back to its real job.
Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow. Use when adding tests, updating docs, or changing public behavior.
Maintain Builder classes — outbound payload construction, validation, serialization, component handling, and fromPart symmetry. Use when changing Builders or outbound Discord API payloads.
Maintain gateway event handlers — payload hydration, cache mutation, event return shapes, and handler registration. Use when touching WebSockets/Events, Handlers.php, or Event.php.
Work with DiscordPHP's infrastructure utilities — CacheWrapper, CacheConfig, BigInt, Multipart, Endpoint::bind URL templates, Collection base class, and domain Exceptions. Use when changing cache behavior, REST endpoint routing, file uploads, big-integer ID math, or adding/modifying exceptions.
Maintain interaction flow — Interaction typing, resolved data caching, command routing, autocomplete, modal responses, and interaction builders. Use when touching Interactions or slash command handling.
Maintain the optional prefix-command layer — DiscordCommandClient, Command class, parsing, aliases, cooldowns, and help system. Use when touching message-based command handling.