Skip to main content

Telemetry Lifecycle

Bu sayfa, Cınga backend içinde bir telemetry paketinin veritabanı açısından nasıl yaşadığını tanımlar. Amaç yalnız tablo listesi vermek değil; her tablonun neden var olduğunu, kabul zincirindeki yerini, hangi veriyi tuttuğunu, hangi veriyi bilerek tutmadığını ve hangi alanların ne amaçla eklendiğini netleştirmektir.

Bu doküman koda başlamadan önce veri sözleşmesini sabitlemek içindir. Bu nedenle burada yazılanlar sadece açıklama değil, davranış kontratıdır.

Genel Akış

Bu akışta temel roller şunlardır:

  • raw_data: ingress journal
  • streams: accepted telemetry event
  • measurement.*: enerji odaklı typed measurement persistence
  • measurements: generic düşük yoğunluklu measurement persistence
  • device_runtime_state: son canlı çalışma özeti
  • device_register_state: son register snapshot
  • ledger_transactions: best-effort integrity trail

1. raw_data

raw_data, sisteme gelen paketin ilk ve en ham journal kaydıdır. Bu tablonun görevi accepted veri üretmek değil, giriş izini kaybetmemektir.

Neden vardır?

  • cihazdan tam olarak ne geldiğini göstermek
  • bozuk JSON veya schema fail payload’ları saklamak
  • duplicate paketleri görünür kılmak
  • firmware ekibine ve operasyon ekibine hata inceleme zemini sunmak
  • accepted olmamış paketler için de tarihsel kayıt tutmak

Neden ayrı tablodur?

Çünkü accepted olmayan paketler de görünür olmalıdır. streams yalnız accepted olayları tutar; raw_data ise acceptance öncesi giriş jurnali görevi görür.

Ne zaman kayıt oluşur?

Bir paket sisteme ulaştığında en erken kalıcı kayıt burada açılır. Parse veya schema sonucu ne olursa olsun ingress izi bu tabloda görünmelidir.

Kolonlar

KolonTipNullAnlamı
idinthayırRaw journal kaydının birincil anahtarı
stream_idintevetBu raw kayıttan accepted stream üretildiyse ilgili stream ilişkisi
device_timetimestampevetPayload içinden çözümlenebilen cihaz zamanı
device_idvarchar(21)evetPayload içinden çözümlenebilen cihaz kimliği
client_ipvarchar(45)evetPaketin geldiği IP bilgisi
raw_packtextevetCihazdan geldiği haliyle wire payload
pack_sizeintevetHTTP body boyutu
valid_packbooleanhayırParse + schema açısından accepted aday olup olmadığı
validation_notevarchar(255)evetHata veya açıklama notu
stream_timetimestamphayırSistemin paketi aldığı/işlediği zaman

Önerilen ek kolonlar

Bu tablo için aşağıdaki alanlar eklenmesi önerilir:

KolonTipNeden gerekli?
ingest_statusvarchar(30) / enumRaw kaydın neden accepted veya rejected olduğunu tek bakışta görmek için
failure_stagevarchar(30) / enumHatanın parse, schema, duplicate veya measurement aşamasında mı olduğunu ayırmak için

Önerilen ingest_status değerleri

DeğerAnlamı
receivedJournal kaydı oluştu, işleme başladı
invalid_jsonJSON parse edilemedi
schema_failedJSON parse edildi ama CPS geçmedi
duplicateDuplicate identity nedeniyle accepted zincire alınmadı
acceptedAccepted zincire girdi ve stream oluştu
failedAccepted zincire girdi ama sonraki aşamalardan birinde başarısız oldu

Örnek kayıtlar

Accepted raw örneği:

{
"id": 101,
"stream_id": 5001,
"device_time": "2026-04-03T10:29:50Z",
"device_id": "46000000C47CA670",
"client_ip": "10.10.1.25",
"raw_pack": "{\"command\":\"timed\",\"device_id\":\"46000000C47CA670\",\"Payload\":{...}}",
"pack_size": 512,
"valid_pack": true,
"validation_note": null,
"ingest_status": "accepted",
"failure_stage": null,
"stream_time": "2026-04-03T10:30:00Z"
}

Invalid JSON örneği:

{
"id": 102,
"stream_id": null,
"device_time": null,
"device_id": null,
"client_ip": "10.10.1.99",
"raw_pack": "{\"command\":\"timed\",\"Payload\":{\"VRMS\":[0,0,0]",
"pack_size": 128,
"valid_pack": false,
"validation_note": "JSON parse hatası",
"ingest_status": "invalid_json",
"failure_stage": "parse",
"stream_time": "2026-04-03T10:31:00Z"
}

Duplicate örneği:

