This document explains every field in SiteConfig.json and how to configure it for your backend. Start from SiteConfig.json.template when creating a local config or a runtime-import config, then fill in your environment-specific values.

If you need a capability, auth policy option, or asset strategy that is not listed here, please open an issue or pull request at github.com/vakesz/SKIES-iOS.

Not yet open, but planned to be with release 1.0.0.

Top-level structure

{
  "schemaVersion": 1,
  "capabilities": { ... },
  "links": { ... },
  "api": { ... },
  "fields": { ... },
  "assets": { ... },
  "textFormatting": { ... },
  "connection": { ... }
}
FieldTypeRequiredDefaultDescription
schemaVersionintegerNo1Config schema version for forward compatibility. Always set to 1.
capabilitiesobjectYesFeature flags and auth mode.
linksobjectYesWeb portal link-building configuration.
apiobjectYesAPI path, query, body, wrapper, and auth policy mappings.
fieldsobjectYesJSON field name mappings for each API model.
assetsobjectYesAsset URL resolution strategy.
textFormattingobjectNo{"outgoingLineBreak": "crlf"}Text encoding settings for outgoing requests.
connectionobjectNo*Backend URLs and OAuth credentials. Required when distributing via in-app file import.

capabilities

Controls which features are enabled and how authentication is enforced.

"capabilities": {
  "authMode": "required",
  "supportsCurrentUser": true,
  "supportsUserDirectory": true,
  "supportsComments": true,
  "supportsLikes": true,
  "supportsActivityRegistration": true,
  "supportsProfiler": true,
  "birthYearHiddenJobTitles": ["example-role"],
  "meaninglessDietaryValues": ["nothing", "none", "n/a", "na", "no", "nil"]
}

authMode

Type: string (enum) — Required

Controls the global authentication gate for the app.

ValueBehavior
"required"All users must sign in. Anonymous access is not allowed.
"optional"Authentication is available but not required. Unauthenticated users can browse.
"disabled"Authentication is completely disabled. No sign-in UI or token handling.

Feature flags

All are boolean. Set to false to disable the feature entirely in the app UI and API calls.

FieldDescription
supportsCurrentUserEnables fetching and displaying the signed-in user’s own profile.
supportsUserDirectoryEnables the user directory / people search feature.
supportsCommentsEnables comments on posts and activities.
supportsLikesEnables like/reaction counts and toggling on posts, activities, and comments.
supportsActivityRegistrationEnables sign-up / registration for activities.
supportsProfilerEnables the external profiler link on user profiles.

birthYearHiddenJobTitles

Type: array of strings — Required (can be empty [])

Job titles for which the birth year should not be displayed on user profiles. Matching is case-sensitive. Use the exact role identifier strings your backend returns.

"birthYearHiddenJobTitles": ["consultant", "contractor"]

meaninglessDietaryValues

Type: array of strings — Required (can be empty [])

Dietary/food preference values that should be treated as “no preference” and suppressed in the UI. Matching is case-insensitive. Include all variants your backend may return.

"meaninglessDietaryValues": ["nothing", "none", "n/a", "na", "no", "nil", "nincs"]

Describes how deep links and web portal URLs are constructed for posts, activities, and user profiles.

