File Formats Reference
This document is the single reference for all JSON file formats consumed or produced by the application. It covers the template file system (used to seed new organizations), the import/export envelope (used by e/org), and the field-level constraints (enums, size limits, and cross-document rules) that both formats share.
For the HTTP routes, curl examples, and CSV ZIP format see org-import-export.
1. Template Files
Template files live in templates/{name}/ and are loaded by organizationFromTemplateCreate when spinning up a new organization from a preset. Each template is a set of three JSON files.
templates/
demo/
demo-selfOrganization.json
demo-organizations.json
demo-ropa-en.json
demo-ropa-de.json
...
upf/
upf-selfOrganization.json
upf-organizations.json
upf-ropa-ca.json
...
bfdi/
bfdi-selfOrganization.json
bfdi-organizations.json
bfdi-ropa-de.json
The shortName passed to organizationFromTemplateCreate becomes the new org's slug; it does not need to match the template folder name.
1.1 {name}-selfOrganization.json
Org-level metadata and configuration. All counters (highest*) must equal the highest ID actually used across the template data — they are monotonic sequence seeds that prevent ID reuse after the org is live.
{
"licenseStart": 0, // Unix ms timestamp — 0 = unset
"licenseEnd": 0, // Unix ms timestamp — 0 = unset
"licenseCost": 0,
"shortName": "bfdi", // seed value; overwritten by caller
"isBlocked": false,
"isPublic": true,
"isDemo": false,
"highestOuId": 3, // = max ouId used in any ropa file
"highestRopaId": 1, // = number of ropa locales
"highestActivityId": 6, // = max activityId used in any ropa file
"highestPartnerId": 2, // = max organizationId used in organizations file
"highestContractId": 0, // = max contractId used (0 if no contracts)
"contracts": [],
"ropas": [
{ "locale": "de", "ropaId": null, "isDefault": true }
// one entry per locale; exactly one isDefault=true
],
"defaultActivityAttributes": {
// pre-filled values applied when a user creates a new activity
// any valid activity field can appear here
"legalbasis": ["Contract"],
"dataCategories": ["Identification"],
"securityLevel": "medium",
...
},
"createdAt": "",
"updatedAt": "",
"schemaVersion": 12 // must match current schema version
}
Notes
licenseStart/licenseEndcan both be0here because templates bypass thelicenseEnd > licenseStartcross-check applied only to import envelopes.ropaIdinsideropas[]is alwaysnullin template files — resolved at creation time.
1.2 {name}-organizations.json
All partner organizations. organizationId: 0 is always the self-organization (the controller). All other entries are processors, joint controllers, or other partners.
{
"partners": [
{
"organizationId": 0, // 0 = self (required)
"organizationNameLong": "Musterfirma GmbH",
"organizationName": "MUSTER", // short label, 2–32 chars
"organizationColor": "#1D4ED8", // 6-digit hex
"organizationWebsite": "https://www.musterfirma.de",
"organizationPostalAddress": {
"addressLine1": "Musterstraße 1",
"addressLine2": "",
"city": "Berlin",
"stateProvince": "Berlin",
"postalCode": "10115",
"country": "DE" // ISO 3166-1 alpha-2, uppercase
},
"organizationLogo": null, // null or base64-encoded PNG
"organizationNotes": "...",
"organizationContacts": [
{
"contactId": 1,
"contactFirstname": "Datenschutzbeauftragte",
"contactLastname": "-",
"contactRole": "DPO",
"contactEmails": [
{ "email": "dpo@example.de", "description": "DPO", "isPrimary": true }
],
"contactPhoneNumbers": [
{ "countryCode": "+49", "phoneNumber": "3012345678",
"description": "Büro", "isPrimary": true }
],
"contactNotes": ""
}
],
"contractOrder": [] // ordered contractId list for this partner
},
{ "organizationId": 1, ... },
{ "organizationId": 2, ... }
],
"highestPartnerId": 2 // = max organizationId above
}
1.3 {name}-ropa-{locale}.json
One file per locale declared in selfOrganization.ropas[]. Contains the full processing activity tree.
{
"orgId": "", // blank — filled at creation time
"orgShortName": "bfdi", // template name
"locale": "de",
"ous": [
{
"ouName": "Personalwesen",
"ouColor": "#C084FC", // any CSS color string
"ouId": 1, // unique within this file, ≤ highestOuId
"activities": [
{
"activityId": 1, // unique within the OU, ≤ highestActivityId
"activityName": "Personalverwaltung",
"purposeShort": "...",
"purposeLong": "...",
"legalbasis": ["LegalObligation", "Contract"],
"legalbasisLong": "...",
"legalbasisSpecial": ["Employment"],
"dataCategories": ["Identification", "Professional", "Financial"],
"datasubjectCategories": "Beschäftigte",
"activityCategories": ["DataCollection", "DataStorage"],
"dataOrigin": "...",
"timeLimit": "...",
"profiling": false,
"communications": "...",
"communicationsLong": "...",
"controllers": [0], // organizationId references
"processors": [1], // organizationId references
"transfers": false,
"transfersLong": "...",
"securityLevel": "high",
"securityMeasuresLong": "...",
"active": true,
"createdAt": 0, // stamped at creation; 0 in templates
"updatedAt": 0
}
]
}
],
"createdAt": "",
"updatedAt": ""
}
2. Import / Export Envelope
The envelope format is used when uploading via e/org (the admin import route). It is a single self-contained JSON file.
{
"exportVersion": 1, // literal 1
"exportedAt": "2026-05-18T00:00:00.000Z", // ISO 8601 with timezone offset
"organization": {
"shortName": "bfdi",
"licenseStart": 0,
"licenseEnd": 4102444800000, // must be strictly > licenseStart
"licenseCost": 0,
"isBlocked": false,
"isPublic": true,
"isDemo": false,
"highestOuId": 3,
"highestActivityId": 6,
"highestPartnerId": 2,
"highestContractId": 0,
"schemaVersion": 12,
"defaultActivityAttributes": { ... },
"partners": [ ... ], // same shape as organizations.json
"contracts": [],
"ropas": [
{ "locale": "de", "isDefault": true }
// ropaId is ABSENT here — resolved at import time
],
"templates": [] // template refs ABSENT — rebuilt at import
},
"ropas": [
{
"orgShortName": "bfdi", // must match organization.shortName
"locale": "de",
"ous": [ ... ] // same ous shape as ropa template files
}
],
"templates": [] // Handlebars templates, empty if none
}
Key differences from template files
| Aspect | Template files | Import envelope |
|---|---|---|
licenseEnd > licenseStart | Not enforced | Required (cross-check fails if equal) |
organization.ropas[].ropaId | null present | Field absent |
organization.templates[] | Not present | Empty array [] |
ropas[].orgShortName | Not present (top-level field) | Required in each ROPA document |
contactFirstname min chars | Not validated | 2 chars minimum |
exportVersion / exportedAt | Absent | Required |
3. Field Reference
3.1 Enum values
All enum fields must use one of the listed string values. Empty string "" means "not specified" and is valid everywhere it appears.
legalbasis — Art. 6 DSGVO
| Value | GDPR basis |
|---|---|
"Consent" | Art. 6(1)(a) — Einwilligung |
"Contract" | Art. 6(1)(b) — Vertragserfüllung / vorvertragliche Maßnahmen |
"LegalObligation" | Art. 6(1)(c) — rechtliche Verpflichtung |
"VitalInterests" | Art. 6(1)(d) — lebenswichtige Interessen |
"PublicTask" | Art. 6(1)(e) — öffentliches Interesse / hoheitliche Aufgabe |
"LegitimateInterest" | Art. 6(1)(f) — berechtigte Interessen |
legalbasisSpecial — Art. 9 DSGVO (special categories)
| Value | GDPR basis |
|---|---|
"ExplicitConsent" | Art. 9(2)(a) — ausdrückliche Einwilligung |
"Employment" | Art. 9(2)(b) — Beschäftigung / Sozialschutz |
"VitalInterests" | Art. 9(2)(c) — lebenswichtige Interessen |
"NonProfit" | Art. 9(2)(d) — nicht gewinnorientierte Einrichtungen |
"PublicInformation" | Art. 9(2)(e) — offensichtlich öffentlich gemachte Daten |
"LegalClaims" | Art. 9(2)(f) — Geltendmachung von Rechtsansprüchen |
"SubstantialPublicInterest" | Art. 9(2)(g) — erhebliches öffentliches Interesse |
"Healthcare" | Art. 9(2)(h) — Gesundheitsvorsorge / medizinische Versorgung |
"PublicHealth" | Art. 9(2)(i) — öffentliche Gesundheit |
"Archiving" | Art. 9(2)(j) — Archivzwecke / Forschung / Statistik |
dataCategories
| Value | Category |
|---|---|
"Identification" | Namen, Adressen, Ausweisdaten |
"Characteristics" | Geburtsdatum, Staatsangehörigkeit, persönliche Merkmale |
"Professional" | Beruf, Qualifikationen, Arbeitsverhältnis |
"Social" | Familienstand, Hobbys, soziale Netzwerke |
"Financial" | Bankdaten, Gehalt, Steuerdaten |
"Commercial" | Verträge, Transaktionen, Kaufhistorie |
"SpecialEthnic" | Art. 9 — ethnische Herkunft |
"SpecialHealth" | Art. 9 — Gesundheitsdaten |
"SpecialBiometric" | Art. 9 — biometrische Daten |
"SpecialGenetic" | Art. 9 — genetische Daten |
"SpecialSexual" | Art. 9 — sexuelle Orientierung |
"SpecialUnion" | Art. 9 — Gewerkschaftszugehörigkeit |
"SpecialPolitical" | Art. 9 — politische Meinungen |
"SpecialReligious" | Art. 9 — religiöse Überzeugungen |
"SpecialCriminal" | Art. 10 — strafrechtliche Verurteilungen |
activityCategories
| Value | Activity type |
|---|---|
"DataCollection" | Erhebung |
"DataGeneration" | Generierung / Ableitung |
"DataAccess" | Zugriff / Abfrage |
"DataStorage" | Speicherung |
"DataCommunication" | Übermittlung / Weitergabe |
"DataDissemination" | Veröffentlichung / Verbreitung |
"DataErasure" | Löschung |
"DataRetention" | Archivierung / Aufbewahrung |
securityLevel
| Value | Meaning |
|---|---|
"high" | Hoch — sensible oder besondere Kategorien |
"medium" | Mittel — personenbezogene Standarddaten |
"low" | Niedrig — geringes Risiko |
"NA" | Nicht anwendbar |
Template types (for organization.templates[] and templates[])
| Value | Purpose |
|---|---|
"activityDeclaration" | Per-activity declaration page |
"activityInformation" | Privacy information sheet |
"ropaFrontPage" | ROPA cover / front page |
"ropaTOC" | ROPA table of contents |
3.2 Size constraints
Source of truth: src/constants/ropaAttributes.js. Enforced at three layers: Mongoose model, Zod import schema, and client-side form.
Activity fields
| Field | Min | Max | Notes |
|---|---|---|---|
activityName | — | 80 | ACTIVITY_NAME_MAX_LENGTH |
purposeShort | — | 512 | PURPOSE_SHORT_MAX_LENGTH |
purposeLong | — | 2048 | PURPOSE_LONG_MAX_LENGTH |
| All other text fields | — | 512 | TEXT_ATTRIBUTE_MAX_LENGTH (default) |
Note:
PURPOSE_SHORT_MAX_LENGTHis 512, not 80.
Organization / partner fields (import envelope only)
| Field | Min | Max | Notes |
|---|---|---|---|
organization.shortName | 2 | 32 | |
organizationName | 2 | 32 | Short label |
organizationNameLong | 2 | 100 | Full legal name |
organizationWebsite | — | 200 | |
organizationNotes | — | 200 | |
addressLine1 | 1 | 100 | |
addressLine2 | — | 100 | |
city | 1 | 50 | |
stateProvince | — | 50 | |
postalCode | 1 | 20 | |
country | 2 | 2 | ISO 3166-1 alpha-2, uppercase |
Contact fields (import envelope only)
| Field | Min | Max | Notes |
|---|---|---|---|
contactFirstname | 2 | 50 | "-" (1 char) fails — use "--" or a real name |
contactLastname | 1 | 50 | "-" is acceptable |
contactRole | 3 | 24 | "DPO" is exactly the minimum |
contactNotes | — | 200 | |
email.description | — | 50 | |
phone.countryCode | — | — | Format: + followed by 1–4 digits |
phone.phoneNumber | 6 | 15 | Digits only |
phone.description | — | 50 |
4. Cross-Document Validation Rules
These rules are checked by organizationCheck (src/lib/schemas/importSchema.js) after Zod structural validation. Violations cause the import to fail before any database writes.
| # | Rule |
|---|---|
| 1 | Every locale in organization.ropas[] must have a matching document in the top-level ropas[] array. |
| 2 | Every document in the top-level ropas[] array must be declared in organization.ropas[]. |
| 3 | No duplicate locales in ropas[]. |
| 4 | Every ropas[].orgShortName must equal organization.shortName. |
| 5 | Every templates[].orgShortName must equal organization.shortName. |
| 6 | activityId values must be unique within each OU (per ROPA document). |
| 7 | ouId values must be unique within each ROPA document. |
| 8 | All controllers[] and processors[] IDs referenced in activities must exist in organization.partners[]. |
| 9 | organization.licenseEnd must be strictly greater than organization.licenseStart. |
| 10 | Exactly one entry in organization.ropas[] must have isDefault: true. |
| 11 | organization.partners[] must contain an entry with organizationId: 0. |
| 12 | Each contact may have at most one isPrimary: true email and at most one isPrimary: true phone. |
5. Source Files
| File | Role |
|---|---|
src/constants/ropaAttributes.js | Enum values and size-constraint constants |
src/lib/schemas/importSchema.js | Zod schemas + cross-document validation |
src/services/exportService.js | Serializes org + ROPAs + templates to envelope |
src/services/importService.js | Deserializes envelope and writes to MongoDB |
src/lib/mongoose/organizationFromTemplateCreate.js | Loads template files and creates org |
templates/demo/ | Reference template (multi-locale) |
templates/upf/ | Reference template (Catalan/Spanish/English) |
templates/bfdi/ | German BFDI Art. 30 DSGVO template (German only) |