{
"id": 103,
"stream_id": null,
"device_time": "2026-04-03T10:29:50Z",
"device_id": "46000000C47CA670",
"client_ip": "10.10.1.25",
"raw_pack": "{\"command\":\"timed\",\"device_id\":\"46000000C47CA670\",\"Payload\":{...}}",
"pack_size": 512,
"valid_pack": true,
"validation_note": "device_id + device_time + canonical hash eşleşti",
"ingest_status": "duplicate",
"failure_stage": "duplicate",
"stream_time": "2026-04-03T10:30:03Z"
}

Ne içermez?

  • canonical measurement kolonları
  • runtime state özeti
  • ledger sonucu
  • rule engine state’i

2. streams

streams, accepted telemetry olayının resmi tablosudur. Bu tabloda yalnız valid, accepted ve non-duplicate telemetry event’ler yer alır.

Neden vardır?

Çünkü downstream servislerin raw_data içindeki her journal kaydını yorumlaması gerekmez. Onlar yalnız accepted olaylarla ilgilenir.

Ne zaman kayıt oluşur?

Şu koşullar birlikte sağlandıktan sonra oluşur:

  • raw journal kaydı var
  • JSON parse başarılı
  • CPS schema validation başarılı
  • paket duplicate değil

Kolonlar

KolonTipNullAnlamı
idinthayırAccepted stream birincil anahtarı
device_idvarchar(21)hayırAccepted paketin cihazı
message_type_idintevetPaket tipi (timed, interrupt, alarm vb.)
sim_idintevetPaket o anda hangi SIM üzerinden geldiyse ilişki
ip_addressvarchar(45)evetKabul edilen isteğin IP bilgisi
payload_sizeintevetKabul edilen body boyutu
process_time_msfloatevetKabul zincirinin maliyeti
device_timetimestamphayırCihazın payload içinde bildirdiği zaman
stream_timetimestamphayırSistemin accepted event zamanı

Önerilen ek kolonlar

KolonTipNeden gerekli?
raw_idintStream’in hangi raw kayıttan türediğini net bağlamak için
ledger_statusvarchar(20) / enumLedger yazım sonucunu görünür kılmak için

ledger_status değerleri

DeğerAnlamı
pendingLedger henüz denenmedi
writtenLedger başarıyla yazıldı
failedLedger yazımı başarısız oldu
skippedBilinçli olarak atlandı

Örnek kayıt

{
"id": 5001,
"raw_id": 101,
"device_id": "46000000C47CA670",
"message_type_id": 1,
"sim_id": 1,
"ip_address": "10.10.1.25",
"payload_size": 512,
"process_time_ms": 18.4,
"device_time": "2026-04-03T10:29:50Z",
"stream_time": "2026-04-03T10:30:00Z",
"ledger_status": "pending"
}

Ne içermez?

  • wire raw payload
  • faz/harmonik measurement kolonları
  • duplicate paketler
  • invalid journal kayıtları

3. measurement.voltage

measurement.voltage, accepted enerji paketlerinin gerilim segmentini typed ve performanslı biçimde saklar.

Neden vardır?

Gerilim verisi faz, harmonik ve temel bileşen gibi çok sayıda ilişkili kolon üretir. Bu veriyi generic satır tablosunda tutmak pahalı ve okunaksız olur.

Kolonlar

KolonTipNullAnlamı
stream_idinthayırBu gerilim kaydının ait olduğu accepted stream
device_idvarchar(21)hayırCihaz kimliği
sequence_nointevetCihaz sequence alanı varsa
device_timetimestamphayırÖlçüm zamanı
sample_period_secinthayırÖrnekleme periyodu
is_validbooleanhayırSegment seviyesinde geçerlilik
vrms_r/s/tfloatevetFaz RMS gerilimleri
vrms_afloatevetOrtalama faz gerilimi
fqfloatevetŞebeke frekansı
vfund_r/s/tfloatevetTemel gerilim bileşenleri
vharm_*floatevetHarmonik bileşenler
create_timetimestamphayırKayıt zamanı
update_timetimestamphayırSon güncelleme

Örnek kayıt

{
"stream_id": 5001,
"device_id": "46000000C47CA670",
"sequence_no": 1,
"device_time": "2026-04-03T10:29:50Z",
"sample_period_sec": 900,
"is_valid": true,
"vrms_r": 229.4,
"vrms_s": 228.9,
"vrms_t": 230.1,
"vrms_a": 229.47,
"fq": 50.0,
"vfund_r": 229.1,
"vfund_s": 228.6,
"vfund_t": 229.8,
"vharm_r_3": 0.8,
"vharm_s_3": 0.7,
"vharm_t_3": 0.9
}

4. measurement.current

measurement.current, accepted enerji paketlerinin akım ve tepe akım segmentini tutar.

Neden vardır?

Akım verisi de gerilim gibi faz bazlı, harmonikli ve yoğun alan seti taşır. Ayrıca IPEAK ve IFUND gibi alt bileşenler operasyonel analizde kritik olduğu için ayrı tutulur.