"links": {
  "webPortalPath": "/YOUR_PORTAL_PATH",
  "resourceQueryKey": "resourceId",
  "postIdentifierQueryKey": "postId",
  "activityIdentifierQueryKey": "activityId",
  "profileUsernameQueryKey": "userName",
  "postResourceID": "POST_RESOURCE_ID",
  "activityResourceID": "ACTIVITY_RESOURCE_ID",
  "userResourceID": "USER_RESOURCE_ID",
  "postExtraQueryItems": [],
  "activityExtraQueryItems": [
    { "name": "mode", "value": "activity" }
  ],
  "profileExtraQueryItems": [
    { "name": "mode", "value": "profile" }
  ]
}
FieldTypeRequiredDescription
webPortalPathstringYesThe URL path appended to connection.webPortalURL for all portal links. Example: "/main.asp".
resourceQueryKeystringYesQuery parameter name used to identify the resource type. Example: "rID".
postIdentifierQueryKeystringYesQuery parameter name for the post ID. Example: "coreID".
activityIdentifierQueryKeystringYesQuery parameter name for the activity ID. Example: "aktID".
profileUsernameQueryKeystringYesQuery parameter name for the username in profile links. Example: "username".
postResourceIDstringYesThe value passed for resourceQueryKey when linking to a post. Example: "200".
activityResourceIDstringYesThe value passed for resourceQueryKey when linking to an activity. Example: "2".
userResourceIDstringYesThe value passed for resourceQueryKey when linking to a user profile. Example: "1".
postExtraQueryItemsarrayNoAdditional query parameters appended to post deep links. Defaults to [].
activityExtraQueryItemsarrayNoAdditional query parameters appended to activity deep links. Defaults to [].
profileExtraQueryItemsarrayNoAdditional query parameters appended to profile deep links. Defaults to [].

Each item in *ExtraQueryItems is an object with "name" and "value" string fields:

{ "name": "mode", "value": "activity" }

api

Maps logical API concepts to the actual path segments, query parameter names, request body keys, response wrapper keys, and per-endpoint authentication policies used by your backend.

api.paths

URL path segments appended to the API base URL for each resource.

"paths": {
  "posts": "posts",
  "activities": "activities",
  "me": "current-user",
  "users": "users",
  "user": "user",
  "comments": "comments",
  "like": "reactions",
  "participants": "participants"
}
KeyDescriptionExample value
postsPath segment for the posts list endpoint."posts"
activitiesPath segment for the activities list endpoint."activities"
mePath segment for the current user endpoint."me", "current-user"
usersPath segment for the user directory endpoint."users"
userPath segment for a single user detail endpoint."user"
commentsPath segment for comments on a post or activity."comments"
likePath segment for the like/reaction endpoint."like", "reactions"
participantsPath segment for activity participants."participants"

api.queryKeys

Query parameter names used in API requests.

"queryKeys": {
  "page": "page",
  "size": "size",
  "department": "department",
  "geography": "location",
  "name": "name",
  "mobile": "phone",
  "userName": "userName",
  "subscribed": "subscribed",
  "registrationAnswer": "response",
  "guestCount": "guestCount"
}
KeyDescription
pagePagination: page number parameter name.
sizePagination: page size parameter name.
departmentFilter by department parameter name.
geographyFilter by location/geography parameter name.
nameSearch by name parameter name.
mobileFilter or search by phone number parameter name.
userNameFilter or lookup by username parameter name.
subscribedFilter activities by subscription status parameter name.
registrationAnswerActivity registration answer parameter name.
guestCountActivity registration guest count parameter name.

api.bodyKeys

Keys used in request bodies (POST/PUT payloads).

"bodyKeys": {
  "comment": "body",
  "liked": "isLiked",
  "count": "itemCount"
}
KeyDescription
commentBody key for the comment text when creating a comment.
likedBody key for the boolean liked state when toggling a reaction.
countBody key for item count in paginated response bodies.

api.wrapperKeys

Keys used to unwrap paginated or list responses from your API.

"wrapperKeys": {
  "items": "items",
  "total": "total",
  "totalGuests": "guestTotal",
  "users": "users",
  "totalCount": "totalCount",
  "page": "page",
  "size": "size"
}
KeyDescription
itemsKey containing the array of results in a list response.
totalKey containing the total item count in a list response.
totalGuestsKey containing the total guest count for activity participants.
usersKey containing the array of users in a user directory response.
totalCountKey containing the total count in user directory responses.
pageKey containing the current page in a paginated response.
sizeKey containing the page size in a paginated response.

api.authPolicies

Per-endpoint authentication policy. Specifies whether a valid auth token is required, optional, or not used for each API call.

"authPolicies": {
  "posts": "required",
  "postDetails": "required",
  "postComments": "required",
  "commentCreation": "required",
  "activities": "required",
  "activityDetails": "required",
  "activityComments": "required",
  "activityParticipants": "required",
  "activityRegistration": "required",
  "currentUser": "required",
  "users": "required",
  "userDetails": "required",
  "likes": "required",
  "commentDeletion": "required",
  "fileDownloads": "required"
}

