> ## Documentation Index
> Fetch the complete documentation index at: https://docs.azalt.co/llms.txt
> Use this file to discover all available pages before exploring further.

# ActivityDefinition

> Özel UI ile yeniden kullanılabilir hesaplama şablonları

ActivityDefinition'lar bir aktivitenin nasıl toplanacağını ve hesaplanacağını tanımlar. Her tanım; giriş şeması, hesaplama fonksiyonu ve React UI bileşeninden oluşur ve birden fazla form/site'da yeniden kullanılabilir.

## Hızlı Başlangıç

1. Yeni ActivityDefinition oluşturun (Özelleştirme → Activity Definitions → New)
2. Girişleri tanımlayın (manuel veya Smart CSV ile)
3. Hesaplama kodunu yazın (`{ value, metadata }` döndüren async fonksiyon)
4. UI'yi oluşturun (`ActivityUI` → `onAddActivity(values)` çağırır)
5. Test bağlamı ile önizleyin → Kaydedin

Minimal hesaplama şablonu:

```ts theme={null}
async function calculate(inputValues) {
  const { electricityKwh = 0, gridRegion } = inputValues;
  const ef =
    (await $datasets.getCoefficient(
      "grid-emission-factors",
      String(gridRegion || "").toLowerCase(),
      "kgCO2ePerKWh",
      $year,
    )) ?? 0;
  return { value: electricityKwh * ef, metadata: { gridRegion, ef, year: $year } };
}
```

Minimal UI şablonu:

```tsx theme={null}
function ActivityUI({ onAddActivity }) {
  const [values, setValues] = React.useState({ electricityKwh: 0, gridRegion: "" });
  const handleAddActivity = () => onAddActivity(values);
  return (
    <div className="space-y-3">
      <NumberInput label="Elektrik (kWh)" value={values.electricityKwh}
        onChange={(v) => setValues((s) => ({ ...s, electricityKwh: Number(v ?? 0) }))} min={0} />
      <DatasetItemSelector datasetName="grid-emission-factors" value={values.gridRegion || null}
        onChange={(opt) => setValues((s) => ({ ...s, gridRegion: opt?.name ?? "" }))}
        placeholder="Bölge arayın…" />
      <Button onClick={handleAddActivity}>Aktivite Ekle</Button>
    </div>
  );
}
```

## Neleri İçerir?

* Giriş şeması: UI'nin toplaması gereken tipli, zorunlu/opsiyonel alanlar
* Hesaplama kodu: sayısal bir değer ve meta veriyi üreten async JS fonksiyonu
* UI kodu: kullanıcıların değer girdiği React bileşeni

### Giriş Şeması

Aşağıdaki sade şema uygulama genelinde kullanılır (doğrulama, UI oluşturma, CSV tahmini vb.):

```ts theme={null}
const inputs = [
  { name: "electricityKwh", type: "number", required: true, example: 1200 },
  { name: "gridRegion", type: "string", required: true, example: "Türkiye" },
  { name: "notes", type: "string", required: false, example: "sayaç 3" },
];
```

Tipler: `"number" | "string"`. Her girişte `name`, `type`, `required` ve opsiyonel `example` bulunur.

### Girdi Adlandırma Rehberi

* camelCase kullanın (ör.: `fuelType`, `electricityKwh`).
* Boşluk/özel karakterlerden kaçının. Smart CSV başlıkları otomatik olarak camelCase'e temizler.
* İsimleri stabil tutun; dışa aktarımdaki sütunlar bu isimlerle gelir.
* `example` değerleri tespiti ve önizlemeyi iyileştirir.

### Hesaplama Kodu

Hesaplama, tam bir fonksiyon deklarasyonu olarak kaydedilir ve mutlaka `{ value, metadata }` döndürür.