Kolonlar

KolonTipNullAnlamı
stream_idinthayırAccepted stream ilişkisi
device_idvarchar(21)hayırCihaz kimliği
sequence_nointevetSequence değeri
device_timetimestamphayırÖlçüm zamanı
sample_period_secinthayırÖrnekleme periyodu
is_validbooleanhayırSegment validliği
irms_r/s/tfloatevetRMS akımları
irms_afloatevetOrtalama RMS akım
ipeak_r/s/tfloatevetFaz tepe akımları
ifund_r/s/tfloatevetTemel akım bileşenleri
iharm_*floatevetHarmonik akım bileşenleri
create_timetimestamphayırKayıt zamanı
update_timetimestamphayırSon güncelleme

Örnek kayıt

{
"stream_id": 5001,
"device_id": "46000000C47CA670",
"device_time": "2026-04-03T10:29:50Z",
"irms_r": 42.8,
"irms_s": 42.2,
"irms_t": 43.0,
"irms_a": 42.67,
"ipeak_r": 61.2,
"ipeak_s": 60.8,
"ipeak_t": 61.5,
"ifund_r": 42.3,
"ifund_s": 41.8,
"ifund_t": 42.6,
"is_valid": true
}

5. measurement.power

Bu tablo aktif, reaktif, görünür güç ve güç faktörü odaklı accepted enerji değerlerini taşır.

Kolonlar

KolonTipNullAnlamı
stream_idinthayırAccepted stream
device_idvarchar(21)hayırCihaz
sequence_nointevetSequence
device_timetimestamphayırÖlçüm zamanı
sample_period_secinthayırÖrnekleme periyodu
is_validbooleanhayırSegment validliği
p_*floatevetAktif güç alanları
q_*floatevetReaktif güç alanları
s_*floatevetGörünür güç alanları
pf_*floatevetGüç faktörü
pfund_*floatevetTemel güç faktörü
qfund_*floatevetTemel reaktif bileşen
create_timetimestamphayırKayıt zamanı
update_timetimestamphayırSon güncelleme

6. measurement.energy

Bu tablo enerji sayaçlarını accepted stream bazında saklar.

Neden vardır?

Enerji sayaçları diğer segmentlerden farklı olarak anlık değil, birikimli ve sayaç mantığında değerler üretir. Bu nedenle kendi segment tablosunda yaşaması daha doğrudur.

Kolonlar

KolonTipNullAnlamı
stream_idinthayırAccepted stream
device_idvarchar(21)hayırCihaz
sequence_nointevetSequence
device_timetimestamphayırÖlçüm zamanı
sample_period_secinthayırÖrnekleme periyodu
is_validbooleanhayırSegment validliği
ae_*bigintevetAktif enerji sayaçları
re_ind_*bigintevetEndüktif reaktif sayaçları
re_cap_*bigintevetKapasitif reaktif sayaçları
create_timetimestamphayırKayıt zamanı
update_timetimestamphayırSon güncelleme

7. measurements

measurements generic ve düşük yoğunluklu standart ölçümler için kullanılır. Bu tablo bütün telemetry verisinin ana deposu değildir.

Neden vardır?

Sıcaklık, nem, basınç, bazı register-türevi sayısal alanlar veya ileride enerji-dışı scalar veriler için esnek bir yapı gerekir.

Kolonlar

KolonTipNullAnlamı
idinthayırÖlçüm satırı anahtarı
stream_idinthayırAccepted stream ilişkisi
variable_idvarchar(30)hayırHangi değişken olduğu
valuedecimal(18,6)evetÖlçüm değeri
calibratedbooleanhayırKalibrasyon uygulanmış mı
synthesizedbooleanhayırSentez kuralıyla mı üretildi
create_timetimestamphayırOluşturma zamanı

Örnek kayıt

{
"id": 9001,
"stream_id": 5002,
"variable_id": "TEMP",
"value": 24.7,
"calibrated": false,
"synthesized": false,
"create_time": "2026-04-03T10:25:00Z"
}

Açık kural

Tasarım kuralı

Enerji odaklı çok kolonlu telemetry alanları measurement.* tablolarında tutulur. measurements generic tablo enerji için ikinci bir storage alanı olarak kullanılmaz.

8. device_runtime_state (önerilen tablo)

Bu tablo, cihazın son canlı çalışma özetini taşır. devices tablosundan ayrılması önerilir.

Önerilen kolonlar

KolonTipNullAnlamı
device_idvarchar(21)hayırCihaz kimliği
last_connection_ipvarchar(45)evetSon bağlantı IP’si
last_connection_timetimestampevetSon bağlantı zamanı
last_stream_idintevetSon accepted stream
last_raw_idintevetSon raw journal kaydı
last_device_timetimestampevetCihazın son bildirdiği zaman
last_seen_statusvarchar(30)evetSon sağlık/erişim özeti
update_timetimestamphayırSon güncelleme

