---
name: service-catalog
description: Backstage/Port/Cortex Internal Developer Platform (IDP) — service catalog ownership + lifecycle + tier + scorecard + tech radar + self-service template + API discovery + dependency graph. "Sahipsiz servis orphan" disipline.
---

# Service Catalog & IDP

## Ortak Doktrin

`agents/shared/severity-rubric.md` ve `agents/shared/escalation-matrix.md`
default-load sayılır (`agents/coordination.md` §11). Bu skill'in çıktısı
**Critical / High / Medium / Low + kanıt** formatında olmak zorunda — spekülatif
Critical yasak. Sahiplik dışı bulgu ilgili agent'a delege; karar yetkisi eşiği
aşılırsa **kullanıcı onayı zorunlu**.

## Felsefe

- **Catalog = single source of truth.**
- **Ownership zorunlu** — orphan = incident'ta sahipsiz.
- **Lifecycle explicit** — experimental / production / deprecated.
- **Tier-based policy** — tier-1 farklı, tier-3 farklı.
- **Scorecard görünür** — sağlık gauge.
- **Tech radar opinionated** — adopt/trial/assess/hold.
- **Self-service paved road** — yeni servis template'ten.

## Ne Zaman Kullanılır

- Yeni cluster / org IDP kurulum (Backstage install)
- Catalog drift audit (sahipsiz / lifecycle belirsiz)
- Scorecard quarterly review
- Tech radar revision
- Self-service template ekleme (yeni stack adoption)
- Migration: ad-hoc inventory → IDP
- Incident sonrası "downstream impact bilinmedi" → dependency graph fix
- Org büyümesi → yeni team / domain catalog entry

## Workflow

### 1) IDP kurulum (greenfield)

```bash
# Backstage
npx @backstage/create-app
# DB postgres backend
# auth github / google
# catalog locations git URL

# k8s deploy
kubectl create ns backstage
helm install backstage backstage/backstage -n backstage \
  --values values-production.yaml
```

`values-production.yaml`:

- replicaCount: 2 (HA)
- postgresql.persistence.size: 50Gi
- ingress.tls (TLS termination)
- auth provider GitHub OAuth
- catalog locations Git URL list

### 2) Discovery — current state

```bash
# Repo scan
find . -name "catalog-info.yaml" | wc -l
# vs total repo count

# Orphan tarama
for repo in $(gh repo list acme --limit 200 --json name -q '.[].name'); do
  if ! gh api repos/acme/$repo/contents/catalog-info.yaml >/dev/null 2>&1; then
    echo "ORPHAN: $repo"
  fi
done
```

### 3) Component entity template

```yaml
# catalog-info.yaml her repo root
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: REPLACE_SERVICE
  title: REPLACE Title
  description: REPLACE
  annotations:
    github.com/project-slug: acme/REPLACE
    datadog.com/dashboard-url: https://...
    pagerduty.com/integration-key: ...
    backstage.io/techdocs-ref: dir:.
  tags: [REPLACE_STACK, REPLACE_TIER_TAG]
spec:
  type: service
  lifecycle: production
  owner: group:REPLACE_TEAM
  system: REPLACE_SYSTEM
  tier: REPLACE_TIER_INT
  providesApis: [REPLACE_API_NAME]
  consumesApis: [REPLACE_CONSUMED_API]
  dependsOn: [resource:postgres-primary, resource:redis-session]
```

CI gate (`.github/workflows/catalog-check.yml`):

```yaml
- name: Validate catalog-info.yaml
  run: |
    test -f catalog-info.yaml || { echo "Missing catalog-info.yaml"; exit 1; }
    yq '.spec.owner' catalog-info.yaml | grep -v '^null$' || { echo "Owner empty"; exit 1; }
    yq '.spec.lifecycle' catalog-info.yaml | grep -E "(experimental|production|deprecated)" || exit 1
    yq '.spec.tier' catalog-info.yaml | grep -E "^[1-4]$" || exit 1
```

### 4) Group + Domain + System

`catalog/groups.yaml`:

```yaml
apiVersion: backstage.io/v1alpha1
kind: Group
metadata: { name: payments-team }
spec:
  type: team
  parent: group:engineering
  members: [alice, bob]
  profile: { email: payments@acme.com }
---
apiVersion: backstage.io/v1alpha1
kind: Domain
metadata: { name: commerce }
spec: { owner: group:engineering }
---
apiVersion: backstage.io/v1alpha1
kind: System
metadata: { name: payments-platform }
spec: { owner: group:payments-team, domain: commerce }
```

### 5) Scorecard

Backstage Tech Insights plugin veya OpsLevel / Cortex:

```yaml
# scorecard.yaml
checks:
  - id: has_slo
    name: SLO defined
    factRetriever: backstage-tag-fact-retriever
    rule: factRetriever.tag.includes("tier-1") implies entity.metadata.annotations["slo.acme.com/spec"]

  - id: has_runbook
    rule: entity.metadata.links.some(l => l.title === "Runbook")

  - id: deps_no_critical_cve
    factRetriever: snyk
    rule: factRetriever.critical == 0

  - id: secret_scan_clean
    factRetriever: gitleaks
    rule: factRetriever.findings == 0

  - id: ci_green_last_10
    factRetriever: github-actions
    rule: factRetriever.success_rate_last_10 >= 0.7
```