Allowed values for every policy key:

ValueBehavior
"required"Request is blocked if the user is not authenticated.
"ifAvailable"Auth token is included when available, but the request proceeds without it.
"none"No auth token is sent, even if one is available.

Policy keys:

KeyEndpoint it controls
postsPost list fetch
postDetailsSingle post detail fetch
postCommentsComments on a post
commentCreationCreating a new comment
activitiesActivity list fetch
activityDetailsSingle activity detail fetch
activityCommentsComments on an activity
activityParticipantsParticipant list for an activity
activityRegistrationSigning up for / leaving an activity
currentUserCurrent user profile fetch
usersUser directory listing
userDetailsSingle user detail fetch
likesLike / reaction toggle
commentDeletionDeleting a comment
fileDownloadsDownloading file attachments

fields

Maps logical field names the app uses internally to the actual JSON keys returned by your API. Every value is a string containing the exact key name from your backend response.

fields.post

JSON key mappings for a post object.

App fieldTemplate defaultDescription
id"id"Unique post identifier
title"title"Post title
body"body"Post body / content
imageUrl"imageUrl"Post cover image URL
created"createdAt"Post creation timestamp
city"city"City associated with the post
country"country"Country associated with the post
companyName"organizationName"Originating organization name
departmentId"departmentId"Originating department identifier
departmentName"departmentName"Originating department name
companyId"organizationId"Originating organization identifier
summary"summary"Short preview / summary text
link"link"External URL linked from the post
userName"userName"Author username
userPhoto"userPhotoUrl"Author profile photo URL
pinned"pinned"Whether the post is pinned
hasExtraParticipants"hasAdditionalParticipants"Whether there are extra participants not counted in capacity
commentsCount"commentsCount"Number of comments
likesCount"likesCount"Number of likes/reactions
liked"liked"Whether the current user has liked the post
global"isGlobal"Whether the post is org-wide / global
activityId"activityId"Linked activity identifier
activityCommentsCount"activityCommentsCount"Number of activity comments
startDate"startDate"Event start date
signUpDeadline"signUpDeadline"Registration deadline
totalCapacity"totalCapacity"Maximum number of participants
subscribed"subscribed"Whether the current user is registered
question"registrationQuestion"Question shown during registration
attachment"attachmentUrl"URL to a file attachment
important"isImportant"Whether the post is marked as important

fields.activity

JSON key mappings for an activity object.

App fieldTemplate defaultDescription
id"id"Unique activity identifier
postId"postId"Parent post identifier
link"link"External URL
title"title"Activity title
description"body"Activity description / body
type"type"Activity type label
imageUrl"imageUrl"Cover image URL
created"createdAt"Creation timestamp
startDate"startDate"Event start date
signUpDeadline"signUpDeadline"Registration deadline
cityId"cityId"City identifier
cityName"cityName"City name
countryId"countryId"Country identifier
countryName"countryName"Country name
departmentId"departmentId"Originating department identifier
departmentName"departmentName"Originating department name
companyId"organizationId"Originating organization identifier
companyName"organizationName"Originating organization name
organizerUserName"userName"Organizer’s username
organizerPhoto"organizerPhotoUrl"Organizer’s photo URL (primary)
organizerPhotoFallbacks["userPhotoUrl"]Fallback photo URL keys tried in order if organizerPhoto is absent
pinned"pinned"Whether the activity is pinned
hasExtraParticipants"hasAdditionalParticipants"Whether there are extra participants
totalCapacity"totalCapacity"Maximum number of participants
subscribed"subscribed"Whether the current user is registered
commentsCount"activityCommentsCount"Number of comments
likesCount"likesCount"Number of likes/reactions
liked"liked"Whether the current user has liked the activity
location"location"Venue / location description
tags"tags"Tags or categories
requirements"requirements"Requirements text
category"category"Activity category
question"registrationQuestion"Registration question
global"isGlobal"Whether the activity is org-wide / global

