Skip to main content
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):
{
  "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? }
    • Returns activities with 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

// 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
curl -H "Authorization: Bearer YOUR_TOKEN" \
  --get \
  --data-urlencode "formId=FORM_ID" \
  --data-urlencode "key=energy_usage" \
  https://your.api/activities
Add activity
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
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
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.