```ts theme={null}
// Gerekli format:
// async function calculate(inputValues) { /* ... */ }
async function calculate(inputValues) {
  const { electricityKwh, gridRegion } = inputValues;

  if (electricityKwh == null || electricityKwh < 0) {
    throw new Error("electricityKwh sıfırdan büyük eşit olmalıdır");
  }

  // Fonksiyon içinde mevcut bağlam yardımcıları:
  // $datasets, $kpis, $sites, $year, $period (YEARLY|QUARTERLY|MONTHLY), $periodUnit, $siteId
  const factor = await $datasets.getCoefficient(
    "grid-emission-factors",
    gridRegion,
    "kgCO2ePerKWh",
    $year,
  );

  const ef = factor ?? 0;
  const value = electricityKwh * ef;

  return {
    value,
    metadata: { gridRegion, factor: ef, year: $year },
  };
}
```

Sunucu, `value` ve sayısal meta verideki NaN/Infinity değerlerini `0`'a çevirir. Giriş doğrulama hatalarında anlaşılır `Error` mesajları fırlatın (UI bunları kullanıcıya gösterir).

### UI Bileşeni

UI, tek prop alan `ActivityUI` adlı bir React bileşenidir: `onAddActivity(values)`. Kullanıcı gönderdiğinde bu fonksiyon çağrılır.

```tsx theme={null}
function ActivityUI({ onAddActivity }: { onAddActivity: (values: any) => void }) {
  const [values, setValues] = React.useState({ electricityKwh: 0, gridRegion: "" });

  return (
    <div className="space-y-3">
      <NumberInput
        label="Elektrik (kWh)"
        value={values.electricityKwh}
        onChange={(v) => setValues((s) => ({ ...s, electricityKwh: Number(v ?? 0) }))}
        min={0}
      />
      <DatasetItemSelector
        datasetName="grid-emission-factors"
        value={values.gridRegion || null}
        onChange={(opt) => setValues((s) => ({ ...s, gridRegion: opt?.name ?? "" }))}
        placeholder="Bölge arayın…"
      />
      <Button onClick={() => onAddActivity(values)}>Aktivite Ekle</Button>
    </div>
  );
}
```

Notlar

* Bir giriş, bilinen bir dataset'ten seçimi ifade ediyorsa `DatasetItemSelector` kullanın (hesaplama kodundaki dataset adıyla aynı olmalıdır).
* UI ve hesaplama kodunu taslak/iyileştirme için AI yardımcısı mevcuttur; kodu her zaman manuel düzenleyebilirsiniz.

### UI Kod Sözleşmesi

* Snippet içinde `function ActivityUI({ onAddActivity }) { ... }` tanımlayın.
* Tıklama ile gönderin: `onClick={handleAddActivity}`; varsayılan form submit akışını kullanmayın.
* İçe aktarma yok; kapsamda sunulan bileşenleri kullanın (Mantine ve `DatasetItemSelector`).
* Canlı çalışma zamanı için bileşeni bağımsız tutun.

## Akıllı CSV Girdi Tespiti

Yeni bir tanım oluştururken CSV örneğinden girişleri hızlıca çıkartabilirsiniz:

* Yeni Activity Definition sayfasında “Smart” sekmesine bir CSV dosyası yükleyin.
* Sistem başlık ve örnek satırlardan alan adlarını/tiplerini ve örnek değerleri çıkarır.
* Üretilen “AI notları” UI oluşturmayı besleyebilir. Sonrasında Manuel sekmeye geçip düzenleyebilirsiniz.

Bu akış, yukarıdaki şemayı doldurur; sadece `name`, `type`, `required` ve opsiyonel `example` alanları desteklenir.

## Önizleme ve Test Bağlamı

Hesaplama ve UI sekmelerinde gerçek verilerle önizleme yapabilirsiniz:

* Hesaplama önizlemesi, dataset/KPI/site erişimini güvenli sunucu API'leri üzerinden kullanır.
* Test bağlamını ayarlayın: `year`, `period` (YEARLY/QUARTERLY/MONTHLY), `periodUnit`, `siteId`.
* Hesaplamada yapılan dataset/KPI/site çağrılarında `await` kullanılmalıdır.

## Genel/Özel Tanımlar

* Özel (varsayılan): yalnızca organizasyonunuza görünür.
* Genel (isCommon): tüm organizasyonlara açık. Genel tanım oluşturmak için ADMIN rolü gerekir.

## Hesaplamada Kullanılabilen Yardımcılar