organizerPhotoFallbacks is an array of strings, not a single string. List fallback key names in priority order.

fields.activityParticipant

JSON key mappings for a participant entry in an activity.

App fieldTemplate defaultDescription
userName"participantId"Participant’s username or identifier
signupDate"signupDate"When the participant registered
department"department"Participant’s department
guests"guestCount"Number of additional guests brought by this participant
answer"response"Participant’s answer to the registration question
foodRestrictions"foodRestrictions"Dietary restrictions
photo"photoUrl"Participant’s profile photo URL

fields.user

JSON key mappings for a user profile object.

App fieldTemplate defaultDescription
userName"userName"Username / unique identifier
firstName"firstName"First name
lastName"lastName"Last name
userPhoto"userPhotoUrl"Profile photo URL
workPhone"workPhone"Work phone number
personalPhone"personalPhone"Personal/mobile phone number
workEmail"workEmail"Work email address
personalEmail"personalEmail"Personal email address
educationType"educationType"Education type label
educationTitle"educationTitle"Education title / degree
cityId"cityId"City identifier
countryId"countryId"Country identifier
departmentId"departmentId"Department identifier
departmentName"departmentName"Department name
companyId"organizationId"Organization identifier
employeeNumber"employeeNumber"Employee number
birthday"birthday"Date of birth
foodPreferences"foodPreferences"Dietary preferences
aboutMyJob"aboutMyJob"“About my job” free-text field
aboutMe"aboutMe"“About me” free-text field
externalProfileId"externalProfileId"Identifier used for the external profiler link
jobTitle"jobTitle"Job title
office"office"Office location

fields.comment

JSON key mappings for a comment object.

App fieldTemplate defaultDescription
commentId"commentId"Unique comment identifier
postId"postId"Parent post identifier
activityId"activityId"Parent activity identifier
body"body"Comment text content
header"headline"Comment headline / subject
userName"userName"Author username
userPhoto"userPhotoUrl"Author profile photo URL
createdAt"createdAt"Comment creation timestamp
likesCount"likesCount"Number of likes
liked"liked"Whether the current user has liked the comment

fields.activitySubscription

JSON key mappings for the activity subscription/registration status object.

App fieldTemplate defaultDescription
activityId"activityId"Activity identifier
userName"userName"Username of the registrant
answer"response"Answer to the registration question
number"guestCount"Number of additional guests
subscribed"subscribed"Whether the user is currently registered

assets

Controls how asset (image) URLs are constructed for activities.

"assets": {
  "activityAssetIdentifierStrategy": "postIdOrActivityId"
}

activityAssetIdentifierStrategy

Type: string (enum) — Required

Determines which ID is used to build the asset URL path for activity images.

ValueBehavior
"activityId"Always use the activity’s own ID when constructing the asset URL.
"postId"Always use the parent post’s ID when constructing the asset URL.
"postIdOrActivityId"Use the post ID if available; fall back to the activity ID.

textFormatting

Controls how text is encoded in outgoing API requests (e.g. comment bodies).

"textFormatting": {
  "outgoingLineBreak": "crlf"
}

outgoingLineBreak

Type: string (enum) — Optional (defaults to "crlf")

The line break sequence used when sending text to the API.

ValueSequenceWhen to use
"crlf"\r\nMost Windows-style or legacy backends. This is the default.
"lf"\nUnix/Linux-style backends.
"cr"\rRare; older systems.

connection

Contains all backend URLs and OAuth credentials. This section is required when distributing the config file via in-app import (the app validates its presence on load). When omitted, the app falls back to values baked into Info.plist at build time.

All URL values must use the https:// scheme. The app will reject any http:// or malformed URL.

