> ## 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.

# Activity

> Calculated records created from ActivityDefinitions

An Activity is a calculated record generated from an ActivityDefinition. It stores the original inputs, the computed numeric value, and any metadata returned by the calculation function. Activities are scoped to a form/site/year/period.

## Lifecycle

1. Choose a form element linked to an ActivityDefinition
2. Collect inputs via the ActivityDefinition’s UI
3. Run the ActivityDefinition’s `calculate` function on the server (on submit)
4. Persist the result as an Activity and link it to a FormElementSubmission
5. View, export, or recalculate as needed

## Data Model

Each Activity contains:

* `definitionId`: the ActivityDefinition used
* `input`: the submitted values (JSON)
* `value`: numeric result of the calculation
* `metadata`: calculation details (JSON)
* linkage to form submission, form element, site, year, period

Example (simplified):

```json theme={null}
{
  "definitionId": "ad_123",
  "input": { "electricityKwh": 1200, "gridRegion": "Türkiye" },
  "value": 432.0,
  "metadata": { "factor": 0.36, "year": 2025 }
}
```

## Working With Activities

Activities are managed via the Activities router (with REST mirrors):

* `activities.addActivity`
  * Input: `{ formId, key, siteId, year, periodUnit, input }`
  * Resolves the form element by `formId + key`, runs the linked ActivityDefinition’s calculation, saves the result.

* `activities.getActivities`
  * Input: `{ formId, key, siteIds?, years?, periodUnits?, limit?, offset? }`
  * `limit`: max results per request (default 100, max 1000)
  * `offset`: number of records to skip (default 0)
  * Returns `{ activities, pagination: { total, limit, offset, hasMore } }` where activities have parsed `input`/`metadata` and context (`siteId`, `siteName`, `year`, `periodUnit`).

* `activities.importActivities`
  * Bulk import; all rows must target elements linked to the same ActivityDefinition; runs per-row calculation with detailed error reporting.

* `activities.exportActivities`
  * CSV/XLSX export with consistent columns (see below).

* `activities.removeActivity`
  * Deletes an activity and its FormElementSubmission rows; applies workflow rules.

* `activities.recalculateActivity` / `activities.recalculateActivities`
  * Re-runs calculations using the current ActivityDefinition `calcCode` for a single or multiple activities.

Access control: all operations enforce site-level permissions. `$datasets/$kpis/$sites` helpers in calculations use server-side RLS for the current organization.

## Export Format

Exports include these columns in order:

* `activityId`, `site`, `year`, `periodUnit`, `value`
* Each input from the ActivityDefinition’s `inputs` array (as columns matching their names)
* `metadata_*` columns for each returned metadata key

Note: Only inputs defined in the ActivityDefinition schema appear as input columns. Additional values must be placed in `metadata` to be included.

Example columns:

* Context: `activityId`, `site`, `year`, `periodUnit`, `value`
* Inputs: `electricityKwh`, `gridRegion`, ... (from definition)
* Metadata: `metadata_factor`, `metadata_year`, ... (flattened keys)

## Import Rules & Errors

* All rows must reference form elements (via `key`) that share the same ActivityDefinition.
* Site access is validated per row.
* Errors are returned with row number and context (key/site/year/period) and a user-friendly message extracted from the calculation, e.g.: `Row 3 (energy - siteA 2024 Period 1): electricityKwh must be a non-negative number`.

## Recalculation

* Recalculation uses
  * the current ActivityDefinition `calcCode`,
  * the stored `input`, and
  * current context (site/year/period) and datasets.
* NaN/Infinity are normalized to `0` in both `value` and numeric `metadata` entries.

## UI & Spreadsheet

* The ActivityDefinition’s `uiCode` is rendered dynamically and calls `onAddActivity(values)` on submit.
* The spreadsheet view lists activities for the element with filters for site/year/period, showing input and metadata fields.

## Workflow & Status

* If the configured workflow requires approval, any add/remove/recalculate/import in a period marks all submissions in that period as `COMPLETED` (pending approval).
* Otherwise, submissions remain `APPROVED`.

## Dataset Lookup Example

```ts theme={null}
// Use dataset coefficients by name and year
async function calculate({ fuelType, consumption }) {
  const key = String(fuelType).toLowerCase();
  const ef =
    (await $datasets.getCoefficient("hotel-emission-factors", key, "kgCO2e", $year)) ?? 0;
  return { value: consumption * ef, metadata: { fuelType: key, ef, year: $year } };
}
```

## Error Handling & Quality

* Throw clear `Error` messages in the calculation for invalid inputs.
* Keep input names clean and consistent with the definition.
* Use `example` values in inputs to improve CSV detection and previews.

## Security

* Site access is enforced on all operations.
* `$datasets/$kpis/$sites` are server-provided helpers subject to org-level RLS.

## See Also

* ActivityDefinition (authoring inputs/UI/calc and preview)
* Activity Calculation Variables (context helpers and examples)
* Dataset Access Examples (end-to-end patterns)
* API Examples

Quick REST examples (replace `YOUR_TOKEN` and IDs):

List activities (paginated)

```bash theme={null}
curl -H "Authorization: Bearer YOUR_TOKEN" \
  --get \
  --data-urlencode "formId=FORM_ID" \
  --data-urlencode "key=energy_usage" \
  --data-urlencode "limit=100" \
  --data-urlencode "offset=0" \
  https://your.api/activities
```

Add activity

```bash theme={null}
curl -H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
  -X POST https://your.api/activities \
  -d '{
    "formId": "FORM_ID",
    "key": "energy_usage",
    "siteId": "SITE_ID",
    "year": 2025,
    "periodUnit": 1,
    "input": { "electricityKwh": 1200, "gridRegion": "Türkiye" }
  }'
```

Recalculate filtered set

```bash theme={null}
curl -H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
  -X POST https://your.api/activities/recalculate \
  -d '{ "formId": "FORM_ID", "key": "energy_usage", "year": 2025 }'
```

Export as CSV

```bash theme={null}
curl -H "Authorization: Bearer YOUR_TOKEN" \
  --get \
  --data-urlencode "formId=FORM_ID" \
  --data-urlencode "key=energy_usage" \
  --data-urlencode "format=csv" \
  https://your.api/activities/export
```

## Troubleshooting

* Add/import fails with a user error → The calculation likely threw `Error("...")`; fix inputs or calc logic per the message.
* Import reports multiple row errors → Use the row index and context in the error details to correct data.
* Recalc produced zeros → Check dataset values/keys for the target year; ensure fallbacks are in place.
* Export missing input column → Ensure the field exists in the ActivityDefinition `inputs` schema.

## Performance Tips

* Avoid repeated dataset lookups when a single `getCoefficients` suffices.
* Keep per-activity metadata small for faster exports.

## Metadata Conventions

* Prefer explicit keys and units (e.g., `efKgCO2ePerKWh`).
* Include `year`, `period`, or `siteId` when it aids downstream analysis.