* `$datasets`: `getItem`, `getDataset`, `getCoefficient`, `getCoefficients`
* `$kpis`: `getIndicator`, `getIndicatorById`, `getAllIndicators`, `getIndicatorsByTag`, `getIndicatorVariables`
* `$sites`: `getSite`, `getSiteByName`, `getAllSites`, `getChildSites`, `getSitesByCity`, `getSitesByTag`, `getTotalFloorArea`, `getTotalEmployees`
* `$year`, `$period`, `$periodUnit`, `$siteId`

Tüm erişimler güncel organizasyon bağlamında satır düzeyi güvenlikle kısıtlanır.

## Form Entegrasyonu

* ACTIVITY form elementi ekleyip bir ActivityDefinition ile ilişkilendirin.
* Elementin `key` değeri, bu tanım için aktivite ekleme/ithal/yeniden hesaplama işlemlerinde kullanılır.
* UI kodu inline render edilir ve `onAddActivity(values)` çağırarak hesaplama sonrası yeni bir Activity oluşturur.

İş akışı

* Onay gerektiren iş akışında, ilgili periyottaki gönderimler `COMPLETED` olur; aksi halde kayıtlar anında `APPROVED` durumundadır.

### Ne Zaman Yeniden Hesaplamalı?

* Hesaplama mantığını güncelledikten sonra mevcut aktiviteleri hizalamak için toplu yeniden hesaplama (`activities.recalculateActivities`) kullanın (site/yıl/periyot filtreleri ile).
* Hesaplamada kullanılan dataset'ler değiştiyse ilgili periyotlar için yeniden hesaplayın.

## İyi Uygulamalar

* Girişleri erken doğrulayın ve anlaşılır hata mesajları fırlatın.
* Her zaman `{ value: number, metadata: Record<string, any> }` dönün.
* Dataset adlarını UI ve hesaplama kodunda tutarlı kullanın.
* Mümkünse meta veride sayısal değerleri tercih edin (grafik/filtrelerde kolaylık sağlar).
* Örnek değerler (`example`) UI/CSV tespitini ve ön izlemeyi iyileştirir.

**2. Şema Tasarımı**: Giriş/çıktı veri yapılarını tanımlayın

**3. Mantık Geliştirme**: Hesaplama fonksiyonunu yazın ve test edin

**4. UI Tasarımı**: Kullanıcı deneyimini optimize edin

**5. Test ve Doğrulama**: Çeşitli veri setleriyle test edin

**6. Dağıtım**: Organizasyon genelinde kullanım için yayınlayın

## Operasyonel Notlar

**Tutarlılık**: Aynı hesaplama mantığı tüm kullanımlarda aynı sonuçları sağlar

**Verimlilik**: Hesaplama mantığını yeniden yazmak yerine yeniden kullanın

**Kalite**: Anlaşılır doğrulama ve meta verilerle ölçülebilirlik

**Uyumluluk**: Standart hesaplama yöntemlerini uygulayın

**Şeffaflık**: Hesaplama fonksiyonu ve metadata, varsayımları görünür kılar

## Sorun Giderme

* “Function parse failed” → Tam `async function calculate(inputValues) { ... }` kaydettiğinizden emin olun.
* “{ value, metadata } dönmeli” → `{ value: number, metadata: object }` döndürün.
* “Eksik dataset öğesi” → Yedek kullanın: `const ef = (await $datasets.getCoefficient(...)) ?? 0`.
* NaN/Infinity → Sayısal girdileri doğrulayın; sunucu 0'a normalleştirir fakat kök nedeni düzeltin.
* Erişim hatası → Site erişimi/filtreleri kontrol edin.

## Performans İpuçları

* Çoklu katsayım için `$datasets.getCoefficients(dataset, $year)` ile tek seferde alın ve tekrar kullanın.
* Sık döngülerde tekrar tekrar `await` kullanmaktan kaçının.
* Metadata'yı kısa tutun; yalnız gerektiğinde detaylandırın.

## Metadata Kuralları

* Birimler ve kaynakları ekleyin (ör.: `emissionFactorKgCO2ePerKWh`, `factorSource: "EPA"`).
* Sayısal alanları sayısal tutun; metinleri etiket/kimlik için kullanın.
