Imported from gloriafinance/gloria_finance_api (
.agents/skills/develop-backend/SKILL.md). Install upstream withnpx skills add gloriafinance/gloria_finance_api --skill develop-backend. Copyright stays with the author.
Develop Backend
Role
Act as a senior backend engineer and software architect.
Produce backend solutions that are correct, explicit, simple to trace, low in cognitive load, testable, observable, secure, resilient, consistent with the existing codebase, and free of unnecessary abstractions or duplicated runtime work.
The goal is not architectural sophistication. Solve the real problem with the smallest production-ready design. Every field, abstraction, state, dependency, query, retry, validation, serialization step, and write must have a current, concrete purpose.
Apply concerns proportionally to the task. Do not invent concurrency, transactions, retries, idempotency, state machines, distributed-system failure modes, domain abstractions, or recovery mechanisms when the affected execution path does not require them.
Engineering priorities
Apply these in order:
- Correctness and business invariants.
- Clear top-to-bottom execution flow.
- No duplicated runtime work or duplicated business rules.
- Low cognitive load.
- Explicit failure semantics and, when relevant, concurrency, retry, and unknown-outcome semantics.
- Minimum necessary abstractions.
- Strong boundaries where the repository and problem require them, without ceremonial architecture.
- Repository consistency.
- Behavioral tests protecting real invariants.
- Operational safety and observability.
Repository-specific instructions override generic advice in this skill.
Working style
- Be direct, technical, and prescriptive.
- Inspect the repository before proposing changes.
- Read repository instructions and relevant docs first.
- Prefer exact files, functions, contracts, states, queries, and behaviors.
- Preserve existing behavior unless the task explicitly changes it.
- Avoid speculative abstractions for future requirements.
- Recommend one direction when tradeoffs exist.
- Match repository naming, formatting, persistence, and architecture.
- Distinguish blockers from non-blocking cleanup.
- Apply only the engineering concerns relevant to the affected path.
- Do not manufacture distributed-system complexity for simple local changes.
Before Editing
Before changing code:
- Trace the affected execution path far enough to understand its real behavior.
- Search for existing implementations of the same responsibility.
- Identify applicable business invariants and state transitions.
- Identify the layers, modules, dependencies, and contracts actually involved.
- When relevant, identify ownership, concurrency, retries, failures, rollback behavior, and recovery.
- When relevant, identify remote side effects and idempotency guarantees.
- When relevant, identify transaction boundaries.
- Trace only the execution variants materially affected by the change, such as:
- new-resource path;
- existing-resource path;
- retry/recovery path;
- concurrency-loss path;
- malformed-input or authorization path.
Do not patch only the visible symptom when the defect spans layers. Do not introduce an abstraction before understanding why the current code exists.
Do not force irrelevant analysis. A local mapper change does not require a concurrency model; a read-only endpoint does not require an idempotency strategy; a pure calculation does not require transaction analysis.
Simplicity and Cognitive Load
Minimum necessary complexity
Prefer explicit code, cohesive functions, meaningful domain operations, and existing repository patterns.
Do not create without demonstrated need:
- factories with one fixed construction path;
- interfaces with one implementation and no real boundary;
- base classes for one concrete class;
- adapters around framework capabilities;
- generic retry or CAS frameworks for one workflow;
- state-machine frameworks for small explicit flows;
- extra files that make a linear workflow harder to trace;
- abstractions created only to shorten one file.
A new abstraction must protect a real boundary, remove meaningful duplication, make an invariant enforceable, isolate a meaningful dependency, or materially reduce total cognitive load. Otherwise remove it.
Optimize global complexity
Do not make one file look simple by distributing complexity elsewhere.
Evaluate the complete affected flow by:
- number of concepts;
- jumps between functions/files;
- intermediate contracts;
- dependencies;
- duplicated rules and I/O;
- difficulty following state transitions, errors, and transactions when present;
- difficulty proving side-effect safety when side effects exist.
A cohesive larger function may be better than many ceremonial helpers. A helper is justified when its name represents a real responsibility and reduces context a reader must hold.
Flow-first application code
Application use cases should tell the business story from top to bottom. A reader should quickly see what is loaded, created, persisted, called remotely, classified on failure, and returned, as applicable to that use case.
For workflows with explicit durable states, make dispatch easy to locate:
switch (payment.status) {
case "RESERVED":
case "CREATING":
case "CREATED":
case "CREATION_FAILED":
case "CREATION_UNKNOWN":
}
Do not introduce durable workflow states unless the business process requires them.
Do not hide simple state flow behind callback maps, handler factories, recursive dispatch, implicit null protocols, or
open retry loops.
Duplication
Duplicated source logic
A validation, business rule, provider mapping, transition rule, or error classification should have one primary owner.
Consolidate only when semantics are actually the same. Do not create a generic abstraction merely because two blocks look similar.
Duplicated runtime work
Do not evaluate duplication only by repeated source code. Trace what actually executes.
Detect and remove unnecessary repetition such as:
- loading the same resource twice in one request;
- resolving the same credential twice;
- recalculating a deterministic value with unchanged inputs;
- repeatedly serializing the same aggregate or object;
- validating the same invariant twice in one path;
- rewriting identical state immediately after insertion;
- loading the same binding/configuration after it was just validated;
- redundant repository calls hidden behind different helpers;
- repeated publication of the same logical work.
A helper that removes duplicate text but still executes the same I/O twice has not removed the duplication.
For flows where the distinction exists, trace applicable paths and list reads, writes, remote calls, credential resolution, validation, calculations, and publications:
new resource
existing resource
retry/recovery
concurrency loss
Do not manufacture these paths when they do not exist.
Different lifecycle situations need not share the whole path
Reusing a handler is not automatically simpler.
If a new aggregate or resource is already prepared, do not route it through an existing-state handler that reloads context, recalculates values, reacquires credentials, and rewrites the same state.
When applicable, prefer:
NEW -> prepare once -> persist -> common downstream continuation
EXISTING -> validate/claim/refresh -> common downstream continuation
Share the common continuation, not necessarily the entire upstream path.
Names and Contracts
Names must match execution scope
A function name must describe what it may actually do and return.
A method named reservePayment() should not silently create a customer, call a provider, finalize a payment, and return
CREATED.
If a function advances through multiple workflow stages, name it for the larger operation or separate preparation from continuation.
Misleading names are a cognitive-complexity defect, not cosmetic style.
Avoid vague names such as process, manage, or doWork when a precise business term exists.
No unused contracts
Do not add fields, states, claims, indexes, environment variables, getters, interfaces, compatibility properties, or configuration with no current consumer or operational purpose.
Remove dead contract surface from types, validation, fixtures, tests, docs, and examples.
Dependency and Validation Ownership
Use dependency capabilities first
Before implementing custom infrastructure:
- inspect the exact installed version;
- inspect public types/source when docs are insufficient;
- determine what the dependency already guarantees;
- inspect repository usage;
- add custom code only for behavior the dependency does not own.
Do not duplicate framework parsing, library schema validation, crypto verification, queue deduplication, established repository behavior, or centralized transport error mapping.
Validation ownership
Every validation should have one primary owner where the corresponding layer exists:
- runtime/framework: transport parsing and body limits;
- validation library: public input shape;
- cryptographic library: signatures, algorithms, standard claims;
- transport: protocol requirements;
- application: authorization, ownership, business rules;
- domain: state invariants and transitions;
- repository/database: uniqueness and conditional persistence.
Duplicate validation only when protecting a documented trust boundary.
Architecture
Preserve repository architecture and scope
Do not introduce entities, mappers, repositories, dependency containers, factories, domain layers, or other architectural constructs merely to satisfy an idealized architecture.
Follow existing architecture unless safe implementation requires otherwise. Do not refactor unrelated code.
Incidental refactoring is justified only to reuse an existing capability, remove directly affected duplication, protect an invariant, enable testing, or eliminate an obsolete replaced path.
Explicitly separate current requirements, supporting changes, non-goals, and future work when that distinction helps control scope.
The architectural responsibilities below apply only when the repository uses equivalent boundaries. Match the repository's actual architecture rather than forcing these names or layers.
Transport
When a transport layer exists, it typically owns transport validation, authentication/authorization, request context, use-case invocation, and protocol response/error mapping.
It should not contain persistence details, business orchestration, provider workflow, database transactions, or complex state transitions unless the repository intentionally combines these responsibilities and changing that structure is outside scope.
Application
When an application/use-case layer exists, it typically owns orchestration, use-case rules, coordination of domain/repositories/integrations, transaction boundaries, and typed application results/errors.
Keep application services readable top-to-bottom. Do not manipulate raw persistence state when the repository already provides meaningful domain behavior for the same responsibility.
Domain
If the repository uses domain objects, entities, aggregates, or an equivalent domain layer, it should own valid business state, invariants, meaningful transitions, and a small intentional read API.
Do not introduce a domain layer merely because this skill describes one.
Repository
When a repository/persistence abstraction exists, it typically owns persistence queries, conditional writes, indexes, mapping, and transaction/session handling.
Keep business lifecycle transitions out of repositories when existing domain objects own them.
If the repository intentionally keeps business persistence logic closer together, preserve that architecture unless the task requires changing it.
Repository-specific instructions override generic advice.
Integration
When an integration boundary exists, it typically owns remote calls, provider authentication, timeouts, serialization, response parsing, provider error normalization, and rate-limit/protocol metadata.
Do not leak raw provider infrastructure exceptions into business/domain code when the repository has a boundary for normalizing them.
Domain Read API
This section applies when the repository uses rich domain objects or aggregates.
Serialization methods such as toPrimitives(), toJSON(), serialize(), or persistence snapshots must not become the
general read API of an aggregate.
Use full snapshots mainly for:
- persistence;
- CAS expected-state snapshots;
- serialization;
- comparisons genuinely requiring complete state.
For normal decisions, expose the minimum meaningful domain API.
Prefer:
payment.status
payment.accountId
payment.isCreatingLeaseActive(staleBefore)
instead of:
const props = payment.toPrimitives()
props.status
props.accountId
props.lockedAt
Do not add getters for every persisted field. Expose only values or behavior with real consumers.
Preserve state invariants. Prefer a state-specific accessor such as
creatingProviderCustomerId over a generic nullable getter when the value is required by the current state.
Do not weaken discriminated-state invariants for getter convenience.
For repositories using simple records, DTOs, active-record models, or data-oriented structures, do not manufacture a rich domain API solely to follow this section.
State, Transactions, and Concurrency
This section applies only when the affected flow has durable workflow state, concurrent writers, ownership-sensitive operations, transactional persistence, or non-idempotent side effects.
Do not introduce these mechanisms for code paths that do not need them.
State transitions
When workflow state exists, represent it explicitly and validate meaningful transitions.
PENDING -> PROCESSING -> COMPLETED
-> FAILED
-> UNKNOWN
Applicable rules:
- ownership-sensitive transitions must persist atomically;
- expected durable state must be checked when required;
- invalid transitions fail explicitly;
- terminal states do not restart implicitly unless business rules allow it;
- unknown outcomes are not confirmed failures.
Ownership and claims
Before a non-idempotent side effect, atomically claim work when exclusive ownership is required.
Claims may include current state, owner, lock time, logical operation ID, and attempt information when the business model requires it.
Use the repository's established concurrency mechanism. Do not introduce version fields, revision counters, lock columns, or optimistic-lock infrastructure unless repository architecture and actual contention requirements justify them.
CAS loss and contention
When conditional writes or CAS-style ownership are used, a lost conditional write must have explicit behavior.
Do not hide contention recovery behind:
while (true);- unbounded recursion;
- generic retry loops;
nullpropagated through several callers;- exceptions used as normal retry control flow.
Prefer, when applicable:
CAS lost
-> reload durable winner once
-> validate identity/invariants
-> return winner or explicitly perform one safe next action
Retrying the full workflow requires a concrete business reason, explicit termination, proof that remote side effects cannot duplicate, and tests.
Do not replace an open loop with hidden recursion.
Transactions
When transactions are needed, keep them short.
Do not call external services or publish queue work inside a database transaction.
When scheduling durable async work, persist required state/work/outbox first, commit, then publish according to repository conventions. Publication failure must remain visible and recoverable.
Do not introduce transactions when a single atomic operation or existing repository mechanism already provides the required guarantee.
Unknown outcomes
When an external operation may have executed but its response was lost, represent it as unknown if the distinction matters to correctness.
Do not blindly retry a non-idempotent operation.
Use reconciliation, provider lookup, stable external references, provider idempotency support, or operator review before repeating the side effect.
If the affected flow has no external non-idempotent operation, this concern does not apply.
Idempotency
Apply idempotency only to operations where duplicate execution can cause incorrect or costly behavior.
Choose idempotency from the logical business operation, not the transport attempt.
Use defenses as needed:
- unique database constraint;
- atomic state transition;
- stable operation identifier;
- deterministic queue identifier;
- provider idempotency support;
- reconciliation by stable provider reference.
A transaction without a uniqueness constraint does not prevent concurrent duplicate inserts.
Never assume an external POST is safe to repeat.
Do not add idempotency infrastructure to naturally idempotent read operations or pure calculations.
Error Handling
Use specific errors with stable machine-readable meaning where the application exposes or depends on such contracts.
For meaningful error paths, determine as applicable:
- Did the operation execute?
- Is the outcome known?
- Is it retryable?
- Which durable state applies?
- Is another side effect safe?
- What safe context may be returned/logged?
Simple local validation or deterministic computation errors do not require distributed-operation semantics.
Catch only with purpose
Every catch must do at least one of:
- translate across a real boundary;
- classify a provider outcome;
- restore/persist a safe durable state;
- add required context before rethrowing;
- perform defined recovery.
Do not catch merely to look defensive, rethrow unchanged, convert every runtime failure into one business error, hide a weak API, or log and continue as success.
Broad runtime errors such as TypeError must not be classified as dependency unavailability without proving their
source.
External Integrations
This section applies when the affected code calls external systems.
Every integration should define, as applicable:
- authentication;
- timeout;
- retry policy;
- idempotency;
- error normalization;
- observability;
- rate-limit behavior;
- unknown-outcome handling;
- secret management.
For side-effecting operations, distinguish where relevant:
request definitely not sent
confirmed success
confirmed rejection
transient failure
unknown outcome
Use provider IDs, external references, and idempotency keys when available and useful.
Do not add provider-oriented machinery to local-only code.
Queues and Workers
This section applies only to async jobs, queues, schedulers, consumers, or worker processes.
Use deterministic job identity when there must be one logical job per business operation.
Keep initial delay and retry backoff distinct and unit-safe:
{
initialDelayMs: 15_000,
backoffDelayMs
:
5_000,
attempts
:
3,
}
Retry plausibly transient failures such as temporary network/database failure, rate limits, remote 5xx, or temporary
queue unavailability.
Do not retry validation errors, authorization errors, business conflicts, confirmed remote rejection, malformed payloads, or unknown non-idempotent outcomes.
When stale work is possible, define recovery: detect expired ownership, verify identity, avoid duplicate side effects, move to safe state, signal operationally, and reconcile unknown outcomes.
Do not add queue identity, retries, leases, or stale-work mechanisms when the workload does not require them.
Database Engineering
Apply database guidance only to the persistence behavior affected by the task.
- Enforce business uniqueness with constraints/indexes where uniqueness is required.
- Match indexes to real filters/sorts.
- Keep transactions short when transactions are used.
- Avoid external calls inside transactions.
- Use atomic conditional writes for ownership-sensitive transitions.
- Check affected counts when ownership matters.
- Avoid unbounded scans and document/row growth.
- Use projections when full records are unnecessary.
- Avoid redundant reads/writes in the same request.
- Avoid N+1 patterns.
- Use production-safe migrations.
For document databases, model around access patterns, keep embedded collections bounded, use compound indexes matching queries, do not assume transactions solve uniqueness, and use the repository's established conditional-update mechanism.
Do not add document version fields unless architecture explicitly requires them.
Do not introduce indexes, transactions, locking, or persistence abstractions without a real query, invariant, or concurrency requirement.
Webhooks
This section applies only to webhook/event-ingestion endpoints.
Authenticate the source, validate the event, recognize/persist event identity when required, process idempotently, acknowledge duplicates safely, define malformed/delayed/out-of-order behavior, avoid sensitive logging, and preserve correlation context.
Apply each protection according to the provider contract and repository requirements rather than mechanically.
Security
Apply relevant controls based on the actual trust boundary and data handled.
- Validate external input.
- Enforce authorization at the appropriate use-case or application boundary.
- Verify client-supplied ownership identifiers when applicable.
- Use least-privilege credentials.
- Keep secrets out of source code and logs.
- Avoid enumeration leaks where relevant.
- Use constant-time comparison for secrets/signatures.
- Apply rate limits where abuse is plausible.
- Keep dependencies/runtime maintained.
- Never disable TLS verification or bypass security checks to satisfy tests.
Delegate cryptographic verification and standard claims to the established crypto library; application code should validate project-specific claims, bindings, authorization, and business rules.
Do not add security machinery unrelated to the trust boundary affected by the change.
Logging and Observability
Use structured logs with useful context appropriate to the operation, such as operation, request/trace, safe tenant/client, aggregate/resource, job, remote request, duration, result, and stable error code.
Do not force every possible field into every log entry.
Never log passwords, tokens, API keys, private keys, full personal identifiers, confidential payloads, or sensitive financial data.
Add metrics where operationally meaningful, such as request/error rate, latency, queue depth, job outcomes, retries, stale work, provider latency/failure, webhook duplicates, and database contention.
Do not add metrics or logging merely to satisfy a checklist if they have no operational value.
API Design
Apply according to the protocol and conventions already used by the repository.
- Use typed request/response contracts where the language/framework supports them.
- Use stable machine-readable error codes when clients depend on them.
- Keep success responses consistent.
202only when work is actually accepted/in progress.409for business/identity conflicts when appropriate.422for semantic input errors when appropriate.503for retryable infrastructure unavailability.500for unexpected internal errors.- Do not expose stack traces, database errors, credentials, or internal provider details.
- Make pagination/filtering/sorting/limits explicit when the endpoint supports them.
Repository API conventions override generic status-code preferences.
Testing Standard
Tests protect behavior and invariants, not implementation trivia.
Select cases based on the affected behavior.
For stateful, side-effecting, concurrent, or integration-heavy flows, consider:
- happy path;
- invalid/missing resource;
- business/authorization conflict;
- duplicate and concurrent requests;
- dependency unavailable/timeout;
- retryable and non-retryable failure;
- ownership loss;
- unknown outcome;
- exact side-effect payload;
- forbidden side effects;
- durable winner after lost CAS;
- no duplicate remote side effect;
- corrected retry path when allowed.
For simpler changes, test only the meaningful behavioral surface and relevant edge cases.
Do not manufacture concurrency, retry, provider, or state-machine tests for code that has none of those concerns.
Test quality:
- assert meaningful outputs and side effects;
- assert important arguments;
- assert forbidden calls were not made when relevant;
- verify ordering when correctness depends on it;
- use realistic domain or application objects;
- avoid mocks creating impossible states;
- keep tests deterministic;
- name tests according to what they actually prove;
- do not consider a blocker resolved because only the happy path passes.
Call counts
Do not assert helper invocation counts merely to freeze implementation structure.
Call cardinality is valid when it protects a real invariant, including exactly one remote side effect, no duplicate database work, no duplicate credential resolution, no repeated publication, no redundant expensive work, or ordering required by concurrency correctness.
Performance
Measure before optimizing.
Prefer query/index fixes before caches.
Avoid repeated serialization, unnecessary loading, and repeated I/O.
When relevant:
- bound concurrency;
- paginate large collections;
- apply backpressure;
- avoid unbounded data growth;
- do not introduce distributed caching without an invalidation strategy.
Do not optimize code paths without evidence or a clear structural issue.
Deployment and Operations
Apply this section when the task affects runtime, packaging, infrastructure, schema, configuration, startup, shutdown, or deployment behavior.
Ensure required dependencies are packaged, fail startup when mandatory infrastructure is unavailable, expose health/readiness when appropriate, support graceful shutdown for long-lived services, validate configuration, keep migrations rollout-safe, avoid destructive startup migrations, and document deployment-impacting changes.
Do not add operational infrastructure to changes that do not affect deployment or runtime behavior.
Review Mode
Lead with findings.
Severity:
P0: catastrophic data loss, severe security compromise, unrecoverable high-impact failure.P1: merge blocker, incorrect behavior, duplicate side effect, lost work, broken deployment, major regression.P2: important correctness, maintainability, performance, resilience, or observability issue.P3: minor improvement or cleanup.
For each finding include:
- severity;
- exact file/location;
- failure scenario;
- why current protection is insufficient;
- minimal fix;
- test proving it, when a test is applicable.
For maintainability findings, state the concrete cognitive burden: duplicated runtime work, hidden control protocol, misleading naming, excessive state exposure, unnecessary jumps, unclear loop/recursion termination, repeated validation, or unnecessary abstraction.
A blocker is resolved only when the behavior under review is actually correct.
For stateful, concurrent, or side-effecting flows, resolution additionally requires that relevant runtime, error, and concurrency behavior is correct, duplicate side effects remain impossible, and the relevant test exists.
Do not require distributed-systems proofs for defects that do not involve distributed behavior.
Implementation Workflow
1. Establish scope
Determine requested/current behavior, affected boundaries, applicable invariants, and explicit non-goals.
Identify which advanced concerns actually apply:
stateful workflow?
concurrent writers?
database transaction?
remote side effect?
non-idempotent operation?
retry/recovery?
queue/worker?
external integration?
rich domain model?
deployment impact?
Do not analyze absent concerns as though they existed.
2. Trace the flow
Trace the main affected path first.
Then trace only materially relevant variants, such as:
happy path
existing-resource path
retry/recovery path
concurrency-loss path
validation/error path
authorization path
List actual reads, writes, calculations, validations, state changes, and side effects.
For a simple local change, this may be only one short execution path.
3. Identify hidden complexity
Look specifically for applicable issues:
- duplicated queries/writes/validation/calculations;
- duplicated credential/secret resolution;
- repeated serialization;
- hidden retries or open loops;
- recursive state re-entry;
- misleading names;
- broad serialization/snapshot usage;
- helpers that hide rather than clarify;
try/catchwithout semantic purpose;- unnecessary layers or indirection.
Ignore categories that do not exist in the affected code.
4. Choose the minimum design
Prefer:
- existing repository patterns;
- explicit contracts;
- one source of truth;
- one clear representation of each business concept;
- the minimum required transaction boundary;
- one error-mapping location where appropriate;
- a small intentional domain API when rich domain objects exist;
- shared downstream continuation when upstream lifecycle paths genuinely differ.
Do not introduce architecture for theoretical future requirements.
5. Implement vertically
Update only required contracts, application logic, domain behavior, persistence, integration, jobs/workers, errors, tests, and deployment configuration.
Touch only the layers that actually exist and are affected.
Do not leave half-completed migrations or competing implementations.
6. Review your own diff
Inspect applicable concerns:
- new/removed files and abstractions;
- public API/getters added;
- duplicated I/O removed;
- duplicated validation removed;
- serialization/snapshot usage;
try/catchpurpose;- state transitions;
- retry/CAS termination behavior;
- transaction boundaries;
- side-effect cardinality;
- whether the main path is easier to trace.
Delete abstractions, getters, fields, states, configuration, and helpers with no real consumer.
7. Validate
Run applicable repository commands:
- formatter;
- typecheck;
- lint;
- unit/integration tests;
- build;
- migration validation;
- Docker/container build for deployment changes;
- security/dependency checks when relevant.
Use the repository's actual commands and tooling.
Never claim success for a command that was not actually executed.
Do not run irrelevant validation solely because it appears in this list.
8. Report
Implementation:
Result
- What changed
Flow
- How the affected path now reads
Removed complexity
- Duplicated work removed
- Hidden control flow removed
- Unnecessary abstractions removed
Validation
- Commands and results
Risks
- Remaining known risks
Omit sections with no meaningful content rather than inventing filler.
Review:
Verdict
- Approved / changes required
Findings
- P0/P1/P2/P3
Resolved
- Verified previous findings
Remaining
- Real blockers only
Language-specific Preferences
Apply only the language section relevant to the repository.
TypeScript
- Use strict types.
- Avoid
anyoutside unavoidable infrastructure boundaries. - Prefer discriminated unions for workflow state/results when they materially improve correctness.
- Use
readonlyfor immutable contracts where appropriate. - Prefer explicit public return types.
- Avoid non-null assertions when a state invariant can prove the value.
- Keep time units explicit.
- Avoid broad casts hiding contract problems.
- Preserve discriminated-state guarantees instead of flattening state fields to nullable getters.
- Do not use serialization snapshots as the primary domain read API when rich domain objects exist.
Go
- Pass
context.Contextthrough request-scoped or cancelable operations. - Keep interfaces close to consumers.
- Avoid package-global mutable state.
- Ensure goroutines have cancellation/ownership.
- Do not start background goroutines without lifecycle management.
- Do not introduce interfaces when a concrete dependency is sufficient.
Java/Kotlin
- Keep transaction boundaries explicit when transactions are used.
- Avoid framework annotations leaking through the domain when a domain layer exists.
- Prefer immutable contracts where practical.
- Classify caught exceptions.
- Keep blocking/non-blocking execution explicit.
- Follow the repository's framework conventions instead of imposing additional layering.
Python
- Use type hints where they materially improve correctness and maintainability.
- Validate runtime input at trust boundaries.
- Avoid hidden global clients.
- Separate sync/async code clearly.
- Handle cancellation in async workflows when relevant.
- Do not block the event loop with synchronous I/O.
- Do not introduce async machinery into synchronous code without a concrete need.
C#/.NET
- Pass cancellation tokens through cancelable operations.
- Keep
DbContextlifetime explicit. - Avoid fire-and-forget tasks.
- Use stable errors/results where the repository follows that pattern.
- Keep DI explicit.
- Avoid mixing rich domain objects with persistence tracking concerns when the repository separates them.
- Do not introduce new architectural layers merely because the platform supports them.
Forbidden Patterns
Do not introduce without demonstrated need:
- generic abstraction for one implementation;
- hidden service locator/global mutable state;
- state-machine framework for a small explicit flow;
- generic CAS/retry executor for one workflow;
while (true)as implicit concurrency recovery;- unbounded recursion for CAS recovery;
nullpropagated through callers as hidden control flow;- catch-and-ignore or catch-and-rethrow without purpose;
- success after required infrastructure failure;
- external calls or queue publication inside database transactions;
- competing workflow state models;
- duplicated business rules or duplicated runtime I/O;
- immediate rewrite of freshly inserted identical state;
- unsafe retry of unknown non-idempotent outcomes;
- serialization methods used as universal aggregate getters;
- nullable getters weakening state invariants;
- getters/contracts with no current consumer;
- tests that mock away the behavior under review;
- architecture driven only by trends/terminology;
- silencing type errors instead of fixing contracts;
- validation duplicating dependency guarantees;
- unused claims, fields, states, config, indexes, interfaces, or abstractions;
- a second mechanism for auth, validation, transactions, queues, workers, or outbox;
- unrelated architectural refactors;
- optional properties/casts hiding missing contracts;
- broad error classification turning unrelated failures into one infrastructure error;
- version fields added only because optimistic locking is possible when the repository uses another mechanism;
- concurrency, transaction, retry, queue, state-machine, idempotency, or domain machinery added only because this skill mentions those concepts.
Final Quality Gate
Apply the universal checks to every backend task.
Apply conditional checks only when that concern exists in the affected execution path.
Universal
- Repository instructions were followed.
- The affected execution path was inspected.
- Existing behavior was preserved unless intentionally changed.
- Business rules and invariants relevant to the change are explicit.
- The main path is readable top-to-bottom.
- No unnecessary abstraction was introduced.
- No unnecessary duplicate runtime work remains.
- No duplicated business rule or validation remains without reason.
- Function and type names match their real execution scope.
- Every new field, config value, abstraction, dependency, index, state, or contract has a current use.
- Error handling has semantic purpose.
- Tests cover the meaningful behavior and edge cases of the change.
- Validation commands were actually executed or limitations were stated.
- The final execution path is no harder to understand than before.
- Final response separates blockers from cleanup.
When rich domain objects exist
- Serialization methods are not universal domain getters.
- State-specific invariants remain strong.
- Public getters expose only values with real consumers.
- Persistence representation has not leaked unnecessarily into business logic.
When durable workflow state exists
- State transitions are explicit.
- Invalid transitions fail safely.
- Terminal-state behavior is intentional.
- Recovery paths do not create competing state models.
When concurrency or ownership exists
- Ownership-sensitive transitions are atomic.
- Concurrency-loss behavior is explicit and bounded.
- No open retry loop or hidden recursive retry remains.
- Lost conditional writes have defined behavior.
- Contention cannot duplicate protected side effects.
When transactions exist
- Transaction boundaries are correct and minimal.
- External calls occur outside database transactions.
- Queue publication follows repository durability conventions.
- Transactions are not being used as a substitute for uniqueness.
When remote side effects exist
- Idempotency requirements are defined.
- Duplicate requests/jobs cannot duplicate unsafe remote side effects.
- Unknown external outcomes are handled safely.
- Retry behavior distinguishes confirmed failure from unknown outcome.
- Stable external references or provider idempotency are used when available.
When retries exist
- Retryable and non-retryable failures are distinguished.
- Retry count/termination is explicit.
- Retrying cannot duplicate unsafe work.
- Initial delay and retry backoff use clear units.
When queues/workers exist
- Logical job identity is correct where deduplication matters.
- Stale work has a defined recovery strategy when applicable.
- Publication failure remains visible/recoverable.
- Worker lifecycle and shutdown are safe.
When credentials or provider configuration exist
- Credentials are resolved no more than necessary.
- Secrets are not logged or exposed.
- Authentication and provider configuration follow existing repository conventions.
When database persistence is affected
- Required uniqueness is enforced at the correct persistence boundary.
- Queries use appropriate indexes/access patterns.
- No unnecessary duplicate DB reads/writes remain.
- Migrations are rollout-safe when schema changes are involved.
When deployment/runtime behavior changes
- Required dependencies and configuration are packaged.
- Startup/readiness behavior remains correct.
- Graceful shutdown is preserved where relevant.
- Deployment-impacting changes are documented.