Kodlama aracıları, siz sınırları açıkça yazana kadar kod tabanınız hakkında hızlı, kendinden emin ve mimari açıdan eksik bilgiyle hareket eder. Claude Code, Codex veya Cursor'a belirsiz bir görev verdiğinizde derlenen, testi geçen ama alan katmanı ile HTTP katmanı arasındaki sınırı bozan kod üretebilir. DESIGN.md, mimari niyeti doğrudan depoya yazarak bu tahmin problemini azaltır.
TL;DR
DESIGN.md, kod tabanının mimari niyetini, değişmezlerini, kısıtlarını ve tasarım kararlarını Markdown olarak kaydeden bir depo dosyasıdır. Kodlama aracıları için “bu sistem neden böyle?” sorusunu yanıtlar.
-
README.md: Proje nedir, nasıl başlatılır? -
AGENTS.md: Nasıl build/test/lint yapılır? -
CLAUDE.md: Claude Code’a özel çalışma talimatları -
DESIGN.md: Mimari kararlar, sınırlar ve bozulmaması gereken kurallar
Giriş
Kodlama aracılarını kullanan ekiplerin sık gördüğü hata şudur: Bir aracıdan ödeme servisine iade endpoint’i eklemesini istersiniz. Aracı çalışan bir handler üretir; testler geçer. Fakat handler veritabanını doğrudan controller’dan çağırır, gateway hatasını yutar ve sistemde zaten bulunan para modelini kullanmak yerine yeni bir para tipi oluşturur.
Sorun aracının kod yazamaması değildir. Sorun, aracının şu bilgileri bilmemesidir:
- Katman sınırları
- Alan değişmezleri
- Geçmişte reddedilen tasarım seçenekleri
- API sözleşmesinin gerçek kaynağı
- “Bunu asla böyle yapmayın” kararları
DESIGN.md, bu bilgileri deponun köküne koyar. Böylece aracı kodu okuduğu yerde mimari niyeti de okur.
DESIGN.md aslında nedir?
DESIGN.md, kodunuzun neden bu şekilde tasarlandığını anlatan düz metin bir dosyadır.
Şunları belgelemek için kullanılır:
- Katmanlar ve bağımlılık yönleri
- Değişmezler
- Kritik kararların gerekçeleri
- Reddedilen alternatifler
- API sözleşmesinin kaynağı
- Veri modeli kuralları
- Yeni kodun nereye ekleneceği
- Aracının dokunmaması gereken alanlar
Örneğin kaynak kodu bir aracının Account.debit() metodunu görmesini sağlar. Ama bu metodun tek yetkili bakiye değiştirme yolu olduğunu söylemez. DESIGN.md bunu açıkça yazar.
Bu yaklaşım, ARCHITECTURE.md ve ADR pratiklerine benzer. Farkı, dosyanın kodlama aracılarının da okuyacağı şekilde daha kısa, daha bildirimsel ve karar odaklı yazılmasıdır.
DESIGN.md vs AGENTS.md vs CLAUDE.md vs README
Bu dosyalar birbirini tamamlar; aynı belgeye dönüştürülmemelidir.
| Dosya | Kitle | Cevapladığı soru | Değişim hızı | Önerilen uzunluk |
|---|---|---|---|---|
README.md |
İnsanlar | Bu proje nedir, nasıl başlatılır? | Özelliklerle değişir | Orta |
AGENTS.md |
Kodlama aracıları | Nasıl build/test/lint/commit yapılır? | Araçlarla değişir | Kısa |
CLAUDE.md |
Claude Code | AGENTS.md + Claude’a özel talimatlar | Araçlarla değişir | Kısa, yaklaşık 200 satır altı |
DESIGN.md |
Aracılar + mühendisler + reviewer’lar | Sistem neden böyle tasarlandı? | Mimariyle değişir | Orta, karar yoğun |
AGENTS.md, agents.md projesi tarafından “kodlama aracılarını yönlendirmek için basit, açık bir format” olarak tanımlanır. İşlevi operasyoneldir: test komutları, build adımları, lint kuralları, commit formatı.
Anthropic’in Claude Code bellek belgelerine göre CLAUDE.md, Claude Code için benzer bir talimat dosyasıdır. Mevcut bir AGENTS.md varsa CLAUDE.md içinde @AGENTS.md ile içe aktarılması önerilir.
Fakat bu dosyalara derin mimari gerekçe koymak iyi bir fikir değildir. Uzadıkça modelin dosyayı takip etmesi zorlaşır. Daha iyi yapı şudur:
README.md -> İnsanlara giriş
AGENTS.md -> Build/test/lint/commit talimatları
CLAUDE.md -> @AGENTS.md + Claude’a özel kısa kurallar
DESIGN.md -> Mimari niyet, değişmezler, kararlar
AGENTS.md içinde DESIGN.md için kısa bir referans yeterlidir:
Mimari ve tasarım kuralları için `DESIGN.md` dosyasını okuyun.
Katman sınırlarını, değişmezleri veya API sözleşmesini etkileyen
değişikliklerden önce bu dosyayı kontrol edin.
Claude Code tarafında:
@AGENTS.md
@DESIGN.md
Bu dosyaların Claude bağlamıyla nasıl çalıştığına dair daha ayrıntılı bir örnek için Claude Code iş akışları yazısına bakabilirsiniz.
DESIGN.md’ye ne koymalı?
Bir DESIGN.md, aracının yalnızca kod okuyarak çıkaramayacağı bilgileri içermelidir.
Koyulması gereken başlıklar:
- Sistem şekli: Katmanlar, modüller, bağımlılık yönleri
- Değişmezler: Her zaman doğru kalması gereken kurallar
- Ana kararlar ve gerekçeleri: Neden bu tasarım seçildi?
- Reddedilen alternatifler: Aracının tekrar önermemesi gereken yollar
- Veri ve domain kuralları: Para, zaman, ID, tenant, soft-delete vb.
- API sözleşmesi: OpenAPI dosyasının konumu ve yetkisi
- Yeni kodun yeri: Endpoint, use case, integration, middleware nereye eklenir?
- Dokunulmaması gerekenler: Generated kod, legacy modüller, eski migration’lar
- Çelişki durumunda davranış: Aracı ne yapmalı?
Örnek DESIGN.md şablonu
Aşağıdaki şablonu kopyalayıp kendi servisiniz için daraltabilirsiniz.
# DESIGN.md: Payments API Service
This file records architectural intent and the decisions behind it.
Read this before generating or modifying code. If a change conflicts
with a rule here, stop and flag it instead of working around it.
## System shape
Layered, dependencies point inward only:
http (handlers, DTOs) -> app (use cases) -> domain (entities,
invariants) <- infra (db, gateway clients)
- `domain/` has zero imports from `http/`, `app/`, or any framework.
- `infra/` implements interfaces declared in `domain/` or `app/`.
- `http/` never touches the database or the payment gateway directly.
It calls a use case in `app/`.
## Invariants
- A ledger entry is immutable once written. Corrections are new
compensating entries, never updates or deletes.
- Account balance is derived from ledger entries, not stored as a
mutable field that code can set directly.
- Money is an integer count of minor units plus an ISO-4217 currency
code. Never use float. Never mix currencies in one operation.
- Every call to an external payment gateway is idempotent, keyed by
`idempotency_key`.
- Balances never go negative unless an explicit `OverdraftPolicy`
authorizes it.
## Key decisions and rationale
- **Outbox pattern for gateway calls.**
Handlers write an intent row in the same DB transaction as the
business change. A worker calls the gateway later.
Rationale: the gateway times out under load. Inline calls made
latency and failure handling unowned.
Do not call the gateway from a request handler.
- **Single write path per aggregate.**
Only `Account.post_entry()` writes to the ledger.
Rationale: a second write path caused balance drift.
Add new behavior as aggregate methods, not new ad-hoc queries.
- **Event sourcing for the ledger only.**
The rest of the system is CRUD.
Rationale: money requires a perfect audit trail; full event sourcing
elsewhere is unnecessary.
## Rejected alternatives
- ORM lazy-loading across aggregates. It caused N+1s and unclear
transaction boundaries.
- Storing balance as a column updated in place.
- Pulling a generic `Money` library from the registry. Use
`domain/money.py`.
- Synchronous merchant webhooks from the request thread. Use the
notification queue.
## Data and domain rules
- All timestamps are UTC, stored as `timestamptz`, formatted RFC 3339
at the edge.
- IDs are ULIDs generated in the app layer, never DB autoincrement.
- Soft delete is not used. Records are active or archived by an
explicit use case.
- Every query is scoped by `tenant_id`. A repository method without
tenant scope is a bug.
## API contract source of truth
- The OpenAPI 3.1 spec in `api/openapi.yaml` is authoritative.
- Request/response types are generated from the spec.
- Do not hand-edit generated types in `http/generated/`.
- New or changed endpoints:
1. Update `api/openapi.yaml`
2. Regenerate types
3. Implement the use case and handler
- Error responses follow RFC 9457 `problem+json`.
Use the shared `problem()` helper.
## Where new code goes
- New endpoint:
- route: `http/routes/`
- DTO: `http/dto/`
- use case: `app/usecases/`
- domain logic: `domain/`
- New external integration:
- client: `infra/clients/`
- interface: `app/ports/`
- Cross-cutting concern:
- middleware: `http/middleware/`
- never inline in handlers
## Out of scope / do not touch
- `http/generated/`: regenerated from OpenAPI
- `legacy/billing_v1/`: frozen, under migration
- `migrations/`: never edit an applied migration; add a new one
## When in doubt
If a requested change requires breaking a rule above, stop and say so.
Propose the smallest design-consistent alternative instead of silently
working around the rule.
Son bölüm önemlidir. Aracıya yalnızca kuralı değil, kural çakıştığında ne yapacağını da söylemiş olursunuz.
Kodlama aracıları DESIGN.md’yi nasıl tüketir?
Aracıların özel bir DESIGN.md parser’ı yoktur. Dosyayı normal bir repo dosyası gibi okurlar ve bağlama eklerler.
Uygulanabilir kurulum:
1. Depo köküne DESIGN.md ekleyin
repo/
README.md
AGENTS.md
CLAUDE.md
DESIGN.md
api/openapi.yaml
src/
2. AGENTS.md içinde referans verin
## Architecture
Before structural changes, read `DESIGN.md`.
Follow its layering rules, invariants, API contract rules, and
"when in doubt" instruction.
3. Claude Code kullanıyorsanız CLAUDE.md içinde içe aktarın
@AGENTS.md
@DESIGN.md
Prefer design-consistent changes. If a request conflicts with
DESIGN.md, explain the conflict before editing code.
4. Review sırasında dosyaya referans verin
Bir PR’da ihlal gördüğünüzde yorumu spesifik yazın:
Bu değişiklik DESIGN.md içindeki "http never touches the database
directly" kuralını ihlal ediyor. Handler yerine app/usecases altında
bir use case ekleyelim.
Bu, aracıya net bir düzeltme hedefi verir.
Kendi aracı sistemlerini kuran ekipler de benzer geri bildirim döngüsüne dayanır. Bunun otonom akışlara nasıl bağlandığını kendi Claude Code’unuzu oluşturun yazısında görebilirsiniz.
Anti-pattern’lar
DESIGN.md kısa, karar yoğun ve güncel kalmalıdır. Aşağıdaki hatalardan kaçının.
1. Kodu yeniden anlatmak
Kötü:
`UserService` kullanıcıları yönetir.
Bu bilgi zaten koddan okunabilir.
İyi:
User creation must go through `RegisterUser` use case because it
creates the audit record and default billing profile in one transaction.
2. Eğitim dokümanına çevirmek
DESIGN.md içine uzun “özellik nasıl eklenir?” rehberleri koymayın. Bunlar CONTRIBUTING.md veya ekip içi dokümana aittir.
DESIGN.md şunları içermemelidir:
- Uzun shell komutları
- Kurulum adımları
- IDE ayarları
- Genel onboarding metni
3. Hedef mimariyi mevcut gerçeklik gibi yazmak
Kötü:
All writes go through use cases.
Eğer legacy kod bunu yapmıyorsa bu yanıltıcıdır.
İyi:
Target: all writes go through use cases.
Current exception: `legacy/` bypasses this. Do not extend that pattern.
4. Sahipsiz bırakmak
Bir sahibi yoksa dosya çürür. PR şablonuna kontrol ekleyin:
- [ ] Bu PR `DESIGN.md` içindeki bir kararı değiştiriyor mu?
- [ ] Değiştiriyorsa `DESIGN.md` aynı PR’da güncellendi mi?
5. Kodla satır satır senkronize etmeye çalışmak
DESIGN.md, fonksiyon imzalarını veya dosya listesini takip etmek için değildir. Yılda birkaç kez değişen kararları belgeleyin:
- Katman sınırları
- Transaction modeli
- API sözleşmesi
- Veri bütünlüğü
- Güvenlik değişmezleri
6. AGENTS.md ile çelişmek
Operasyonel kurallar AGENTS.md içinde, mimari kurallar DESIGN.md içinde kalmalıdır. Aynı kuralı iki yerde farklı şekilde yazmayın.
API ve arka uç kod tabanları için DESIGN.md
DESIGN.md en çok API ve backend servislerinde değer üretir. Çünkü bu sistemlerde hatalı tahminler pahalıdır:
- Yanlış API sözleşmesi
- Bozuk transaction sınırı
- Eksik idempotency
- Tutarsız hata modeli
- Tenant izolasyonu hatası
- Katman ihlali
- Generated kodun elle değiştirilmesi
OpenAPI sözleşmesini yetkili kaynak yapın
DESIGN.md içinde açık yazın:
The OpenAPI spec in `api/openapi.yaml` is authoritative.
Generated types must not be edited by hand.
Endpoint changes start with the OpenAPI spec.
Bu, aracının derlemeyi geçirmek için generated type dosyasını elle değiştirmesini engeller.
Eğer sözleşmeyi önce Apidog içinde tasarlayıp OpenAPI olarak depoya aktarıyorsanız, DESIGN.md doğrudan bu dosyayı işaret edebilir. Koddan önce sözleşme tasarlama yaklaşımı AI aracıları için API tasarlama yazısında daha ayrıntılı ele alınır.
Transaction sınırlarını belirtin
Örnek:
External calls must never happen inside a DB transaction.
Use the outbox table and background worker.
Bu kural yazılı değilse, aracı genellikle en basit yolu seçer: handler içinde satır içi gateway çağrısı.
Idempotency kuralını değişmez yapın
Ödeme, sipariş ve provisioning endpoint’leri için kritik:
All POST endpoints that create money movement require an
`Idempotency-Key` header. Retries must not create duplicate charges.
Hata modelini sabitleyin
All API errors use RFC 9457 `problem+json`.
Use the shared `problem()` helper.
Do not invent endpoint-specific error envelopes.
Tenant kapsamını güvenlik değişmezi yapın
Every repository query must be scoped by `tenant_id`.
A repository method without tenant scope is a security bug.
Versiyonlama kurallarını yazın
Renaming or removing a response field is a breaking change.
Breaking changes require a new major API version.
Minor versions may only add optional fields.
Bu kurallar aracıların “küçük refactor” adı altında istemci kırmasını engeller.
Aracının yazdığı API’yi sözleşmeye karşı test etmek istiyorsanız, Apidog’u indirin. Önce API tasarımını oluşturabilir, DESIGN.md içinde işaret edeceğiniz OpenAPI çıktısını alabilir ve oluşturulan endpoint’lerin sözleşmeyle uyumunu test edebilirsiniz.
Uygulama planı
Mevcut bir depoya DESIGN.md eklemek için küçük başlayın.
Adım 1: En sık bozulan 5 kuralı yazın
Örneğin:
## Invariants
- HTTP handlers never access the database directly.
- All writes go through app use cases.
- OpenAPI spec in `api/openapi.yaml` is authoritative.
- Generated files under `http/generated/` are never hand-edited.
- Every query is scoped by `tenant_id`.
Adım 2: Her kuralın gerekçesini ekleyin
Rationale: direct DB access from handlers previously bypassed audit
logging and tenant checks.
Adım 3: AGENTS.md ve CLAUDE.md’den referans verin
Read `DESIGN.md` before changing architecture, API contracts,
transactions, generated code, or domain rules.
Adım 4: PR şablonuna kontrol ekleyin
## Design impact
- [ ] This PR changes architecture, API contract, transaction behavior,
domain invariants, or generated code rules.
- [ ] If yes, `DESIGN.md` was reviewed and updated.
Adım 5: İlk ay sadece ihlal yakalayın
Başlangıçta dosyayı mükemmelleştirmeye çalışmayın. Review sırasında her tekrar eden aracı hatasını DESIGN.md kuralına dönüştürün.
Sonuç
-
DESIGN.md, kodunuzun neden böyle tasarlandığını kaydeder. -
AGENTS.mdveCLAUDE.mdyerine geçmez; onları tamamlar. - Kuralları kısa, test edilebilir ve mutlak ifadelerle yazın.
- API ve backend servislerinde özellikle değerlidir: OpenAPI sözleşmesi, transaction sınırları, idempotency, tenant izolasyonu ve hata modeli gibi görünmez kuralları açık hale getirir.
- PR sürecine bağlanmazsa çürür.
- En büyük backend kazanımı, OpenAPI dosyasını yetkili kaynak ilan etmektir.
- Önce sözleşmeyi tasarlamak, sonra aracıya o sözleşmeye göre kod yazdırmak daha güvenilir sonuç verir. Bunun için Apidog’u indirin.
Sıkça Sorulan Sorular
DESIGN.md, AGENTS.md gibi resmi bir standart mıdır?
Hayır. AGENTS.md, Linux Vakfı’nın Agentic AI Vakfı tarafından denetlenen tanımlı ve yaygın bir formattır. DESIGN.md ise ARCHITECTURE.md ve ADR’lere benzeyen bir topluluk konvansiyonudur. Standarttan çok uygulanabilir bir kalıp olarak düşünün.
AGENTS.md veya CLAUDE.md varsa DESIGN.md’ye ihtiyaç var mı?
Mimarinizde açık olmayan kısıtlar varsa evet. AGENTS.md ve CLAUDE.md kısa ve operasyonel kalmalıdır. Derin mimari gerekçe DESIGN.md içinde durmalı ve bu dosyalardan referans alınmalıdır. Operasyonel dosya için AGENTS.md dosyaları nasıl yazılır yazısına bakabilirsiniz.
DESIGN.md, ARCHITECTURE.md’den nasıl farklıdır?
Fark çoğunlukla hedef kitle ve yazım tarzıdır. ARCHITECTURE.md genellikle insan katkıda bulunanlara yönelik daha geniş bir mimari haritadır. DESIGN.md, kodlama aracılarını da hedeflediği için daha bildirimsel, daha kısa ve değişmez odaklı yazılır.
DESIGN.md ne kadar uzun olmalı?
Aracıların sık yanlış yaptığı kararları kapsayacak kadar uzun, her satırın değer taşıyacağı kadar kısa olmalı. İki ila dört sayfalık net kurallar, on beş sayfalık mimari anlatıdan daha kullanışlıdır.
Aracının DESIGN.md’yi okumasını nasıl sağlarım?
Aracının başlangıçta yüklediği dosyalardan referans verin.
Claude Code için:
@DESIGN.md
AGENTS.md için:
Read `DESIGN.md` before structural or API contract changes.
Tüm içeriği kısa talimat dosyalarına kopyalamayın; referans verin.
Aracı DESIGN.md’ye her zaman uyacak mı?
Hayır. Bu dosyalar zorunlu kural motoru değildir; modele verilen bağlamdır. Bu yüzden kuralları net yazın, çelişki durumunda ne yapılacağını belirtin ve review sürecinde ihlalleri DESIGN.md maddesine referansla düzeltin.
DESIGN.md API sözleşme sorunlarına gerçekten yardımcı olur mu?
Evet. En değerli kullanım, OpenAPI dosyasını yetkili kaynak ilan etmektir. Böylece aracı şema icat etmek veya generated type dosyalarını elle düzenlemek yerine sözleşmeye uyar. Bu sözleşmeyi önce Apidog gibi bir araçta tasarlamak, DESIGN.md için net bir hedef oluşturur.
DESIGN.md depoda nerede bulunmalı?
Genellikle depo kökünde:
README.md
AGENTS.md
CLAUDE.md
DESIGN.md
Monorepo kullanıyorsanız kökte sistem genelindeki kararları, paketlerde ise yerel mimari kuralları tutabilirsiniz.
Top comments (0)