Örnek kayıt

{
"device_id": "46000000C47CA670",
"last_connection_ip": "10.10.1.25",
"last_connection_time": "2026-04-03T10:30:00Z",
"last_stream_id": 5001,
"last_raw_id": 101,
"last_device_time": "2026-04-03T10:29:50Z",
"last_seen_status": "online",
"update_time": "2026-04-03T10:30:00Z"
}

9. device_register_state (önerilen tablo)

Bu tablo son register snapshot’ını tutar.

Önerilen kolonlar

KolonTipNullAnlamı
device_idvarchar(21)hayırCihaz kimliği
register_statusbigintevetSon durum register’ı
register_stopbigintevetSon stop register’ı
register_publishbigintevetSon publish register’ı
update_timetimestamphayırSon güncelleme

Örnek kayıt

{
"device_id": "46000000C47CA670",
"register_status": 5,
"register_stop": 0,
"register_publish": 1,
"update_time": "2026-04-03T10:30:00Z"
}

10. ledger_transactions

Accepted stream için best-effort integrity trail tablosudur.

Neden vardır?

  • accepted verinin hash-zincirli denetim izini tutmak
  • değişmezlik / audit ihtiyacına taban hazırlamak
  • cihaz bazlı zincirli kayıt oluşturmak

Kolonlar

KolonTipNullAnlamı
idbiginthayırLedger kaydı anahtarı
device_idvarchar(21)hayırCihaz
stream_idinthayırİlgili accepted stream
device_timetimestamphayırÖlçüm zamanı
payloadjsonhayırAccepted payload / snapshot
payload_hashvarchar(64)hayırPayload hash’i
previous_hashvarchar(64)hayırÖnceki zincir halkası
transaction_hashvarchar(64)hayırBu halkaya ait hash
source_signaturetextevetKaynak imzası varsa
create_timetimestamphayırOluşturma zamanı

Örnek kayıt

{
"id": 1,
"device_id": "46000000C47CA670",
"stream_id": 5001,
"device_time": "2026-04-03T10:29:50Z",
"payload_hash": "1111111111111111111111111111111111111111111111111111111111111111",
"previous_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"transaction_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"create_time": "2026-04-03T10:30:01Z"
}

Ledger fail olursa

Bu modelde ledger yazımı kabul zincirini geri almaz.

Sonuç:

  • accepted stream kalır
  • measurement kalır
  • runtime state kalır
  • ledger eksik kalabilir
  • streams.ledger_status = failed olur

Duplicate Identity Spesifikasyonu

Duplicate kararı şu üçlüden oluşur:

  • device_id
  • device_time
  • canonical_payload_hash

Bu üçü aynıysa paket duplicate kabul edilir.

Duplicate olduğunda

  • raw_data kaydı tutulur
  • ingest_status = duplicate
  • stream oluşmaz
  • measurement yazılmaz
  • runtime state güncellenmez
  • warning/log üretilebilir

Transaction Boundary

Boundary 1 — Journal

raw_data journal kaydı erken ve bağımsız yazılır.

Boundary 2 — Accepted transaction

Aşağıdakiler aynı transaction içinde değerlendirilir:

  • streams insert
  • measurement.* insertleri
  • measurements insertleri
  • device_runtime_state update
  • device_register_state update
  • raw_data.ingest_status = accepted

Bu zincirin herhangi bir noktasında hata olursa accepted transaction rollback olur.

Boundary 3 — Best-effort sonrası işler

  • ledger write
  • reaction side-effects
  • bazı secondary projection’lar

Failure Matrix

Durumraw_datastreamsmeasurementruntime stateledgerSonuç
invalid JSONvaryokyokyokyokjournal kalır
schema failvaryokyokyokyokjournal kalır
duplicatevaryokyokyokyokduplicate journal kalır
stream create failvarrollbackyokyokyokraw failed işaretlenir
measurement failvarrollbackrollbackrollbackyokraw failed işaretlenir
runtime failvarrollbackrollbackrollbackyokraw failed işaretlenir
ledger failvarvarvarvarfailedaccepted event korunur

Sonuç

Telemetry lifecycle modeli, Cınga backend içindeki accepted veri akışının veritabanı sözleşmesini tanımlar. Burada raw_data giriş jurnali, streams accepted event, measurement.* enerji odaklı typed persistence, measurements generic persistence, runtime tabloları latest state, ledger_transactions ise best-effort integrity trail olarak konumlanır.

Bu ayrım, kod yazarken hangi veri hangi tabloda doğar, hangi veri rollback olur, hangisi tarihsel kanıt olarak kalır ve hangisi yalnız en son durumu taşır sorularına net cevap üretir.