Quarterly review: grade < C servisler P1 issue.

### 6) Tech radar

```yaml
# tech-radar/radar.yaml
- { name: Python, ring: adopt, quadrant: languages }
- { name: Go, ring: adopt, quadrant: languages }
- { name: Rust, ring: trial, quadrant: languages, note: "prod 2 servis sınır" }
- { name: PostgreSQL, ring: adopt, quadrant: data }
- { name: MongoDB, ring: hold, quadrant: data, note: "yeni use case yasak" }
```

Backstage Tech Radar plugin UI'da görünür.

### 7) Self-service template

```yaml
# templates/python-fastapi-service.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata: { name: python-fastapi-service }
spec:
  type: service
  parameters: [...]
  steps:
    - fetch:template (skeleton dir)
    - publish:github (repo create)
    - catalog:register (auto-import)
```

Paved road: production-ready Dockerfile + helm + workflows + observability
preset.

### 8) Dependency graph

`spec.dependsOn` + `spec.providesApis` + `spec.consumesApis` →
Backstage UI relationship graph. Incident'ta tek tık downstream.

### 9) Migration: ad-hoc → IDP

```text
Phase 1 (2 hafta): IDP install + auth + catalog seed (5 pilot servis)
Phase 2 (1 ay): Top-20 servis catalog-info.yaml + group/domain
Phase 3 (1 ay): Scorecard + tech radar publish
Phase 4 (1 ay): Self-service template + paved road
Phase 5 (continuous): Orphan tarama monthly + scorecard quarterly
```

### 10) Permissions

```yaml
permission policy:
  - resource: catalog-entity
    action: update
    rule: HAS_OWNER_MEMBERSHIP
  - resource: scaffolder-template
    action: execute
    rule: ANY_AUTHENTICATED_USER
```

## Checklist

- [ ] IDP install (Backstage / Port / Cortex)
- [ ] Catalog seed (component + group + domain + system + resource + API)
- [ ] `catalog-info.yaml` her repo root (CI gate)
- [ ] Ownership boş yok (orphan list = 0)
- [ ] Lifecycle stage explicit (experimental sustained > 6 ay alarm)
- [ ] Tier atanmış (1-4)
- [ ] Tier-based policy (chaos / DR / security cadence)
- [ ] Scorecard 5 kategori (production-readiness, obs, security, quality, doc)
- [ ] Tech radar quarterly review
- [ ] Self-service template (en az 3: python, node, go)
- [ ] API entity (OpenAPI ref)
- [ ] TechDocs build
- [ ] Dependency graph görünür
- [ ] Permissions (owner edit, all read)
- [ ] Migration faz planı (varsa ad-hoc → IDP)

## Antipattern

- **Catalog yok**.
- **Ownership boş / multi**.
- **Lifecycle belirsiz**.
- **Tier yok**.
- **Scorecard yok**.
- **Tech radar yok**.
- **Self-service template yok**.
- **API discovery yok**.
- **Catalog drift** (schema değişti güncellenmedi).
- **Permission açık** (herkes edit).
- **Sunset plan yok** (deprecated sustained).
- **Dependency graph eksik**.
- **Wiki "service inventory"** IDP yerine geçer sanılması.

## Örnek Agent Davranışı

```text
User: /catalog-audit
Agent (platform-engineer + architecture-cartographer):
1. 147 repo bulundu, 89'unda catalog-info.yaml var (61%).
2. 58 orphan repo:
   - 23 deprecated/abandoned (sunset karar gerek)
   - 14 internal tool (tier-3 catalog-info gerek)
   - 21 active critical/important (acil sahip atama)
3. Ownership audit: 89 catalog'lu repo'nun 8'i owner: group:xxx-team (yok)
   → 8 group eksik.
4. Lifecycle: 31 experimental, 4 deprecated, 54 production.
   3 experimental > 6 ay sustained → review.
5. Tier eksik: 12 component tier alanı yok.
6. Scorecard taranınca: 18 < C (production-readiness gap).
7. Tech radar: yok; 5 farklı Python web framework adopt'da → opinion gerek.

Findings:
- Critical: 21 active orphan repo (incident sahipsiz)
- Critical: 8 catalog'lu repo owner non-existent group
- High: 12 tier eksik (policy uygulanamıyor)
- High: 18 component scorecard < C
- Medium: 3 experimental 6 ay sustained
- Medium: Tech radar yok

Action items: 11 issue
```

## Çıktı Formatı

```markdown
# Service Catalog & IDP: <org | cluster>

## Catalog inventory
- Total repo / catalog'lu / orphan
- Group / Domain / System sayısı

## Ownership audit
- Sahipsiz component
- Non-existent group owner

## Lifecycle distribution
- Experimental / production / deprecated breakdown
- Long-running experimental flag

## Tier distribution
- Tier-1/2/3/4 sayısı
- Tier eksik component

## Scorecard
- Grade A/B/C/D/F breakdown
- < C component listesi

## Tech radar
- Adopt/Trial/Assess/Hold

## Self-service template
- Mevcut template + paved road

## Findings (Critical/High/Medium/Low)

## Action Items
| P | Aksiyon | Sahip | Bitiş | Issue |

## Migration plan (varsa)
```