"connection": {
  "apiBaseURL": "https://YOUR_API_BASE_URL",
  "assetsBaseUrl": "https://YOUR_ASSETS_BASE_URL",
  "avatarOrgBaseURL": "https://YOUR_AVATAR_BASE_URL",
  "webPortalURL": "https://YOUR_WEB_PORTAL_URL",
  "profilerURL": "https://YOUR_PROFILER_URL",
  "tenantID": "YOUR_AZURE_TENANT_ID",
  "clientID": "YOUR_AZURE_CLIENT_ID",
  "redirectURI": "msalYOUR_CLIENT_ID://auth",
  "scopes": ["openid", "profile", "email", "api://YOUR_CLIENT_ID/YOUR_SCOPE_NAME"],
  "authProviderDisplayName": "Microsoft"
}
FieldTypeRequiredDescription
apiBaseURLstring (HTTPS URL)YesRoot URL of your backend REST API. All API path segments are appended to this.
assetsBaseUrlstring (HTTPS URL)YesBase URL for activity and post image assets.
avatarOrgBaseURLstring (HTTPS URL)YesBase URL used to resolve user avatar/profile photos.
webPortalURLstring (HTTPS URL)YesBase URL of the web portal, used together with links.webPortalPath to build deep links.
profilerURLstring (HTTPS URL)YesURL of the external profiler service. Used when capabilities.supportsProfiler is true.
tenantIDstringNoAzure AD tenant ID (GUID). Required for Microsoft OAuth authentication.
clientIDstringNoAzure AD app registration client ID (GUID). Required for Microsoft OAuth authentication.
redirectURIstringNoMSAL redirect URI registered in your Azure app. Must match exactly. Conventional format: "msal<clientID>://auth".
scopesarray of stringsNoOAuth scopes to request. Typically includes OpenID Connect scopes and your API’s application scope.
authProviderDisplayNamestringYesDisplay name shown in the sign-in UI. Example: "Microsoft".

Never commit a SiteConfig.json containing real credentials to source control. The file is listed in .gitignore and should be distributed to users out-of-band (e.g. via MDM, email, or a secure link).

Minimal example

Below is the smallest valid config to get started. Replace all placeholder values before use.

