DDD-first operating guide for coding agents in this repository.
Model behavior around the domain first. Protect domain language, business invariants, and bounded-context boundaries before optimizing frameworks, transport, or storage.
The boundaries/ directory represents bounded contexts and related interfaces:
link(Go) - core short-link lifecycle domainmetadata(Go) - enrichment and screenshot/metadata domainbff(Go) - client-facing application/API composition for webapi/api-gateway(Go) - deprecated API boundary contextproxy(TypeScript) - redirect/runtime edge serviceui(Next.js/TypeScript) - web clientmobile(Expo + Nx) - mobile clientchrome-extension(WXT + React/TS) - browser client
Read first:
boundaries/README.md- boundary-local
README.md docs/ADR/README.md
If instructions conflict, follow:
- Files in the exact service/context being edited
- Boundary-local rules:
boundaries/proxy/.cursor/rules/architecture.mdboundaries/ui/.cursor/rules/front-end-cursor-rules.mdc
- Repo-wide rules:
.cursor/.cursorrules.cursor/rules/go-microservices.mdc
- This document
- Domain layer
- Entities, Value Objects, Aggregates, Domain Services, Domain Events
- No infrastructure dependencies
- Business invariants enforced here
- Application layer
- Use cases/application services
- Orchestrates domain behavior and transactions
- DTOs for boundary contracts
- Infrastructure layer
- DB, MQ, HTTP clients, file systems, third-party SDKs
- Implements repository/gateway interfaces
- Interface/transport layer
- HTTP/gRPC handlers, CLI, messaging consumers
- Map external contracts to application DTOs
Dependency direction must always point inward (toward domain).
- Keep aggregate roots small and consistency-focused.
- Modify aggregate state only through aggregate behavior.
- Prefer immutable Value Objects.
- Repositories should load/save aggregate roots, not random tables.
- Domain events should express business facts in ubiquitous language.
- Cross-context integration should use explicit contracts (events, APIs, ACL/adapters), never hidden coupling.
- Use terms from boundary glossary/README/ADR in names.
- If domain meaning changes, update docs and naming in the same PR.
- Avoid generic names like
manager,data,utilfor domain logic.
- Identify the target bounded context.
- Identify affected aggregate/use case.
- Write change at domain/application level first; adapt infra second.
- Keep changes local to one context unless integration is required.
- Validate with the narrowest relevant tests/checks.
- Summarize domain impact (invariant, event, contract, behavior).
make helpmake depmake proto-lintmake proto-generatemake up/make down(heavy full stack)
Run from context directory:
go test ./...go test -run <Name> ./...make help
Useful local targets:
boundaries/link:make dev,make proto-lint,make proto-generate,make docs,make e2eboundaries/metadata: proto/docs viamake helpboundaries/bff:make dep,make generate,make docs
boundaries/proxy:pnpm install && pnpm build && pnpm lint && pnpm testboundaries/ui:pnpm install && pnpm type-check && pnpm lint && pnpm test:runboundaries/mobile:pnpm install && pnpm nx serve shortlink(orpnpm nx build shortlink)boundaries/chrome-extension:pnpm install && pnpm build && pnpm compile
- If
.protocontracts change, run correspondingproto-lintandproto-generate. - Regenerate derived artifacts in the same change when contracts/interfaces change.
- Do not hand-edit generated files unless unavoidable; document reason when doing so.
- Business logic inside handlers/controllers/repositories.
- Infrastructure types leaking into domain entities/value objects.
- Cross-context direct DB coupling.
- “God” services that bypass aggregate invariants.
- Renaming domain concepts without updating ubiquitous language docs.
- Check current tree before editing:
git status. - Keep commits small and domain-focused.
- Use clear English commit messages.
- Never revert unrelated user changes.
Before finalizing:
- Bounded context and aggregate boundaries were respected.
- Domain invariants are preserved and tested.
- External contracts/events are updated and validated if changed.
- Relevant tests/lint/type-check were run (or explicitly justified).
- ADR/README/glossary updates are included when domain language changed.