OCPP Charger Create — HTTP 500
POST /api/ocpp/chargers endpoint'i HTTP 500 dönüyorsa (manuel charger oluşturma form'unda "Hata: Internal server error") bu rehberi takip edin. PR #277 ile kök sebep çözüldü; aynı semptom tekrar görünüyorsa regression checklist'i geçin.
Semptom
- Frontend
/chargers/newform submit → "Hata: Internal server error" toast. - Network tab'inde
POST /api/ocpp/chargers→ 500 Internal Server Error. - Diğer OCPP endpoint'leri (
GET /api/ocpp/chargers,GET /api/ocpp/chargers/:id) çalışıyor — sadece CREATE endpoint'inde sorun.
Hızlı Tanı
1. Backend log
docker logs zeus-backend 2>&1 | grep -A 20 "create_charger"
Tipik hata trace:
sqlalchemy.exc.IntegrityError: (sqlalchemy.dialects.postgresql.asyncpg.IntegrityError)
<class 'asyncpg.exceptions.CheckViolationError'>:
new row for relation "devices" violates check constraint "ck_devices_chk_device_source"
DETAIL: Failing row contains (..., ocpp, ...).
[SQL: INSERT INTO devices (...) VALUES (...)]
Anahtar mesaj: violates check constraint "ck_devices_chk_device_source".
2. DB tarafında constraint'in mevcut hali
docker exec -it zeus-postgres psql -U postgres -d zeus -c \
"SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname='ck_devices_chk_device_source';"
4 değer (sorunlu):
CHECK ((device_source)::text = ANY (ARRAY['modbus'::text, 'zigbee'::text, 'virtual'::text, 'manual'::text]))
5 değer (çözülmüş):
CHECK ((device_source)::text = ANY (ARRAY['modbus'::text, 'zigbee'::text, 'virtual'::text, 'manual'::text, 'ocpp'::text]))
3. Alembic head'i kontrol
docker exec zeus-backend alembic current
# Beklenen: 0038_chk_device_source_ocpp (head)
Eğer 0037_add_ocpp_tables veya daha eski → migration apply edilmemiş.
Kök Sebep
0037_add_ocpp_tables migration'ı OCPP 1.6J şemasını (8 tablo + hypertable) eklerken devices.chk_device_source CHECK constraint listesine 'ocpp' eklemeyi atladı. Whitelist baseline'dan beri ('modbus', 'zigbee', 'virtual', 'manual') (4 değer).
Backend create_charger (backend/app/features/ocpp/service.py:305) yeni Charge Point kaydı oluştururken:
device = Device(
tenant_id=tenant_id,
name=payload.name,
device_source="ocpp", # ← whitelist'te yok
...
)
session.add(device)
await session.flush() # ← CheckViolationError burada fırlar
Sonuç: INSERT reddedilir, transaction rollback olur, FastAPI 500 döner.
Niye 0037 değil de 0038? 0037 zaten production'da apply edilmişti; düzeltme amaçlı ayrı migration daha güvenli (idempotent + alembic_version forward-only).
Niye CI'da yakalanmadı?
Charger create endpoint'i için integration testi yoktu (test gap). PR #277 ile schema-model contract test eklendi (backend/tests/integration/test_schema_model_contract.py) — gelecek incident'leri yakalar.
Çözüm — PR #277
1. 0038_chk_device_source_ocpp migration
backend/alembic/versions/0038_chk_device_source_ocpp.py — NOT VALID + VALIDATE pattern (production lock minimize):
# 1) Eski constraint DROP
ALTER TABLE devices DROP CONSTRAINT ck_devices_chk_device_source;
# 2) Yeni constraint NOT VALID — anlık metadata, satır taraması YOK
ALTER TABLE devices
ADD CONSTRAINT ck_devices_chk_device_source
CHECK (device_source IN ('modbus','zigbee','virtual','manual','ocpp'))
NOT VALID;
# 3) VALIDATE — ShareUpdateExclusiveLock; okuma/yazma trafiği bloklanmaz
ALTER TABLE devices VALIDATE CONSTRAINT ck_devices_chk_device_source;
Detay: Migration Rehberi — NOT VALID + VALIDATE.
2. MIGRATION_TARGET=head deploy.yml fix
.github/workflows/deploy.yml:244 — MIGRATION_TARGET="${MIGRATION_TARGET:-merge_sofar_mqtt}" → head.
Önceden 0037+ revisionlar otomatik deploy'a giremiyordu (workflow_dispatch override veya manuel SSH apply gerektiriyordu). Bu sebeple 0038 migration'ı deploy'a otomatik girebilsin diye varsayılan head'e taşındı. Detay: CI/CD Pipeline.
3. Schema-Model contract test
backend/tests/integration/test_schema_model_contract.py — 7 test, drift detection. App device_source literal'leri ⊆ DB whitelist invariant'ı CI'da doğrulanır.
Doğrulama Komutları
1. Migration apply
docker exec zeus-backend alembic current
# Beklenen: 0038_chk_device_source_ocpp (head)
# Eğer değilse:
docker exec zeus-backend alembic upgrade head
2. Constraint güncel mi
docker exec -it zeus-postgres psql -U postgres -d zeus -c \
"SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname='ck_devices_chk_device_source';"
# Beklenen: ARRAY içinde 'ocpp' var
3. End-to-end smoke (charger create)
# 1. Login → token al
TOKEN=$(curl -s -X POST https://enerji.kepmark.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"...","password":"..."}' | jq -r .access_token)
# 2. Charger create
curl -i -X POST https://enerji.kepmark.com/api/ocpp/chargers \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"cpid": "TEST-CP-01",
"vendor": "ZJ-Beny",
"model": "BCP-AT2N-P",
"serial_number": "SMOKE-001",
"name": "Smoke Test Charger"
}'
# Beklenen: 201 Created + charger objesi (id, cpid, ...)
4. Backend log temiz mi
docker logs zeus-backend --since 1m 2>&1 | grep -E "CheckViolation|create_charger" | head -10
# Beklenen: HİÇBİR CheckViolationError satırı
Regression Koruma
PR #277 ile gelen test_schema_model_contract.py artık drift'i CI'da yakalıyor. Eğer ileride birisi device_source="<yeni-değer>" ekler ama whitelist migration'ını unutursa CI fail eder:
# backend/tests/integration/test_schema_model_contract.py (özet)
def test_device_source_literals_subset_of_db_whitelist():
"""App device_source literal'leri DB whitelist'in alt kümesi olmalı."""
app_literals = collect_device_source_literals_in_app()
db_whitelist = parse_check_constraint_whitelist("ck_devices_chk_device_source")
drift = app_literals - db_whitelist
assert not drift, f"Schema-model drift: {drift} app'te var ama DB whitelist'inde yok"
Tekrar Görürsen Checklist
| Adım | Komut | Beklenen |
|---|---|---|
| Migration apply edildi mi? | alembic current | 0038_chk_device_source_ocpp |
| MIGRATION_TARGET head mi? | cat deploy.sh | grep MIGRATION_TARGET | ${MIGRATION_TARGET:-head} |
| Constraint güncel mi? | DB pg_constraint sorgusu | 'ocpp' whitelist'te |
| Contract test pass mi? | pytest -m "not integration" tests/integration/test_schema_model_contract.py | yeşil |
| Backend log temiz mi? | docker logs zeus-backend | grep CheckViolation | hiç satır yok |
Bilinen Issue (Follow-up)
alembic_version.version_num kolonu VARCHAR(32). İlk denememizde 0038_extend_chk_device_source_ocpp (34 char) StringDataRightTruncationError verdi → 0038_chk_device_source_ocpp (27 char) ile düzeltildi.
Follow-up: alembic_version VARCHAR(64) migration ayrı PR. Geçici workaround: revision id 32 char altında tut.