{
  "schemaVersion": 1,
  "capabilities": {
    "authMode": "required",
    "supportsCurrentUser": true,
    "supportsUserDirectory": true,
    "supportsComments": true,
    "supportsLikes": true,
    "supportsActivityRegistration": true,
    "supportsProfiler": false,
    "birthYearHiddenJobTitles": [],
    "meaninglessDietaryValues": ["none", "n/a", "no"]
  },
  "links": {
    "webPortalPath": "/portal",
    "resourceQueryKey": "resourceId",
    "postIdentifierQueryKey": "postId",
    "activityIdentifierQueryKey": "activityId",
    "profileUsernameQueryKey": "userName",
    "postResourceID": "1",
    "activityResourceID": "2",
    "userResourceID": "3",
    "postExtraQueryItems": [],
    "activityExtraQueryItems": [],
    "profileExtraQueryItems": []
  },
  "api": {
    "paths": {
      "posts": "posts",
      "activities": "activities",
      "me": "me",
      "users": "users",
      "user": "user",
      "comments": "comments",
      "like": "like",
      "participants": "participants"
    },
    "queryKeys": {
      "page": "page",
      "size": "size",
      "department": "department",
      "geography": "location",
      "name": "name",
      "mobile": "phone",
      "userName": "userName",
      "subscribed": "subscribed",
      "registrationAnswer": "answer",
      "guestCount": "guests"
    },
    "bodyKeys": {
      "comment": "body",
      "liked": "liked",
      "count": "count"
    },
    "wrapperKeys": {
      "items": "items",
      "total": "total",
      "totalGuests": "totalGuests",
      "users": "users",
      "totalCount": "totalCount",
      "page": "page",
      "size": "size"
    },
    "authPolicies": {
      "posts": "required",
      "postDetails": "required",
      "postComments": "required",
      "commentCreation": "required",
      "activities": "required",
      "activityDetails": "required",
      "activityComments": "required",
      "activityParticipants": "required",
      "activityRegistration": "required",
      "currentUser": "required",
      "users": "required",
      "userDetails": "required",
      "likes": "required",
      "commentDeletion": "required",
      "fileDownloads": "required"
    }
  },
  "fields": {
    "post": {
      "id": "id", "title": "title", "body": "body", "imageUrl": "imageUrl",
      "created": "createdAt", "city": "city", "country": "country",
      "companyName": "companyName", "departmentId": "departmentId",
      "departmentName": "departmentName", "companyId": "companyId",
      "summary": "summary", "link": "link", "userName": "userName",
      "userPhoto": "userPhoto", "pinned": "pinned",
      "hasExtraParticipants": "hasExtraParticipants",
      "commentsCount": "commentsCount", "likesCount": "likesCount",
      "liked": "liked", "global": "global", "activityId": "activityId",
      "activityCommentsCount": "activityCommentsCount", "startDate": "startDate",
      "signUpDeadline": "signUpDeadline", "totalCapacity": "totalCapacity",
      "subscribed": "subscribed", "question": "question",
      "attachment": "attachment", "important": "important"
    },
    "activity": {
      "id": "id", "postId": "postId", "link": "link", "title": "title",
      "description": "description", "type": "type", "imageUrl": "imageUrl",
      "created": "createdAt", "startDate": "startDate",
      "signUpDeadline": "signUpDeadline", "cityId": "cityId",
      "cityName": "cityName", "countryId": "countryId",
      "countryName": "countryName", "departmentId": "departmentId",
      "departmentName": "departmentName", "companyId": "companyId",
      "companyName": "companyName", "organizerUserName": "userName",
      "organizerPhoto": "organizerPhoto",
      "organizerPhotoFallbacks": ["userPhoto"],
      "pinned": "pinned", "hasExtraParticipants": "hasExtraParticipants",
      "totalCapacity": "totalCapacity", "subscribed": "subscribed",
      "commentsCount": "commentsCount", "likesCount": "likesCount",
      "liked": "liked", "location": "location", "tags": "tags",
      "requirements": "requirements", "category": "category",
      "question": "question", "global": "global"
    },
    "activityParticipant": {
      "userName": "userName", "signupDate": "signupDate",
      "department": "department", "guests": "guests",
      "answer": "answer", "foodRestrictions": "foodRestrictions",
      "photo": "photo"
    },
    "user": {
      "userName": "userName", "firstName": "firstName",
      "lastName": "lastName", "userPhoto": "userPhoto",
      "workPhone": "workPhone", "personalPhone": "personalPhone",
      "workEmail": "workEmail", "personalEmail": "personalEmail",
      "educationType": "educationType", "educationTitle": "educationTitle",
      "cityId": "cityId", "countryId": "countryId",
      "departmentId": "departmentId", "departmentName": "departmentName",
      "companyId": "companyId", "employeeNumber": "employeeNumber",
      "birthday": "birthday", "foodPreferences": "foodPreferences",
      "aboutMyJob": "aboutMyJob", "aboutMe": "aboutMe",
      "externalProfileId": "externalProfileId",
      "jobTitle": "jobTitle", "office": "office"
    },
    "comment": {
      "commentId": "commentId", "postId": "postId",
      "activityId": "activityId", "body": "body", "header": "header",
      "userName": "userName", "userPhoto": "userPhoto",
      "createdAt": "createdAt", "likesCount": "likesCount",
      "liked": "liked"
    },
    "activitySubscription": {
      "activityId": "activityId", "userName": "userName",
      "answer": "answer", "number": "number", "subscribed": "subscribed"
    }
  },
  "assets": {
    "activityAssetIdentifierStrategy": "postIdOrActivityId"
  },
  "textFormatting": {
    "outgoingLineBreak": "crlf"
  },
  "connection": {
    "apiBaseURL": "https://api.example.com",
    "assetsBaseUrl": "https://assets.example.com",
    "avatarOrgBaseURL": "https://avatars.example.com",
    "webPortalURL": "https://portal.example.com",
    "profilerURL": "https://profiler.example.com",
    "tenantID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "clientID": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
    "redirectURI": "msalyyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy://auth",
    "scopes": [
      "openid", "profile", "email",
      "api://yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/access_as_user"
    ],
    "authProviderDisplayName": "Microsoft"
  }
}