go-crypto-wallet / internal
Cursor rule128 starsChanged 6 months agoMITView on GitHub
DTO and Data Definition Placement Rules
We split this dto.mdc into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 35
All types used in application/ports/ interface signatures MUST be defined in internal/application/dto/.
- Very specific: line 141
Add new DTOs to the appropriate chain sub-package.
≈ “Common” is an estimate: at least 1 in 5 of the 6,350 Cursor rule files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
---
description: DTO and Data Definition Placement Rules
globs: ["internal/**/*.go"]
alwaysApply: false
---
# DTO and Data Definition Placement Rules
## Overview
Rules for where to define data types (DTOs, wire types, presentation types) and where to place
conversion logic in the Clean Architecture layers of `internal/`.
## Layer Summary
```
Interface Adapters → defines: presentation input/output types (CLI args, HTTP body, gRPC message)
converts: presentation → application DTO before calling use case
Application Layer → defines: canonical cross-boundary DTOs (internal/application/dto/)
port interfaces use ONLY these types in their signatures
Infrastructure → defines: internal wire/DB types (JSON-tagged structs, ORM models)
converts: wire types ↔ application DTOs at the boundary
Domain Layer → defines: domain entities, value objects (with business logic — NOT DTOs)
no conversion, no DTOs
```
## Rules
### 1. Application DTOs Are the Canonical Cross-Boundary Types
All types used in `application/ports/` interface signatures MUST be defined in `internal/application/dto/`.
Infrastructure types MUST NOT appear in port interface signatures.
```go
// ✅ GOOD: port interface uses application DTO
// internal/application/ports/api/xrp/interface.go
type TransactionPreparer interface {
CreateRawTransaction(
ctx context.Context,
senderAccount, receiverAccount string,
amount float64,
instructions *dtoxrp.Instructions, // application DTO
) (*dtoxrp.TxInput, string, error) // application DTO
}
// ❌ BAD: port interface returns an infrastructure package type
type KeyGenerator interface {
WalletPropose(ctx context.Context, passphrase string) (*xrprpcadmin.ResponseWalletPropose, error)
// ^^^^^^^^^ infrastructure type in port
}
```
### 2. Infrastructure Defines Wire Types Locally, Converts at the Boundary
Infrastructure packages may define their own internal types optimised for wire format (JSON tags,
protocol buffer fields, etc.). These must be converted to/from application DTOs before crossing
the boundary.
Conversion functions must be **private** unless explicitly needed by a sibling package.
```go
// internal/infrastructure/api/xrp/public/transaction.go
// Internal wire type — JSON tags, infra-specific detail
type TxInput struct {
TransactionType string `json:"TransactionType"`
Account string `json:"Account"`
// ...
}
// Private converters — live in the infrastructure package, not in application/
func toInfraTxInput(dto *dtoxrp.TxInput) *TxInput { ... }
func toDTOTxInput(infra *TxInput) *dtoxrp.TxInput { ... }
// Public method satisfies the port interface — returns application DTO
func (p *PublicXRP) CreateRawTransaction(...) (*dtoxrp.TxInput, string, error) {
infra := buildTxInput(...)
return toDTOTxInput(infra), jsonStr, nil
}
```
### 3. Interface Adapters Convert Presentation Input Before Calling Use Cases
CLI flags, HTTP request bodies, gRPC messages are presentation details. Handlers must convert
them to application DTOs and never pass raw presentation types into use cases.
```go
// internal/interface-adapters/cli/watch/api/xrp/sendcoin.go
func (h *SendCoinHandler) Handle(args CLIArgs) error {
instructions := &dtoxrp.Instructions{ // convert CLI args → application DTO
Fee: args.Fee,
}
return h.useCase.Execute(ctx, args.Sender, args.Receiver, args.Amount, instructions)
}
```
### 4. Domain Types Are NOT DTOs
Domain entities and value objects contain business logic (validation, invariants). They are
not plain data carriers. Do not use them as DTOs across layer boundaries.
| Domain type | Used as DTO? |
|-------------|-------------|
| `domain/address.Address` | No — pass `string` or an application DTO |
| `domain/coin.CoinTypeCode` | Acceptable as a value type if it has no infra deps |
| `domain/transaction.Transaction` | No — map to an application DTO |
### 5. Where Conversion Code Lives
The **outer** layer is always responsible for conversion. This keeps inner layers clean.
| Conversion direction | Where the conversion code lives |
|---|---|
| Infra wire type → Application DTO | Infrastructure package (`toDTOXxx` functions) |
| Application DTO → Infra wire type | Infrastructure package (`toInfraXxx` functions) |
| Presentation input → Application DTO | Interface-adapters handler/controller |
| Application DTO → Presentation output | Interface-adapters handler/controller |
### 6. DTO Placement by Sub-Directory
```
internal/application/dto/
├── address.go # shared address DTOs (all chains)
├── address_format.go # address format helpers
├── btc/
│ ├── dto.go # BTC-specific DTOs (AddressInfo, etc.)
│ └── fullpubkey.go # BTC public key DTOs
├── eth/
│ └── transaction_file.go # ETH file-based transaction DTOs
└── xrp/
├── transaction.go # XRP transaction DTOs (TxInput, Instructions, ...)
├── transaction_file.go # XRP file-based transaction DTOs
└── response.go # XRP response DTOs
```
Add new DTOs to the appropriate chain sub-package. Chain-agnostic DTOs go in the root `dto/` package.
## Quick Checklist
- [ ] Port interface method signatures use only `internal/application/dto/` types (or primitives/domain value types)
- [ ] Infrastructure wire types are private to their package
- [ ] Conversion functions (`toDTOXxx`, `toInfraXxx`) live in the infrastructure package
- [ ] Handlers in interface-adapters convert presentation input to DTOs before calling use cases
- [ ] No infrastructure package types appear as return types in `application/ports/` interfaces
## Related Rules
- @.claude/rules/internal/clean-architecture.md - Layer dependency rules
- @.claude/rules/internal/application-layer.md - Application layer specifics
- @.claude/rules/internal/infrastructure-layer.md - Infrastructure layer specifics
- @.claude/rules/internal/interface-adapters-layer.md - Interface adapters layer specifics
- @.claude/rules/internal/internal-interface.md - Interface definition placement rules
Where files are headingNew Cursor rule files have more rules about planning and tracking tasks, and fewer about code style.
Of the Cursor rule files we read, the 3,978 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository62 other files it gives its agents.
- AGENTS.mdAGENTS.md
- internal/AGENTS.mdAGENTS.md
- pkg/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- internal/CLAUDE.mdCLAUDE.md
- pkg/CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/agent-files.mdcCursor rule
- .cursor/rules/apps/bun.mdcCursor rule
- .cursor/rules/apps/eth-contracts.mdcCursor rule
- .cursor/rules/apps/xrp-server.mdcCursor rule
- .cursor/rules/database/atlas-hcl.mdcCursor rule
- .cursor/rules/database/sqlc.mdcCursor rule
- .cursor/rules/documentation-language.mdcCursor rule
- .cursor/rules/general.mdcCursor rule
- .cursor/rules/github-actions.mdcCursor rule
- .cursor/rules/go/conventions.mdcCursor rule
- .cursor/rules/go/di.mdcCursor rule
- .cursor/rules/go/go-path.mdcCursor rule
- .cursor/rules/go/go-test.mdcCursor rule
- .cursor/rules/internal/application-layer.mdcCursor rule
- .cursor/rules/internal/btc-shared.mdcCursor rule
- .cursor/rules/internal/clean-architecture.mdcCursor rule
- .cursor/rules/internal/cli-structure.mdcCursor rule
- .cursor/rules/internal/domain-layer.mdcCursor rule
- .cursor/rules/internal/infrastructure-layer.mdcCursor rule
- .cursor/rules/internal/interface-adapters-layer.mdcCursor rule
- .cursor/rules/internal/internal-interface.mdcCursor rule
- .cursor/rules/internal/mockery.mdcCursor rule
- .cursor/rules/internal/repository.mdcCursor rule
- .cursor/rules/internal/usecase.mdcCursor rule
- .cursor/rules/proto.mdcCursor rule
- .cursor/rules/README.mdCursor rule
- .cursor/rules/security.mdcCursor rule
- .cursor/rules/shell-script.mdcCursor rule
- .cursor/rules/ssot.mdcCursor rule
- .cursor/rules/task-context-loading.mdcCursor rule
- .cursor/rules/typescript.mdcCursor rule
- .cursor/rules/yaml.mdcCursor rule
- llms.txtllms.txt
- bch-developmentSkill
- btc-terminologySkill
- db-migrationSkill
- devopsSkill
- docs-ssotSkill
- docs-updateSkill
- fix-pr-reviewSkill
- github-issue-creationSkill
- git-workflowSkill
- go-developmentSkill
- knowledge-gapSkill
- label-context-mappingSkill
- makefile-updateSkill
- mockerySkill
- openspec-apply-changeSkill
- openspec-archive-changeSkill
- openspec-exploreSkill
- openspec-proposeSkill
- shell-scriptsSkill
- solidity-developmentSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

