Skip to main content


All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

5.3.0 (2023-02-16)โ€‹


  • analytics: Added analytics UI integration (327155d)
  • analytics: Added initial setup if integration enabled (31eb58f)
  • analytics: Configured int and prd connectivity (8a8253e)
  • analytics: updated db schema (3c456aa)
  • api: Added GetTeamsByTemplate endpoint (96a0b3a)
  • bo: analytics and operations persistence (932b2fc)
  • bo: Analytics loaded from internal collection (f78d44f)
  • bo: back-office v1 (52504f4)
  • bo: Handle env without analytics enabled (1fcd096)
  • bo: initialized ui (80bc65c)
  • bo: operations + analytics (6b052f4)
  • business-graph: added basic client and server (608a63d)
  • db: Added subscription model to sequelize + db (e994fde)
  • db: documented models (91663d4)
  • hosting: Updated self-hosted docker compose files (724926a)
  • infra: initialized migration code from cosmosdb and az storage to sql (c2d41d4)
  • lifecycle: Added control for concealed info in usage reports (5d6ae6c)
  • lifecycle: alpha (81d7b5b)
  • lifecycle: improved jobs data with teams count + processed (4a1f6f1)
  • lifecycle: job scheduled every hour (ea71bac)
  • self: Added docker compose for self-hosted (4367a32)
  • ui: Basic UI v2 (2b975cb)

Bug Fixesโ€‹

  • bo: updated startup command (dcdae84)
  • docker: fixed docker compose for self-hosted (2fc3b61)
  • lifecycle: disabled concealed data option check (7ba5816)
  • lifecycle: updated concealed option handling (48819ce)
  • package: Updated manifests descriptions (f1c3f18)
  • provisioning: Fixed sensitivity labels issue (e01c8a4)
  • ui: Fixed moble text rendering of placeholders (48a3424)

5.2.0 (2023-01-20)โ€‹


  • api: System app authorized to access all tenants logs (176df5b)
  • api: Updated system app id and system webhook url (d526ab9)
  • auth: Added support for multiple client id across services (edbe838)
  • exports: Template and settings export is limited to change mgrs (859609c)
  • provisioning: Failure to update mailnickname results in a warning, not an error. Automated truncature to 50 characters. (8398106)
  • queues: Added scheduled job (29982d0)
  • queues: Added INT startup script (f629832)
  • queues: Added queue_read_only and queue_allow_retry (2a3adaa)
  • queues: Added queues dashboard options (3137879)
  • queues: Added queues-dashboard service (07d3829)
  • queues: Jobs dashboard support for queues mgmt options (fc15905)
  • queues: New fine-grained queues options (177543f)
  • queues: New queues options + Webhooks priorities (dddc1cf)
  • reply to channel message (7c946e0)
  • search: Added search client (ab15901)
  • setup: Included setup scripts in scheduler startup sequence (9d87298)
  • signin: Added support for multiple app regs (f0d3d18)
  • subscriptions: Data model + events + db operations v0 (dd6641c)
  • templates: System templates can now be deleted (aa6e9e8)
  • update channel (3047db1)

Bug Fixesโ€‹

  • approval: Fixed email approval process when triggered from a card in Outlook (c232860)
  • BadGateway error (de51c1d)
  • better error form (5d59185)
  • catalog: ON/OFF sorting filters in templates catalog are not working #1471 (8c2610c)
  • channel displayName length (061d6c0)
  • deeplinks: Fixed open team and open tab deep links (67f746c)
  • error create channel (12204e8)
  • error for expired service account and channel name already exist (ca70f4c)
  • home: Fixed rendering issues in templates and requests (602e41b)
  • issue #257 (4467d38)
  • less-test (558bffd)
  • nbold v5 (a8d04ec)
  • not modified graph send 503 (79c2679)
  • not modified graph send 503 (cb67041)
  • repliesMessage to replyToMessage (73fc482)
  • send full response (ff8106a)
  • webhooks: Disabled system webhooks for token renewal (aa969aa)
  • webhooks: Fixed approval webhooks definition (e777a45)
  • workflow on push (705dd01)

5.1.0 (2022-10-21)โ€‹


  • api: added the ChannelMessage.Send permission to the service account scopes (921a960)
  • microsoft-lists: added the microsoft_teams_list_tab_cloned event + tracking capabilities (15ed9c9)
  • onenote: added permission check and audit trail event to the onenote module (d09f76c)
  • package: added new v2 package for publication on the Teams store (2dfd3d5)
  • package: updated package template to ease customization (68884e8)
  • planner: new telemetry and audit events (see events-specification-microsoft-planner.js) (331e35b)
  • sensitivity-labels: added service_account_missing_licenses telemetry event (a9a4c3e)
  • service_account: added the service_account_refresh_token_expired event for alerting (2de5aee)
  • sessions: updated session mgmt to use a Redis store using the redis package (31afa79)

Bug Fixesโ€‹

  • approval: added instrumentation to the approval email process (029d708), closes #843
  • approval: fixed approval email template path (0c32a08)
  • auditing: updated auditing integration configuration (0c7aafd)
  • authorization: included legacy admin consent from the login page using konami code (ecddbfc)
  • azure-storage: updated Azure Storage setup to create containers using the blog public access (67dd7c2)
  • cicd: fixed cicd infrastructure paths (65a7b3b)
  • fix fails (5720e20)
  • intercom: fixed error handling in getintercomconfiguration (d81721c)
  • intercom: fixed intercom initialization error (0282135)
  • intercom: temporarily disabled rate limiter for intercom configuration api endpoint (ac2480d)
  • lists: fix for INT environment (e2faf1f)
  • lists: fixed lists cloning + Feat OneNote and Office (98abe25)
  • office: fix for Office viewer as a tab (2e7eccb)
  • onenote: fixed onenote error from graph (70ef987)
  • permissions: adjusted default permissions scopes (3ffc386)
  • service-account: fixed service account update + added template export function (9d94e88)
  • signin: better error handling for Apple devices (0ce86e5)
  • signin: changed error management in signin process to cope with fetch (6c0703c)
  • signin: fixed admin consent success and error pages using async await for teams-js (3e41da8)
  • signin: fixed non-sso signin after migration to teams-js v2 (5c67280)
  • signin: fixed teams-js initialization in non-sso signin (9b14e29)
  • signin: fixed typo in signin module (ca6cf59)
  • signin: reenabled redirect with sso (8bdcd46)
  • signin: service account registration (36e9b4e)
  • signin: updated grant consent behavior (33c47a6)
  • teams-js: upgraded teams-js dependency to v2.2 (efe0261), closes #1291
  • teams: updated @microsoft/teams-js to v2.3.0 (6f08d18)
  • telemetry: fixed new telemetry settings (6d7b5b9)
  • throttling: temporarily disabled throttling in /events/specifications (7ddf1ca)

4.24.0 (2022-06-23)โ€‹


  • api: added getTeamMembers api endpoint (bce1257)
  • application-insights: reenabled application insights in build (2383038)
  • docker: added monitoring components to docker stack (prometheus, exporters...) (d6417aa)
  • docker: docker image now runs without a root-level account (419d3b1)
  • indexing: added robots.txt to prevent indexation from search bots (fb955b7)
  • microsoft-lists: microsoft Lists cloning support in provisioning (98d2b33)
  • npm: added NODE_ENV to npm start commands for each deploy (493f823)
  • packages: enabled configurable properties for the targeted home package (7bf6d28)
  • rbac: prevent early access to connected apps and reports to admins (273c4db)
  • reports: updated /reports endpoints to reflect roles requirements (01535b6)
  • templates: available teams when creating a template is now from /me/joinedTeams (fc5adbb), closes #1219

Bug Fixesโ€‹

  • api: fixed api / webhooks codes (6341937)
  • api: re-enaled cache for user roles + changed error management (a55164a)
  • app-instghts: disabled legacy page tracking (572b182)
  • assets: rebuilt cdn assets (7ccd6ce)
  • assets: reverted cdn assets to previous build (0ee187e)
  • audit-trails: fixed provisioning audit trails stucked at 0% (291351b), closes #1231
  • cdn: removed cdn directory from docker image (aecaeb3)
  • cdn: removed cdn from .env config files (1bc13c6)
  • cicd: fixed cicd image name for integration (5d46063)
  • cicd: updated cicd docker image (a7f94a5)
  • cicd: updated cicd script to build and push using github sha as version (fa5492e)
  • deps: added explicit deps to vm2 and he modules (e1ed798)
  • docker: fixed docker image build (df9f75e)
  • docker: reverted dockerfile until issue with the api service resolution (b0eb106)
  • intercom: fixed intercom access from login page in case of admin consent request (4ca430a)
  • license: fixed display of license from the settings tab (345f5b5)
  • locales: fixed cdn locales url (bf65051)
  • manifests: fixed manifests loading directory in configuration module (d42f887)
  • packages: added missing images in packages (703ebd8)
  • permissions: added Sites.Manage.All to the service account required permissions (d09a8cc)
  • planner: fixed Planner tab configuration URLs using the latest version (6dc419f), closes #1222
  • planner: provisioning now preserves tasks checklists order (26fe2e4), closes #1150
  • power-automate: fixed issue with power automate triggers (d66a883)
  • power-automate: fixed Power Automate issues with API and webhooks (15d6d0c)
  • provisioning: updated /provisioning validation schema to accept members display names (5ed8a47)
  • rate-limiter: replaces rate limiter redis store with the default in-memory (2172036)
  • redis: updated redis cache client initialization from connect to ready (ccd59bf)
  • search: fixed in-app search from the homepage (d4254e7), closes #1224
  • service-account: fixed issue with service account registration (1bc33ee)
  • services: updated services loading logging (238034e)
  • setup: fixed setup scripts path in package.json (258a15c)
  • teardown: fixed case when the service doesn't start properly and exits (86beb45)
  • timeout: disabled timeout module until further investigation (90e0e32)
  • timeout: reenabled timeout in web and api service (226becb)
  • timeout: updated timeout behavior for web and api (192ddde)

4.23.0 (2022-05-19)โ€‹

Bug Fixesโ€‹

  • app-instghts: disabled app-instghts client-side script (4d9f792)

4.22.0 (2022-05-19)โ€‹

Bug Fixesโ€‹

  • app-insights: disabled client-side app-insights integration (ceef679)

4.21.0 (2022-05-19)โ€‹

Bug Fixesโ€‹

  • build: updated production cdn scripts (9ac4a51)

4.20.0 (2022-05-19)โ€‹

4.19.0 (2022-05-19)โ€‹


  • api: added /catalog/templates endpoints for granular management (922da0e)
  • bot: added bot packages (ac7b42f)
  • connected-apps: added connected-apps button + embed (1a578c8), closes #1176
  • events: fixed connectivity to events server (3c5e8f5)
  • metadata: added metadata query api (612a66f)
  • rbac: added governance manager role in rbac settings (1c4ae58), closes #1178
  • reports: added "user_report_viewed" analytics event (4610b4d)
  • reports: added reports categorization + dynamic reports height (a4b72b2)
  • reports: added reports navigation and dynamic loading (b9e9aca)
  • webhooks: updated webhook creation to support Tray (0c48af7)

Bug Fixesโ€‹

  • api: fixed issue with delete archive and rename teams operations (7b61164), closes #78
  • connected-apps: fixed iframe to host communication (18a3c8b)
  • connected-apps: whitelisted connected-apps test environment url (95d1730)
  • db: fixed events db name in PRD (469fab5)
  • git: fixed large log files in commits (0093061)

4.18.0 (2022-03-08)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • github organization: updated refs to our previous GitHub org (f94bd83)

๐Ÿ“š Docsโ€‹

  • changelog: fixed changelog broken links (e1673bc)
  • changelog: fixed refs to our former GitHub org (281311d)
  • docs: fixed invalid links in generated docs (275269f)
  • docs: updated WEBSITES_DOCS constant URL (fae4f33)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • github: updated deps for our new GitHub org (ddba4c7)

4.17.0 (2022-03-04)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • packages: fixed manifest rendering in json format (f489706)
  • packages: fixed settings tab name in manifests (e033c49)
  • provisioning: fix planner provisioning issue (7d9b83a)

๐Ÿš€ Featuresโ€‹

  • onenote: oneNote tabs are now cloned just as other Office tabs (92ab7a7)

๐Ÿ“š Docsโ€‹

  • contributing: updated contributing guide (4dd9535)
  • docs references: updated generated assets for docs site (faa5d03)

4.16.0 (2022-02-14)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • packages: updated packages to remove the docs tab and the configurable tab (53352d0)

๐Ÿš€ Featuresโ€‹

  • i18n: integrated updates from i18n (4408e06)

4.15.0 (2022-02-14)โ€‹

๐Ÿš€ Featuresโ€‹

  • packages: packages version is now synchronized with the platform version (c1b37ff)

4.14.0 (2022-02-13)โ€‹

4.13.0 (2022-02-13)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • cdn: updated production cdn assets (975dc30)

๐Ÿ“š Docsโ€‹

  • licences: updated licences mentions to SalesTim SAS (85c71c7)

4.12.0 (2022-02-10)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • homepage: fixed issue preventing the homepage to load (2344d13), closes #1096

4.11.0 (2022-02-10)โ€‹

๐Ÿญ Build Systemโ€‹

  • packages: updated dev packages to include a docs tab (b62de1c)

๐Ÿ› Bug Fixesโ€‹

  • docs: fixed events_reference doc generation (69efd2f)

๐Ÿš€ Featuresโ€‹

  • branding: updated all references to salestim to nbold (7fa4943)

4.10.0 (2022-02-08)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • provisioning: fixed tab configuration after MS graph update (c57f24d), closes #1108

๐Ÿ“ฆ CIโ€‹

  • docs: updated build script to generate docs assets (ce7856f)
  • references: included all assets from app-platform repo into build (977800b)

4.9.0 (2022-02-08)โ€‹

๐Ÿ“š Docsโ€‹

  • changelog: removed breaking change alert from a previous commit (adabd64)
  • permissions: updated the list of permissions scopes in the "hosting" documentation (84d67d0)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • connected-apps: removed references to the @salestim/connected-apps module (31017ca)

๐Ÿš€ Featuresโ€‹

  • branding: updated packages logo and tabs to match the nbold brand (1090604)

4.8.1 (2022-01-25)โ€‹

๐Ÿญ Build Systemโ€‹

  • dependencies: bump node-fetch from 2.6.1 to 2.6.7 (38458ce)
  • deps: bump node-fetch from 2.6.1 to 2.6.7 in /src/libs/github (c74459b)
  • deps: bump node-fetch from 2.6.1 to 2.6.7 in /src/libs/webhooks (8a06244)

4.8.0 (2022-01-25)โ€‹

๐Ÿญ Build Systemโ€‹

  • npx: updated all references to npx in package.json to include the --yes option (10e69b0)

๐Ÿš€ Featuresโ€‹

  • channels: clone channel settings as part of the provisioning process #592 (f7369bc)
  • naming convention: added console logging to preview naming conventions and see detailed errors (9e30f7b)
  • service account: force account selection during service account update (3a1aed5)
  • service account: users granted as teams_service_admin now can access and manage app settings (ac1d28b), closes #1062

๐Ÿ› Bug Fixesโ€‹

  • provisioning: fix: Settings not copied as part of the provisioning (1b98c41), closes #1079
  • security: any unexpected error in web or app is now managed to prevent debug info leak (4c3191a)
  • security: excessive error verbosity (ISMS #39) (86a208d)
  • security: preparation for fixing potential XSS security issue (14b0212)
  • service account: disabled cache for organization API endpoints (6626ce5), closes #1086

4.7.0 (2021-12-11)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • permanent_membership: fixed help label displaying the maximum number of permanent members (683048e)

4.6.0 (2021-12-11)โ€‹

4.5.0 (2021-12-11)โ€‹

๐Ÿš€ Featuresโ€‹

  • permanent_membership: updated permanent membership limit to 30 owners and 50 members (3f2b24b), closes #1068

๐Ÿ› Bug Fixesโ€‹

  • private_channels: fixed reuester not added to private channels (85e983d), closes #914
  • provisioning: fixed app installation issue (0450461)

4.4.1 (2021-12-09)โ€‹

๐Ÿ› Bug Fixesโ€‹

  • cdn: fixed cdn production version (e56f9e1)
  • jobs: prevent jobs deletion on complete (7d13b2b)

4.4.0 (2021-12-09)โ€‹

๐Ÿงช Testsโ€‹

  • auth: added mocks for Microsoft Identity platform API to fully isolate tests (858269e)
  • db: mocked Sequelize module using sequelize-mock to isolate unit tests (f5c8386)
  • github: mocked github api to isolate unit tests (4e2a5db)


๐Ÿš€ Featuresโ€‹

  • analytics: included analytics script based on plausible (self-hosted) (6e4f841)
  • analytics: new analytics capabilities based on self-hosted Plausible (89f8607)
  • logs: added LOG_PERSISTENCY_DIRECTORY option to define logs location if persistency is enabled (d4a5c2a)
  • prometheus: prometheus exporter now supports X-Auth-Token to secure the /metrics endpoint (239043d)

โšก Performance Improvementsโ€‹

  • prometheus: disabled gc metrics as there is a dep incompatibility with prometheus-gc-stats (9f58ae1)

๐Ÿ“ฆ CIโ€‹

  • dependabot: updated dependabot.yml to not exclude dev-dependencies and improve PR tagging (8ad1c9f)
  • deps: assets rebuilt (67cf5cc)
  • docker: added github action to build push docker image to azure and gh registries (f9d4386)
  • jobs: reschedules jobs in PRD (3bd4469)
  • prometheus: enabled prometheus exporter for all environments (9045259)
  • prometheus: included npm rebuild in GH action for INT to rebuild native components (36010fc)
  • redis: pPR now targets the non-production redis server (e7fe447)
  • terraform: updated terraform azure provider and added new resources (0931ff7)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • i18n: removed references to DE in packages (4e95d1a)
  • webclient: moved webclient to /src/client to isolate it from the web service (4ef4e50)

๐Ÿ“š Docsโ€‹

  • adr: added proposed adr for redis connections (cache and queues) monitoring (511d000)
  • analytics: added ADR 0006-web-analytics to validate our app analytics platform (72ba99a)
  • audits: rebuild audit log files (372775c)
  • hosting: changed site navigation to cope with long toc (71dbc22)
  • hosting: updated the description of all the services and events of the platform (932f16c)
  • package: added :help entries to package.json to describe each script (b25aed4)
  • records: finalized importing all records as md (11f3191)
  • self-hosted: added diagram for additional operations services (uptime, metrics...) (35c8d47)
  • self-hosted: added draft of architecture data-flow (bc91ee6)
  • self-hosted: added power-platform setup documentation (ee9cf9c)
  • self-hosted: created new pages for permissions, provisioning and permanent membership jobs (d2def02)
  • self-hosted: fixed broken links and intercom integration (14f5ff4)
  • self-hosted: fixed nav (1e4bfa2)
  • self-hosted: included an export to docx and pdf script as part of the docs npm script (18e3be6)
  • self-hosted: self-hosted docs rebuild (8de66f5)
  • self-hosted: updated Azure resources from the terraform script (6103a0b)
  • self-hosted: updated azure resources with additional monitoring services (32febe3)
  • self-hosted: updated cloud vs self comparison by including networking differences (1e910a2)
  • self-hosted: updated core architecture documents (7855b2c)
  • self-hosted: updated novigation structure and included azure docs (7072734)
  • self-hosted: updated self-host documentation with terraform projects and docker guide (5d15ef1)
  • self-hosted: updated the updates management doc describing upgrade options (d249331)

๐Ÿ› Bug Fixesโ€‹

  • approval: fixed error during loading of the avatar picture in initApprovalsConsumer (57e1224)
  • flow: fixed flow storage location by including the /vomules/flow/storage empty folder in git (9614eca)
  • i18n: added support for nl-be, nl-nl and da-dk as fallbacks to en-us to i18n module (329e417), closes #968
  • logging: better error management when the log file transport can't access the target directory (916e765)
  • prometheus: fixed express exporter issue by explicitely including prom-client in deps (a19478c)
  • provisioning: fixed issue with channel calendar and yammer tabs provisioning (742c6f6), closes #1054
  • tab-config: fixed tab configuration page when adding the app as a custom tab in a team (df588eb)

๐Ÿญ Build Systemโ€‹

  • deps-dev: bump @jest/globals from 27.2.4 to 27.2.5 (9a31712)
  • deps-dev: bump @jest/globals from 27.2.5 to 27.3.0 (bfd4179)
  • deps-dev: bump @jest/globals from 27.3.0 to 27.3.1 (e648460)
  • deps-dev: bump eslint-plugin-import from 2.24.2 to 2.25.1 (6343d25)
  • deps-dev: bump eslint-plugin-import from 2.25.1 to 2.25.2 (37c5e46)
  • deps-dev: bump eslint-plugin-jest from 24.5.0 to 24.6.0 (1df9017)
  • deps-dev: bump eslint-plugin-jest from 24.6.0 to 25.0.1 (9b0be3b)
  • deps-dev: bump eslint-plugin-jest from 25.0.1 to 25.0.5 (483820b)
  • deps-dev: bump eslint-plugin-jest from 25.0.5 to 25.0.6 (9e44516)
  • deps-dev: bump eslint-plugin-jest from 25.0.6 to 25.2.1 (6e46bf9)
  • deps-dev: bump eslint-plugin-jest from 25.2.1 to 25.2.2 (945aff5)
  • deps-dev: bump eslint-plugin-jest from 25.2.2 to 25.3.0 (75f7e0c)
  • deps-dev: bump eslint-plugin-promise from 5.1.0 to 5.1.1 (8fcb63f)
  • deps-dev: bump jest from 27.2.4 to 27.2.5 (f6d2fa4)
  • deps-dev: bump jest from 27.2.5 to 27.3.0 (84d40b0)
  • deps-dev: bump jest from 27.3.0 to 27.3.1 (671c0bb)
  • deps: bump @microsoft/microsoft-graph-client from 3.0.0 to 3.0.1 (be275e5)
  • deps: bump @nboldhq/i18n from 16e383e to a00fb74 (0f82811)
  • deps: bump ajv from 8.6.3 to 8.8.0 (fa25f0f)
  • deps: bump bull from 3.29.2 to 3.29.3 (439a537)
  • deps: bump cronstrue from 1.117.0 to 1.119.0 (72e25ea)
  • deps: bump cronstrue from 1.119.0 to 1.122.0 (9fb7623)
  • deps: bump express-rate-limit from 5.4.0 to 5.4.1 (231d6b1)
  • deps: bump express-rate-limit from 5.4.1 to 5.5.0 (676997b)
  • deps: bump express-rate-limit from 5.5.0 to 5.5.1 (54e406e)
  • deps: bump ioredis from 4.27.10 to 4.27.11 (f3d71a7)
  • deps: bump ioredis from 4.27.11 to 4.28.0 (b70e63c)
  • deps: bump ioredis from 4.28.0 to 4.28.1 (3e0d236)
  • deps: bump nock from 13.1.3 to 13.1.4 (ca6d9a0)
  • deps: bump node from 16-alpine to 17-alpine (65cf3e7)
  • deps: bump node-red from 2.0.6 to 2.1.3 (2b8da2f)
  • deps: bump pg-mem from 2.0.1 to 2.1.5 (30b319b)
  • deps: bump pg-mem from 2.1.5 to 2.1.6 (0dc4493)
  • deps: bump sequelize from 6.6.5 to 6.7.0 (5856381)
  • deps: bump sequelize from 6.7.0 to 6.8.0 (c786a3e)
  • deps: bump ua-parser-js from 0.7.28 to 1.0.2 (aea2625)
  • deps: bump unleash-proxy-client from 1.5.2 to 1.6.0 (f754f28)
  • deps: bump validator from 13.6.0 to 13.7.0 (aad99b0)
  • deps: bump validator from 13.6.0 to 13.7.0 in /src/libs/db (9210bf9)
  • deps: bump zaproxy/action-baseline from 0.5.0 to 0.6.1 (42b9253)
  • deps: updated deps from dependabot (86f3d90)
  • docker: changed from npm ci to npm install (09fd42b)
  • github: added github token for remote dependencies (059d4a7)
  • ngrok: excluded /bin/ngrok directory from git (0c79ac0)
  • node: locking app with a specific node.js version using nvm and .nvmrc (3d3af0e)
  • npm: fixed npm install issue due to wrong npm version (f5593fe)
  • packages: rebuilt packages (bef89fb)
  • terraform: added monika, redis-exporter and bull-exporter to the dev iac (8c49630)

4.3.0 (2021-10-03)โ€‹

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • azure-storage: migrated from azure-storage to @azure/storage-blob (9cafb1c)

๐Ÿญ Build Systemโ€‹

๐Ÿ› Bug Fixesโ€‹

  • libs: now using exclusively relative paths to require internal modules (d74b1fe)

๐Ÿ“ฆ CIโ€‹

  • github-actions: updated PRD scripts to use npm install instead of npm ci (f9fdfa0)
  • terraform: first terraform iac project to host the the entire platform on a local docker server (33a1b01)

4.2.0 (2021-10-02)โ€‹

๐Ÿš€ Featuresโ€‹

  • logs: enable log files persistency through a new LOG_PERSISTENCY_ENABLED environment variable (8aaede5)

๐Ÿ“š Docsโ€‹

  • events: docs auto-generation for events and services (3a8d9c7)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • dist: removed all references to global variables (f9527e8)
  • teardown: when an exit signal is catched, the service tries to shutdown gracefully (532c0a0)

๐Ÿงช Testsโ€‹

  • jest: excluded tests folders from the dist generation (b282624)
  • jest: included jest option modulePathIgnorePatterns to prevent inclusion of the /dist path (0a4951b)
  • jest: tests (unit and e2e) and now running with the --silent switch (767902b)
  • redis: using ioredis-mock instead of the INT redis instance for unit tests (748f712)
  • unit-tests: re-enabled the whole unit tests suite (dd83840)

๐Ÿญ Build Systemโ€‹

  • changelog: updated standard-version scripts for better changelog generation (71321b3)
  • deps: bump unleash-server from 4.2.0-0 to 4.2.0-2 (28b7f8e)
  • dist: removed /dist contents from git tracking (83b50fb)
  • tests: reenabled unit tests in GitHub Actions build steps (20c3cc5)

4.1.0 (2021-10-01)โ€‹

๐Ÿš€ Featuresโ€‹

  • monitoring: added Express Prometheus middleware, accessible at /monitoring/metrics (d22e8af)
  • prometheus: included a new setting to enable the prometheus exporter + options (e42c9f7)

๐Ÿ“š Docsโ€‹

  • discovery: removed references to the discovery service (8fb9b9d)
  • self-hosted: created the minimal documentation for self-hosting the platform (b47a524)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • config: included addition logs during config loading (e92e622)
  • config: included loaded config details in startup logs (51ab21d)
  • config: reviewed all the settings and .env files for DEV and INT (2351802)
  • feature-toggles: feature toggles service and proxy are now disabled by default (8bb306f)
  • logging: better error handling by using the serialize-error module (e34d863)
  • redis: implemented Redis retry strategy to retry on connection error (ed56b69)
  • scripts: made scripts independent from the core engine (374473c)

๐ŸŽจ Stylingโ€‹

  • configuration: refactored all .env files (577f323)

๐Ÿ› Bug Fixesโ€‹

  • authentication: fixed issue authenticating against the api after client-side session expiration (3aaad5a)
  • config: fixed dynamic PORT environment variable used by Azure for its containers (74cae14)
  • deps: fixed missing references in api (829c293)
  • github: fixed github assignees issue when ther's only one assignee (e9662a8)
  • logging: better errors logs through tags and payload parsing/formatting (474a3c1)
  • prometheus: express-prometheus-middleware module is now only loaded if the option is enabled (0889241)
  • prometheus: fixed redis exporter and bull queue exporter configuration from docker compose file (fb36586)
  • webclient: fixed issue #932 Deeplinks from home app are sending the users to the wrong team (f5ac611)

๐Ÿญ Build Systemโ€‹

  • build: updated INT build (215aea4)
  • build: updated int script (0c2c2d2)
  • deps-dev: bump @jest/globals from 27.2.0 to 27.2.1 (298d8a6)
  • deps: bump @nboldhq/i18n from 9ac2bf7 to 174838e (c9fa7e6)
  • deps: bump @yaireo/tagify from 4.7.2 to 4.8.0 (5be4dcb)
  • deps: bump alpinejs from 3.3.4 to 3.4.0 (1f3501d)
  • deps: bump unleash-proxy-client from 1.4.0 to 1.5.2 (e426ebe)
  • deps: fix deps issue between express prometheus and unleash server with prom-client (3c72949)
  • deps: updated dependencies from GitHub (501d78c)
  • npm: updated npm dependencies to their latest version (358c20b)
  • npm: using npm ci instead of npm install in INT + added npm rebuild for native packages (e511c01)
  • teams-packages: fixed Teams packages build after introducing publisher/product constants (0672f80)
  • tests: disabled unit tests for testing in INT (77daeee)
  • version: updated major version number to 4 (3e72aab)

3.10.2 (2021-09-21)โ€‹

๐Ÿ“š Docsโ€‹

  • self-hosting: initialized the self-hosting docs published to dist (9f96583)

3.10.1 (2021-09-21)โ€‹

๐Ÿญ Build Systemโ€‹

  • deps: bump alpinejs from 3.3.3 to 3.3.4 (14b2230)

๐Ÿ› Bug Fixesโ€‹

  • cache: fixed massive redis session keys creation for each http request (01d1edd)
  • catalog: fix catalog audience targeting check feature (f87d465)
  • cdn: added root file to support UptimeRobot monitoring (e35db66)
  • feature-toggles: fixed issue preventing catalog to launch (8a09416)
  • service-account: fixed service account refresh after update (d149a6b)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • api: moved api root from /v1.0 to /api/v1.0 (77b6f10)
  • cdn: renamed /cdn/staging to cdn/integration (b282470)
  • environment variables: refactored environment variables management (83e04f8)
  • environments: environment variables preprocessing is now done from environment.js (ef9f499)
  • guthub: migrated github ops token to the new format (0a7b5b9)
  • monitoring: moved appinsights initialization to the instrumentation module (a6d342c)
  • ms-graph: improved logging in getUserDirectoryRole function (3ca8863)
  • ms-lists: removed ms-lists dependency (eb3c3d4)
  • packages: renamed packages zip file name without "automation" for easier readibility (b8481ca)

๐Ÿ“š Docsโ€‹

  • audits: added an automatically generated Audits Index (c8bd5d7)
  • audits: added uptimerobot data export to npm run audit script (c1a6bd4)
  • audits: updated audit index format (dcda3e4)
  • depcheck: included depcheck as part of the audit reports generated from npm run audit (8fa391b)
  • environment variables: moved to the root to prevent jekyll errors (50c9f3d)
  • packages: new packages index (4742bd7)

3.10.0 (2021-09-16)โ€‹

๐Ÿš€ Featuresโ€‹

  • feature-toggles: enabled feature toggles service in all envs in std and role-specific mode (d139535)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • feature-toggles: refactored service (40b92d9)
  • mail-alerts: disabled mail alerts for all environments, keeping github for ppr and prd (a801824)

๐Ÿ“ฆ CIโ€‹

  • ๐ŸŽก updated gh action scripts to use npm install for std (1f70df5)
  • feature-toggles: added st-featuretoggles-prd-01 to GitHub actions CI/CD (0b4f397)
  • feature-toggles: updated int gh action script to use npm install instead of npm ci (e133481)
  • infrastructure: added two new audit scripts db:stats and cache:stats (24e7e0a)

๐Ÿญ Build Systemโ€‹

  • appservice: added .deployment and scripts for fastest deployment (34e4980)
  • ci-cd: updated github action scripts to use npm install instead of ci (ca1e403)
  • deps-dev: bump adm-zip from 0.5.5 to 0.5.6 (ee38d21)
  • deps: bump ajv from 8.6.2 to 8.6.3 (c37d3c6)
  • deps: bump alpinejs from 3.3.2 to 3.3.3 (722d7b3)
  • deps: bump applicationinsights from 2.1.6 to 2.1.7 (a57ffe2)
  • deps: bump unleash-proxy-client from 1.3.0 to 1.4.0 (1242b6e)
  • deps: bump zaproxy/action-baseline from 0.4.0 to 0.5.0 (2b37e25)
  • deps: bump zaproxy/action-full-scan from 0.2.0 to 0.3.0 (dae08b1)
  • feature-toggles: removed github action yml file (75cb6fa)

๐Ÿ› Bug Fixesโ€‹

  • feature-toggles: disabled unleash on client-side (bdb73be)
  • feature-toggles: updated gh action deployment script to use npm install instead of ci (56cbd0f)
  • service-account: fixed refresh issue after updating or removing a service account (558eed7)
  • service-account: fixed service account update from the settings tab (ce6732e), closes #946

3.9.0 (2021-09-09)โ€‹

๐Ÿš€ Featuresโ€‹

  • feature-toggles: configured smtp parameters for emailing from the Unleash service (2d191a2)
  • feature-toggles: feature-toggles service is now enabled and available in standalone mode (ce4776d)
  • feature-toggles: installed "Unleash" to implement feature toggles (cbcc222)

๐Ÿ› Bug Fixesโ€‹

  • i18n: locales not loaded from the login and main pages (022e716)

3.8.1 (2021-09-09)โ€‹

๐Ÿญ Build Systemโ€‹

  • deps: bump axios from 0.21.1 to 0.21.4 (d38112b)
  • deps: updated axios (69f672b)

๐Ÿ› Bug Fixesโ€‹

  • i18n: reintegrated locales to the cdn legacy folder in /dist (2b5159e)
  • package: fixed issue with old teams home packages that were using query parameters (01d8897)

๐Ÿ› ๏ธ Code Refactoringโ€‹

  • cdn: cdn assets are now distincts between staging and production (691a629)
  • i18n: changed dist / cdn folder structure to enable "staging" and "production" (5652d38)

[3.7] (2021-09-09)โ€‹

๐Ÿ› ๏ธ Code Refactoringโ€‹

Build Systemโ€‹

  • changelog: integrated commitzen and standard-version (ffe2d89)
    • New changelog format generated from commits
  • npm: updated npm scripts for the build/release process (823f430)
  • changelog: added .versionrc to configure changelog generation (215156e)
  • deps: bump @nboldhq/i18n from abe8038 to 3ec1717 (b70238f)
  • deps: bump alpinejs from 3.3.1 to 3.3.2 (ff2d1c3)
  • versions: extracted version bump from npm build scripts (73c9191)

Bug Fixesโ€‹

  • login: fix issue with login attempts without admin consent (63f6f6b)
  • rbac: fixed rbac control for restricted tabs (3206c06)
  • npm: removed segfault-handler dependency (e08826e)

[3.6] (2021-09-02)โ€‹

  • fixed: API Error Solution for "413 Request Entity Too Large" error
    • Probably the origin of this issue "Impossible to create a new template in PPR" #897
    • Resolution: update express middlewares by specifying a body content limit to 50mb
    app.use(bodyParser.json({limit: '50mb'}))
    app.use(bodyParser.urlencoded({limit: '50mb', extended: false}))
  • changed: Better error handling in tabs configuration
    • Example:
      • Error in in graphServices/getPlannerPlan. (PRD) #2002851
      • Origin: Happens when the service account doesn't have access to the original plan
    • Error:
      • Error message: Forbidden
      • Error status: 403
      • Error response text: {"error":{"code":"","message":"You do not have the required permissions to access this item.","innerError":{"date":"2021-09-02T07:21:45","request-id":"7773f54f-5056-4214-8f84-549360adfa28","client-request-id":"7773f54f-5056-4214-8f84-549360adfa28"}}}
      • Error stack: Error: Forbidden
    • Improvements:
      • When this kind of exception happens (except for explicitely unsupported tabs such as Wiki or OneNote):
        • The audit trail mention the error with the tab and application name
        • An organization_configuration_issue_raised event is triggered and the issue is tracked in the corresponding table accessible from our admin portal, with this payload:
          issue_type: 'TAB_CONFIGURATION_ISSUE',
        tenant_id: customer.msTenantId,
        tenant_initial_domain: customer.msTenantInitialDomainName,
        tenant_default_domain: customer.msTenantDefaultDomainName,
        message: `"${tabDisplayName}" (${appDisplayName}${message})`,
        status: 'open',
        diagnostic_data: JSON.stringify({
        tab_display_name: tabDisplayName,
        app_display_name: appDisplayName
  • fixed: Team creation getting stuck at 10% #888
    • Changed the behavior of requests limiters by setting the maxConcurrent option to null.
    • It appears that with a non-null value defined, some requests were leaked.
    • See:
    • Also fixes:
      • Teams creation provisioning blocked at Planner tab #896
      • Impossible to create a new template in PPR #897
  • added: Team provisioning audit trails are now saved in the events db from the team_provisioning_audit_entry_created event (in addition to beeing saved in the job)
  • changed: Error alerts are now temporarily sent by email in addition to as a GitHub issue in all environments for debugging purposes.
  • changed: Group updates operations for email nickname and sensitivity labels are now executed through distincts functions
  • changed: GitHub alerts issue creation is now managed by a request limiter to prevent beeing throttled
  • refactor: Connected Apps and Governance pages optimization
    • /integration and /governance are now loaded from the main component
    • Cleaned bundled js and css
  • refactor: Client instrumentation initialization code is now running asynchronously and uses the client_state object
  • changed: Issues in the ops repo are now created by our GitHub service account:
    • Login: st-service-cicd
    • token: st-ops
    • Scope: repo
    • Has Access to the Ops repo with write access
  • changed: The Connected Apps module is now managed from a dedicated repo to enable external contributors
  • added: Admin Dashboard
  • added: cloc code statistics report generated as part of the build (lines, comments, code...)
  • changed: Migrated alpinejs from v2 to v3
  • added: auth module
    • Implements clientCredentialsFlow for automated tests and future service-account-free (application) mode.
  • added: Queues monitoring dashboard
    • Uses Bull Board
    • Accessible from the admin dashboard (Queues page) or /admin/queues
    • Protected with the same authentication than the whole /admin portal
  • added: Tests and documentation for the i18n repo
  • changed: Private GitHub Packages
    • Our individual packages are now published in our organization GitHub Packages
    • For instance with the @salestim/ms-lists repo.
      • package.json Incldes a publishConfig property that sets the access to restricted (to our organization) and defines GitHub Packages as the registry
        "publishConfig": {
        "access": "restricted",
        "registry": ""
      • Could be published using npm publish (and the appropriate token scope)
    • From the @salestim/app-platform repo:
      • .npmrc file defines:
        • GitHub Packages as the registry for all packages from the @salestim scope through @salestim:registry= (local packages referenced as 'file:' are not impacted)
        • The token to use to connect to GitHub Packages. To avoid to use a specific user personal access token, we're now using a new service account (that will be used for all the CI/CD operations)
          • Microsoft Azure AD Account (required because GItHub enforces SSO)
          • GitHub account:
            • Login: st-service-cicd
            • Access Token name: st-cicd (SSO must be enabled)
            • Scopes: read:packages
      • The @salestim/ms-lists package can be referenced as a dependency using "@salestim/ms-lists": "^1.0.X"
  • changed: Remote git repo dependencies management
    • The @nboldhq/i18n is public, and can therefore be referenced as a dependency by:
      • "@nboldhq/i18n": "nBold/i18n"
      • NPM assumes that this is a public GitHub repo, therefore no protocol has to be defined
  • fixed: Default values future deprecation for express-session middleware was generating warnings
    • Errors:
      • express-session deprecated undefined resave option; provide resave option node_modules/@adminjs/express/lib/buildAuthenticatedRouter.js:56:41
      • express-session deprecated undefined saveUninitialized option; provide saveUninitialized option node_modules/@adminjs/express/lib/buildAuthenticatedRouter.js:56:41
    • Reason:
    • Fix:
      • Set values for saveUninitialized and resave in AdminJSExpress.buildAuthenticatedRouter
      saveUninitialized: false,
      resave: false
  • fixed: Default values for express.urlencoded middleware was generating warnings
    • Errors:
      • body-parser deprecated undefined extended: provide extended option src/app/app.js:211:21
    • Reason:
    • Fix:
      • Set values for extended and resave in app.use(express.urlencoded
      app.use(express.urlencoded({ extended: false }))
  • added: Jupyter notebook as an interactive documentation for the webhooks module.
    • Uses Jupyter notebook and the iJavascript kernel
    • Installation:
      # Install PIP Python installer
      sudo apt install pip
      # Install Jupyter notebook
      pip install notebook
      # Install nodejs prerequisites
      sudo apt-get install nodejs-legacy npm ipython ipython-notebook
      # Install ijavascript
      sudo npm install -g ijavascript
      # Start ijavascript install
  • References:
  • changed: Our Redis servers now enforce TLS v1.2 minimum
  • added: Daily job that cleans all jobs entries in cache older than 24h
    • Uses the Bull queues Clean method
  • fixed: The service account token renewal job failed in case of non-existing registered tenant (happens when a demo tenant expires for instance)
    • Root cause: The refreshtokensimple operation was not calling the expected callback method, therefore the job was permanently flagged as active.
  • changed: Replaced the external body-parser module with the one built in express (Starting Express 4.16+)
  • changed: Homepage performance optimizations
    • Unified client state:
      • The whole client state (environmenty variables, Intercom configuration, user profile, organization configuration...) is now rendered directly from the server as JS variables, directly accessible to the client js code.
      • From 6 to 0 requests during the initialization of the page
    • Batched Microsoft Graph Requests:
      • All the requests made to retreive teams and groups properties are now batched (per batch of 12 as the pagination)
      • From 96 requests per page to 6 requests per page
    • Serving static resources from our CDN
      • All the html components are now rendered from the CDN instead of from out servers
    • Cached infos used to authenticate calls to the platform's API
      • All the server-side methods used during the authentication of api requests are now cached
        • Retreive the organization from Cosmos DB:
          • cosmosDbServices.getCustomerByTenantId
          • ORGANIZATION_CACHE_DURATION: 1000 * 60 * 5, // 5 minutes
        • Calculate the roles of the current user from its token
          • graphServices.userHasDirectoryRole
          • USER_ROLE_CACHE_DURATION: 1000 * 60 * 5, // 5 minutes
  • added: App package customization from Microsoft Teams Admin Center
  • added: Jest test framework + coverage analysis
    • Run test manually (also triggered by CI/CD GitHub action): npm run test
    • Test report generated as part of the build:dist npm script
    • Report is generated at ./docs/audits/tests/tests_report.txt and available from
      • How to tead the report:
        • Statement (Stmts) coverage Has each statement in the program been executed?
        • Branch coverage Has each branch (also called DD-path) of each control structure (such as in if and case statements) been executed? For example, given an if statement, have both the true and false branches been executed? Another way of saying this is, has every edge in the program been executed?
        • Function (Funcs) coverage Has each function (or subroutine) in the program been called?
        • Line coverage has each executable line in the source file been executed?
  • added: SonarQube analysis
  • changed: Abstracted and dynamic configuration for Microsoft Graph and Microsoft Azure AD environments (National Cloud Deployments)
    • The Microsoft Graph base URL is now defined from the MICROSOFT_GRAPH_BASEURL environment variable (default to
    • The Microsoft Azure AD base URL is now defined from the MICROSOFT_IDENTITY_PLATFORM_BASEURL environment variable (default to
  • changed: Shared Channels support
    • The code is ready to enable the support of shared channels
    • This feature will be enabled when the support of shared channels will move from the /beta to /v1.0 Microsoft Graph endpoints
  • changed: I18n resources now integrated as a private npm module
    • Before: json resources files were downloaded from the public repository as part of the build process using a custom code
    • Now:
      • The resources are integrated as a private npm package through a standard npm install (see package.json)
  • fixed: Membership policies not reflected on the existing teams #788
    • fixed: Create/Update record in the teams directory table on creation
    • changed: The Governance job "Permanent membership policy" is now triggered by our scheduler (every 5 min)
    • Supported scenarios:
      • new member/owner added in a template > Added to every team attached to the template
      • deleted member/owner in team > Re-invited
      • team owner demoted to member > Re-promoted as owner
      • deleted member/owner in channel > Re-invited
      • channel owner demoted to member > Re-promoted as owner
    • added: 2 new audit trails are available in a new "Governance" tab
    • added: 2 new webhooks are available for notifications/tracking:
      • permanent_membership_policy_team_user_invited
      • permanent_membership_policy_channel_user_invited
    • changed: regular users and the service account are now using different graph permission scopes (requires a new service account sign-in)
    • Known issues:
      • For the "Permanent membership policy" to work, the service account must be signed-in again
      • The "Permanent membership policy" will only apply to new created teams (See the "Governance"\"Teams Management" tab)
  • added: Run nBold platform using Docker
    • Migrated development environment from "Docker for WSL" (WSL using the docker service hosted by Windows) to a native linux docker daemon (started on boot using service instead of systemd)
    • Updated the guide
    • Created npm scripts for building and starting each environment/role
      • Build: npm run build:docker:[ENV]:[ROLE]
      • Start: npm run start:docker:[ENV]:[ROLE]
  • added: is now monitored by UptimeRobot as CDN. See
  • refactor: Externalization of key features as private NPM modules
    • Why:
      • Self-contained, better isolation
      • No more cross-dependencies (Dependencies are dynamically injected at runtime)
      • Modules dependencies are installed as node_modules by npm install
      • Individual configuration from environment variables with safe defaults
      • Each module could be externalized in its own dedicated repo later
    • New NPM modules in the /src/modules folder
      • Cache
      • DB
      • Events
      • GitHub
      • i18n
      • Mail
      • Sandbox
      • Webhooks
  • changed: Team name now supports the "_" character. See: #849
  • added: PPR and PRD GitHub Actions full deployment scripts
  • changed: OWASP ZAP Baseline Scan
  • added: OWASP ZAP Full Scan
  • changed: Updated GitHub deployment actions versions

[3.4] (2021-07-05)โ€‹

  • fixed: Channels are not provisioned #828
    • Detected in Ops:
      • Error in /graphServices/cloningMissingChannels/createChannel. (PRD) #1757382
        at createChannel (/home/site/wwwroot/src/microsoft/graph/graphServices.js:3599:19)
        at graphLimiter.submit (/home/site/wwwroot/src/microsoft/graph/graphServices.js:6780:48)
        {"statusCode":400,"code":"BadRequest","message":"Invalid OData type specified: ""","requestId":"1a7c87e9-483a-417f-b776-815aa90ef12c","date":"2021-07-05T15:17:10.000Z","body":"{"code":"BadRequest","message":"Invalid OData type specified: \"\"","innerError":{"date":"2021-07-05T15:17:10","request-id":"1a7c87e9-483a-417f-b776-815aa90ef12c","client-request-id":"f4a45710-a1cc-4f07-c641-9df1eb683c53"}}"}
    • Root cause: Undocumented update for the v1.0 CreateChannel endpoint
  • changed: Additional server protection with the Helmet package
    • A bout Helmet:
    • Benefits:
      • Less security warnings in our automated pentests
      • Better control over third-party client-side modules (mostly Intercom)
      • We now have a better control over resources origins (scripts and css) and targets (Graph, Azure...)
    • Configuration
      contentSecurityPolicy: {
      useDefaults: true,
      directives: {
      'frame-ancestors': ["'self'", ''],
      'default-src': ["'self'", 'https://*', '', '', '', 'wss://', 'https://*'],
      'script-src': ["'self'", '', '', '', '', '', "'unsafe-eval'", "'unsafe-inline'"],
      'script-src-attr': ["'self'", '', '', "'unsafe-eval'", "'unsafe-inline'"],
      'img-src': ["'self'", 'data:', '', '', '', '', '']
  • changed: /dist folder now accessible from instead of
    • Related documents have been updated on tech hub and handbook
  • changed: Static assets (Images, fonts, css, compiled js...) are now distributed through GitHub Pages as a CDN
  • changed: finalize dependency updates
    • All our third-party dependencies are now up to date with their respective latest version, excluding:
      • Alpine.js: migration impacts from v2 to v3 have to be evaluated
      • Bootstrap: migration impacts from v4 to v5 have to be evaluated
  • fixed: Coding style / security best practices issues
    • Standard JS coding style linter: From 1600 to 8 identified issues
    • ESLint security issues: From 1866 to 10 identified issues (only from the recent connected apps modules)
  • changed: public assets
  • changed: Dependency cleaning
    • Why: A lot of dependencies are not used anymore (mostly replaced by another one, sometimes the associated feature is not implemented anymore)
    • Results:
      • Decreased deployment duration in integration from 8 to 3 min (1min for the entire build, 2 min to deploy to azure)
      • GitHub dependency alerts reduced from 6 to 2
    • Removed modules:
      • Production
        • "@octokit/rest": "^16.36.0",
        • "ace-builds": "^1.4.7",
        • "acorn": "^7.4.1",
        • "advanced-search-query": "^5.1.1",
        • "botbuilder": "^4.13.3",
        • "cheerio": "^1.0.0-rc.9",
        • "clearbit-logo": "0.0.1",
        • "colorthief": "^2.3.2",
        • "daemonite-material": "^4.1.1",
        • "datatables": "^1.10.18",
        • "": "^1.10.23",
        • "encodeurl": "^1.0.2",
        • "escape-html": "^1.0.3",
        • "eslint-plugin-react-hooks": "^2.3.0",
        • "etag": "^1.8.1",
        • "extract-data-from-text": "^1.0.2",
        • "helmet": "^3.21.2",
        • "into-stream": "^5.1.1",
        • "jsforce": "^1.10.1",
        • "knex": "^0.21.16",
        • "knex-migrate": "^1.7.4",
        • "masonry-layout": "^4.2.2",
        • "merge-descriptors": "^1.0.1",
        • "method-override": "^3.0.0",
        • "modernizr": "^3.11.7",
        • "node-email-reply-parser": "^0.1.1",
        • "opencollective-postinstall": "^2.0.2",
        • "parse-domain": "^2.3.4",
        • "react": "^16.14.0",
        • "react-dom": "^16.14.0",
        • "restify": "^8.5.1",
        • "serve-index": "^1.9.1",
        • "summernote": "^0.8.15",
        • "uikit": "^3.6.21",
        • "underscore": "^1.13.1",
        • "url-polyfill": "^1.1.12",
        • "vcard-parser": "^1.0.0",
      • Development
        • "@microsoft/microsoft-graph-types": "^1.37.0",
        • "adaptivecards": "^2.6.0",
        • "archiver": "^3.1.1",
        • "autoprefixer": "^10.2.4",
        • "better-docs": "^1.4.7",
        • "css-loader": "^5.2.4",
        • "cssnano": "^4.1.11",
        • "gulp-copy": "^4.0.1",
        • "gulp-csso": "^4.0.1",
        • "gulp-eslint": "^6.0.0",
        • "gulp-exec": "^4.0.0",
        • "gulp-htmlmin": "^5.0.1",
        • "gulp-jsdoc3": "^2.0.0",
        • "gulp-jslint": "^1.0.10",
        • "gulp-markdown-toc": "^1.1.0",
        • "gulp-plumber": "^1.2.1",
        • "gulp-rename": "^2.0.0",
        • "gulp-string-replace": "^1.1.2",
        • "gulp-terser": "^1.4.1",
        • "gulp-uglify": "^3.0.2",
        • "gulplog": "^1.0.0",
        • "jsdoc": "^3.6.7",
        • "node-pandoc": "^0.3.0",
        • "npm-license-crawler": "^0.2.1",
        • "shx": "^0.3.3",
        • "sloc": "^0.2.1",
        • "snazzy": "^8.0.0",
        • "style-loader": "^2.0.0",

[3.3] (2021-06-18)โ€‹

  • fixed: Issue with flags on template language #814
  • fixed: Salestim display in Pl-Pl fails to default to english #813
  • fixed: Planner Provisioning not Working in PPR #812
    • Updated the app installation process, but the root cause seems to be that the service account didn't had access to the app (or may it needs to open it once... to be checked)
    • Fixes this other related issue: "Planner provisioning failing with same planner added in the tab in PPR" #815
  • fixed: Provisioning stucked at "Processing Request" #807
    • The provisioning engine does not rely on the standard cloning feature anymore
    • Fixed multiple 401 errors with token renewal
    • Now the service account access token is refreshed on provisioning startup
  • fixed: nBold app & nBold home: BLANK #801
    • Analysis:
      • Looks like the issue only affects some tenants (Maybe related to waves of migrations/deployments on MS side)
      • Browser console stack trace: Failed to load resource: the server responded with a status of 403 (Forbidden)
        main.js:3049 Error retreiving user roles.
        error @ main.js:3049
        main.js:3050 Object
        main.js:181 Error loading user roles{"readyState":4,"responseText":"{\"message\":\"This resource requires one of the following roles: AUTHORIZED_APP,AUTHENTICATED_USER\"}","responseJSON":{"message":"This resource requires one of the following roles: AUTHORIZED_APP,AUTHENTICATED_USER"},"status":403,"statusText":"Forbidden"}
        (anonymous) @ main.js:181
    • Updates:
  • changed: Update to the GenerateHookSignature API operation and PowerPlatform action
    • The endpoint signature now only accepts a json object for the payload parameter instead of a string, in order to avoid encoding issues.
    title: Hook Signature Request
    description: A HookSignatureRequest object comprised of the secret and payload.
    type: object
    description: Webhook secret
    type: string
    description: Webhook payload
    type: object
    - secret
    - payload
  • fixed: Folders Copy not working for a specific Template #749
    • Reference:
    • Reported failed requests:
      • Tuesday, April 6, 2021 7:13 AM:32: ๏“ฎ Saved : Request saved with id 'e89081d1-955c-4ad4-b734-d0311bb21e7b-72bc4e4a-d71b-4a36-a2eb-40ff2a8a19f8-ed396cce-b38a-4b01-b2a4-5d4b68225031'
      • Monday, April 5, 2021 5:39 PM:56: ๏“ฎ Saved : Request saved with id 'e89081d1-955c-4ad4-b734-d0311bb21e7b-72bc4e4a-d71b-4a36-a2eb-40ff2a8a19f8-359c8faf-fb5a-4c82-9853-a8612b71594b'
      • tid: e89081d1-955c-4ad4-b734-d0311bb21e7b
      • uid: 72bc4e4a-d71b-4a36-a2eb-40ff2a8a19f8
      • teams context:
    • Resolution:
      • The graphHelper/getTeamsDriveChildren function was using the Graph SDK. Now replaced by a 'request' operation
  • changed: In-product release notes now restricted to "Change managers"
  • changed: Connected Apps features visibility
    • The Connected Apps tab is only visible to users with the "Change Manager" role (OR teams service admin or global admin)
    • The Audit Trails tab is only visible to users with the "Change Manager" AND "Compliance Managers" roles (OR teams service admin or global admin)

[3.1] (2021-05-30)โ€‹

  • fix: Error in approveApproval: Cannot retreive requester user (PRD) #790
    • Error message:
      at Object.logInternalServerError (/home/site/wwwroot/src/app/api/api-helper.js:32:20)
      at /home/site/wwwroot/src/app/api/routes/approvals/approvals.js:704:25
      at Object.getUser (/home/site/wwwroot/src/microsoft/db/cosmosDB/cosmosDbServices.js:44:28)
    • Root cause:
      • At line 633 of approvals.js, the function is expecting a nBold internal user ID, and receives instead an Azure AD object ID.
  • added: In-product release notes
    • Implemented using the Headway app
    • Public release notes page:
    • Message is shown in the home navigation bar only if there are unseen updates
    • The counter uses eyecatching animations so users are nagged to click the badge
    • For testing purposes, the unseen count could be reinitialized from the Advanced menu (8 clicks on the app icon)
  • added: Webhooks run history
    • A new internal event webhook_run_executed is triggered when a new webhook job is done
    • The webhook job is tracked in our events tables evt_webhook_run_executed, with the following properties:
      • Tenant ID
      • Webhook ID
      • Run ID
      • Payload
      • Start date
      • End date
      • Duration (ms)
      • Attempts
      • Status: Succeeded/Failed
      • Failed reason
    • New API operations:
      • getaudittrails, getaudittrail
        • /audittrails/:code with code = 'webhook_run_executed'
      • Accessible from the API Explorer
    • From the Integration page, we now have a new tab "Audit Trails" that shows all the audit trails for the connected apps and webhooks for the last 28 days
      • Support for I18n
      • download audit trails as excel
    • Availability: User need both CHANGE_MANAGER and COMPLIANCE_MANAGER to see this feature
  • changed: Throttling headers are now included in CORS requests
    • Rationale: CORS requests have limitations and show only a subset of headers:
      • Cache-Control
      • Content-Language
      • Content-Type
      • Expires
      • Last-Modified
      • Pragma
    • Impact: This issue doesn't impact API requests made from a third-party client or server app, only web clients
    • Solution: In order to show more headers on the response, the server has to add a header to allow more extra headers.
      • The API server now systematically includes the following headers:
        • 'Access-Control-Expose-Headers': 'X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After'
      • Headers could be iterated from the client by:
        for (var pair of res.headers.entries()) {
        console.log(pair[0]+ ': '+ pair[1]);
    • Control: Try to refresh an audit trail more than 6 times in a row to see the warning message.
  • added: Advanced error diagnostic for issue: Error in graphHelper/userHasDirectoryRole/getDirectoryRoles #787
  • changed: JS bundles and mins are now excluded from eslint and standard audit reports
  • changed: Power Automate and Logic Apps connector labels
  • Changed: Power Automate and Logic Apps connector default webhook name and description
    • Now each trigger (starting with "When...") sets its own default values for the webhook name and description
  • changed: Migration to FontAwesome 5.15.3
    • Replaced the npm package "font-awesome" v4.7 to "@fortawesome/fontawesome-free" v5.15.3
  • added: Service account granted permissions are now visible from the "Settings" tab
  • fixed: Check if the service account is a member of a team selected as template from the catalog
    • Works again, using a new control technique
  • added: The OpenAPI definition of the /hooks operation now describes the events and body schema of all the possible callbacks from all the supported webhooks.
  • changed: The TeamProvisioningCompletedNotificationPayload object (payload of the team_provisioning_completed webhook), now has an additional metadata property holding the metadata passed to the createTeamProvisioningJob operation
  • changed: Metadata
    • Metadata passed through the createTeamProvisioningJob operation
      • The createTeamProvisioningJob operation accepts an arbitrary json object that could be used as a naming convention tag, or for further reference from the API
      • Input:
      "metadata": {}
      • Storage
        • Metadata passed through the createTeamProvisioningJob are stored as a "freeform_metadata" jsonb field on the "team" table in DB
        "freeform_metadata": {}
    • Metadata defined by a connected app
      • When an event is raised, or a job is executed, a connected app can store/update metadata and associate them with an object (team, channel or tab)
      • Storage
        • To keep the DB schema static, we're leveraging a single partitioned jsonb field in Postgresql
        • Connected apps metadata are stored as a "connectedapps_metadata" field on "team", "channel" and "tab" tables, each one partitioned in its own key:
        "connectedapps_metadata": {
  • fixed: Mobile app rendering issues preventing app publishing to the Teams store
    • All the screen now have narrowed external margins
    • Fixed the cards width on mobile
    • Removed query parameters from teams packages, it now relies only on the url path (/home, /catalog...)
    • Debugging tool used to remotely access the browser console:

[3.0] (2021-04-16) - Codename "Shodai"โ€‹

[2.2] Codename "Kakuryu" - (2021-04-07)โ€‹

  • added: New Power Platform actions #powerplatform
  • added: API Explorer development mode
  • changed: Power Platform information from the "Integration" tab #powerplatform
    • From the integration tab, a message in the card header indicates if the webhook is a custom one, or created from Power Platform
    • From the webhook details, if the webhook is coming from Power Platform, is shows the workflow ID, name and operation
  • changed: API and Power Platform "Hooks" endpoint are now restricted to integration managers by RBAC
    • API operations:
      • GetHooksEvents
      • CreateHook
      • DeleteHook
      • GenerateHookSignature
    • Power Platform triggers and actions:
      • TeamCreatedHook
      • TeamProvisioningCompletedHook
  • added: New Power Platform connector triggers: team_created and team_provisioning_done #powerplatform
  • added: New Power Platform connector test connection endpoint #powerplatform
  • changed: Power Platform operations versioning #powerplatform
  • added: New Power Platform documentation section: "Update the Power Platform Connector" #powerplatform
  • added: New Power Platform actions and triggers documentation #powerplatform
  • added: New Power Platform "teams" actions #powerplatform
    • GetTeam
    • GetTeamChannels
    • GetTeamPrimaryChannel
    • CreateTeamChannel
    • GetTeamChannelTabs
    • CreateTeamChannelTab
  • added: New Power Platform action "GenerateHookSignature" #powerplatform
    • Purpose: bring Power Platform the capability to verify the signature generated from a webhook secret.
    • Testing procedure:
      • Create a new "Automated cloud flow" and skip the assistant
      • Add a "When a HTTP request is received" trigger
      • Add a "Compose" action and name it "Get Webhook Signature Header"
        • Retreive the "X-nBold-Signature" header using this formula triggerOutputs()['headers']['X-nBold-Signature']
      • Add a "Compose" action and name it "Get Webhook Payload"
        • Retreive the payload using this formula triggerBody()
      • Add a nBold action "Generate a signature from a secret and a webhook payload"
        • Set the secret value previously used during the webhook creation
        • Set the "Webhook payload" to the result of the "Get Webhook Payload" action
      • You can then compare the signature retreived from the "Get Webhook Signature Header" action with the signature calculated from the nBold "GenerateHookSignature" action. If they match, it means that the request was effectively coming from nBold.
  • added: Webhooks payloads examples and schema #api
  • fixed: API explorer errors #api
    • The API openapi definition is up to date
    • Login / Logout works from the API Explorer
  • changed: API Rate Limits #api
  • added: Global Node/Express timeout #api
    • Implemented the connect-timeout module
    • All the API requests now timeout after 5 seconds
  • changed: TechHub "Code Copy" feature #techhub
    • New "Copy Code" plugin that doesn't interfer with the language tag + Complete review of all the code blocks
  • changed: Naming convention page #techhub
    • Naming conventions page in Tech Hub was updated to reflect the new team name length (to 264) and authorized characters (such as "|")
  • fixed: Approval workflow: multiple and unreadable automated emails #629
  • added GitHub actions have now a workflow_dispatch trigger so that actions could be started manually
  • fixed: Audience Targeting - syntax display issue #739
  • fixed: Naming Convention - policy display issue #737
  • changed: Azure Application Insights configuration #AAI
    • Client-side events
      • New "Page View" events to track pages and high UI-level activities:
        name: 'loginsso',
        pageType: 'page'
        name: 'home',
        pageType: 'page'
        name: 'newprovisioningrequest',
        pageType: 'popin'
        name: 'myprovisioningrequests',
        pageType: 'popin'
        name: 'catalog',
        pageType: 'page'
        name: 'newtemplate',
        pageType: 'popin'
        name: 'edittemplate',
        pageType: 'popin'
        name: 'integration',
        pageType: 'page'
        name: 'hooks',
        pageType: 'tab'
        name: 'newhook',
        pageType: 'popin'
        name: 'savehooks',
        pageType: 'form'
        name: 'connectedapps',
        pageType: 'tab'
        name: 'settings',
        pageType: 'page'
        name: 'permissionmodel',
        pageType: 'tab'
        name: 'serviceaccountupdate',
        pageType: 'tab'
        name: 'serviceaccountremove',
        pageType: 'tab'
        name: 'serviceaccountcheck',
        pageType: 'tab'
        name: 'approvalsettings',
        pageType: 'tab'
        name: 'rbacsettings',
        pageType: 'tab'
        name: 'systeminformation',
        pageType: 'tab'
        name: 'systeminformationenvironment',
        pageType: 'tab'
        name: 'systeminformationlicense',
        pageType: 'tab'
        name: 'systeminformationlegal',
        pageType: 'tab'
        name: 'unauthorized',
        pageType: 'page'
      • "Page View" events properties:
        • Standard properties (Automatically collected):
          Page view URL: ''
          Browser version: 'Edg 89.0'
          Country or region: 'France'
          State or province: 'Paris'
          City: 'Paris'
          Page view load time: '744 ms'
          Event time: '3/27/2021 3:58:26 PM (Local time)'
          pageView/id: '2b20a209e20d47dba44a640e998f21f9'
          View page name: 'catalog' // page code
          Performance: '500ms-1sec'
          Telemetry type: 'pageView'
          Operation name: '/catalog'
          Operation Id: '2b20a209e20d47dba44a640e998f21f9'
          Parent Id: '2b20a209e20d47dba44a640e998f21f9'
          Session Id: 'nyoxDPSyVJGI17qyptv5hg'
          // User and Auth ID defined through appInsights.setAuthenticatedUserContext
          User Id: 'uASTl' // Anonymous user id generated by AAI
          Auth Id: '' // Set by nBold as the user UPN
          Account Id: 'af54e9f5-6b9e-488f-b1e7-d97ff21b1cf3' // Set by nBold as the tenant ID
          Device type: 'Browser'
          Device model: 'Other'
          Operating system: 'Windows 10'
          Client IP address: ''
          // Cloud role and instance defined through envelope.tags[''] and envelope.tags['']
          Cloud role name: 'webclient' // Set by nBold for the web app
          Cloud role instance: '' // Set by nBold as the user UPN
          SDK version: 'javascript:2.5.11'
          Sample rate: '1'
        • Custom properties:
          companyName:    null // From the user profile
          tenantDefaultDomainName: // From the organization
          tenantInitialDomainName: // From the organization
          hostClientType: web // From the Teams context
          preferredLanguage: en // From the user profile
          userObjectId: c12e8c68-ba71-47ed-84bb-ab68e8452bf3 // From the Teams context
          displayName: Guillaume Meyer // From the Teams context
          department: null // From the user profile
          jobTitle: null // From the user profile
          locale: en-us // From the Teams context
          email: // From the user profile
          tid: af54e9f5-6b9e-488f-b1e7-d97ff21b1cf3 // From the Teams context
          upn: // From the Teams context
    • Server-side events
      • Identified by:
        'Cloud role name': 'app:ppr', // Role of the container. Use the format ROLE:ENVIRONMENT
        'Cloud role instance': 'st-app-ppr-01'// The unique container name. Use the format st-ROLE-ENVIRONMENT-INSTANCE
  • added: New server roles: Service Discovery, Scheduler
    • Service Discovery: Exposes through an api endpoint the whole configuration
    • Scheduler: Schedule jobs and distribute workload through workers
    • Infrastructure changes:
      • PPR environment:
        • st-app-ppr-01
        • st-api-ppr-01
        • st-job-ppr-01
        • st-connectedapps-ppr-01 (new)
        • st-discovery-ppr-01 (new)
        • st-scheduler-ppr-01 (new)
      • PRD environment:
        • st-api-prd-01
        • st-api-prd-02
        • st-app-prd-01
        • st-app-prd-02 (new)
        • st-connectedapps-prd-01 (new)
        • st-discovery-prd-01 (new)
        • st-events-prd
        • st-job-prd-01
        • st-job-prd-02 (new)
        • st-scheduler-prd-01 (new)
  • Changed: "Layered" App Service Plans
    • Purposes:
      • Create more isolation between the architecture layers (web, api, jobs...)
      • Ease performance monitoring and scalability
    • Each layer now has its own app service plan to scale it more easily
      • st-serviceplan-app-prd (Web servers)
        • st-app-prd-01
        • st-app-prd-02
      • st-serviceplan-api-prd (API servers)
        • st-api-prd-01
        • st-api-prd-02
        • st-connectedapps-prd-01
        • st-discovery-prd-01
        • st-events-prd
      • st-serviceplan-job-prd (Jobs servers)
        • st-job-prd-01
        • st-job-prd-02
        • st-scheduler-prd-01
  • changed: Application logs collection
    • No more custom log files stored and managed by the application. Everything is managed through Docker containers logs that dynamically collects console/stdout logs
  • added: Status monitoring for recently added services (connectedapps, discovery, scheduler, eventscollector)
  • added: Application Insights Integration
    • Purpose: Control Azure Application Insights integration through environment variables
    • MICROSOFT_APPINSIGHTS_INTEGRATION_ENABLEDD: Enable/Disable the integration with Azure Application Insights in UI and Servers
  • changed: GitHub Integration
    • Purpose: Control GitHub integration through environment variables
    • GITHUB_INTEGRATION_ENABLED: Enable/Disable the creation of GitHub issues on alerts
  • changed: SendGrid Alert Emails Integration
    • Purpose: Control SendGrid integration through environment variables
    • MAIL_ALERTS_ENABLED: Enable/Disable sending emails on alerts
  • changed: Intercom Integration
    • Purpose: Control Intercom integration through environment variables
    • INTERCOM_INTEGRATION_ENABLED: Enable/Disable Intercom integration in UI and Servers
  • fixed: API reference documentation #api
  • fixed: Naming convention in inserting named and numerical character references in team name, description and welcome message
    • Example: When using "R&D" in a team name (from the UI or the API), the generated name is "R&"
    • Origin: The EJS templating system escapes special characters
    • Resolution: Unescape the result of the EJS templating operation
    • Module: We're now using the HE module (for HTML Entities) to decode named and numerical characters
  • changed: Log files are not published to the ops repository anymore
  • fixed: Requested members are not cleared between two requests
  • fixed: Audience checkbox appears as checked even if it was previously saved as "disabled"
    • fixed a regression in template form processing as the audienceTargeting targeting was processed as "false" (as a string) instead of false (as a boolean)
    • Fixed the "Check Syntax" operation
  • changed: Team name length and authorized characters
  • changed: New cloned planner plans naming convention
    • Updated the function clonePlannerTab
    • Cloned Planner plans are now followinf the naming convention:
    const planName = `${teamDisplayName} - ${sourcePlanDisplayName}`
  • added: Channels calendar tabs configuration
    • After the channel calendar has been cloned, the provisioning process now generates the right contentUrl property value from the configuration object:
    const tabUrl = `${channelId}/tab%3a%3a${tabId}?label=${tabDisplayName}&groupId=${teamId}&tenantId=${tenantId}`
  • changed: TechHub documentation for RBAC and Audience Targeting
    • Audience targeting: Included docs and example for the tag
    • Updated RBAC docs to include our new roles, catalog managers and integration managers
  • changed: TechHub now uses Algolia for its full-text search engine.
  • changed: nBold Connector for Power Platform documentation
    • Updated the "Abstract" section
    • Added an introductory message describing the purpose of each step
    • Added a few minor additional steps
    • Added blog articles links to the "Getting Started" section
    • Graph permissions are now alphabetically ordered
    • Added a visual process overview
    • Added a plugin that enables to copy to your clipboard code blocks (such as names or URLs) in one click (easier that having to select precisely then copy)
    • Added text zones to paste temporarily the client id and secrets while executing the procedure (avoid using a notepad...)
    • Steps are now numbered for easier reference
  • changed: Environment variables
    • As a best practice, dotenv is not loaded anymore through a require from the app code itself.
    • It's instead pre-loaded through the node --require dotenv/config command-line option:
      • In execution mode, from the package.json scripts: node --require dotenv/config src/index.js
      • In development mode, from the launch.json file:
        "program": "${workspaceFolder}/src/index.js",
        "runtimeArgs": [
    • .env file has been refactored and comments improved
  • changed: Teams packages generation
    • The multiplicity of packages to generate, based on so many files, generated issues and made this process tedious and prone to errors.
    • Now all the packages (Standalone and Home) are automatically generated from only two template files.
    • All the variables are stored in the .env configuration file
    • Here is the up-to-date list of generated packages (we now have the home package for int and uat too), all of them still accessible from[PACKAGE_FILE]:
  • added: Webhooks
    • Webhooks enable organizations to trigger automated operations outside of the nBold platform, such as in a custom application, or in an automation tool such as Power Automate or Zapier.
    • See the online doc:
  • Power Platform Connector v1 #534
    • Available actions:
      • GetMyCatalogTemplates: Returns a collection of catalog templates, filtered by the audience targeting rules for the connected user
      • GetCatalogTemplates: Returns all the catalog templates, restricted to catalog administrators
      • CreateTeamProvisioningJob: Create a new team based on a template, returns a provisioning job ID
      • GetJob: Returns the current status of a provisioning request
    • Documentation:
  • changed: Updated list of downloadable packages: # PPR without sso # PPR with SSO # PRD without SSO # PRD with SSO # PRD with SSO
  • changed: Migrate to the New Microsoft Graph Team Membership Management API in v1 #624
  • fix: Prevent auto-fill on text and pickers fields
    • Problem: Under certain circumstances (when using teams from a chromium-based browser), the browser shows a list of previously selected values for forms fields
      • team name, description
      • additional members (More problematic as is masks the dropdown list of values)
    • Disabling this behavior is now enforced by using a hack to prevent the browser to use autofill on selectize fields
  • fix: Regression on tabs provisioning in PPR environment.
    • Root cause: the teamsAppId property from the tab object is deprecated from the v1.0 endpoint
    • Resolution: Instead of tab.teamsAppId, use
  • fix: Service account owner check on templates for RBAC users displays the wrong message in PPR environment.
    • The non-tenant-admin user were not able to retreive service account id from our API, making oi appear as a non-owner.
    • Resolution: Catalog admins can now access the service account ID (as long as we're using a delegated mode with a service account)
  • fix: Mandatory membership is not enforced in provisioning form in PPR environment.
    • This feature was available for standard (non-sso) authenticated users.
    • Resolution: It is now enforced for sso-connected users
  • fix: Naming convention @tags (and audience targeting) are not displayed properly in PPR environment.
    • The 'tagify' component we're using introduced a new bug in their latest version when rendering non-sanitized labels
    • Resolution: Tags labels (the one visible in the dropdown) now don't use the character '>' anymore (replaced by ':')
  • fix: #security updated bull-board to v1.2.0 due a a vulnerability in highlight.js. See
  • fixed: RBAC settings for catalog managers not applied in PPR environment.
  • fixed: Naming convention tags are not properly displayed in PPR environment.
  • changed: The "Compliance" tab is no hidden in PPR environment.
  • fix: Placeholder label in the RBAC tab (tabs.settings.rbac.catalogManagers.placeholder) in PPR environment.
  • fixed: Cannot save a new template due to an error with Summernote plugin in PPR environment.
  • changed: SSO login page optimization
    • JS and CSS bundled and minified
    • Removed unnecessary js libraries
    • Intercom is only loaded in case of admin consent required
  • changed: Admin consent page
    • Two buttons:
      • Consent as an administrator
      • I'm not an administrator > Talk to support
  • fix: Removing the emoji in the "not admin consented" message
  • added: Connected Apps server in production
  • fix: Show channel by default for requesters / owners / members #350
    • The IsFavoriteByDefault channel property is now officially supported by Microsoft: See #6792
    • During the provisioning process, nBold replicate the IsFavoriteByDefault property value from the original channel to the cloned/created one.
  • fixed: JOB RENEWSERVICEACCOUNTTOKENS: Task execution failed: Error in renewServiceAccountTokens/cosmosDbServices/updateCustomer: {"code":429,"body":"{\"code\":\"429\",\"message\":\"Message: {\\"Errors\\":[ (PRD) #655
    • This exception was causing global service interruption because this job was putting access to cosmosdb in throttled mode
    • Implemented a rate limiter for update operations (similar to the graph limiter) using the Bottleneck package
    • Job rescheduled every sunday at 6am throught cron 0 6 * * 0
  • changed: Enable Microsoft Teams App SSO for the Home package #393
  • added: Role-Based Access Control (RBAC) for Catalog Management #625
  • added: Events Services (
    • Abstract:
      • Why: We're too tied to Intercom today, and Intercom lacks many ad-hoc reporting capabilities
      • Purpose: Having a self-hosted events collector, a multiplexer, a Data Warehouse and a reports server
      • Preliminary analysis: See New events data collection platform #636
      • Relies on EventNative
    • The events service is comprised of two main workloads:
      • Events Collector API: A global and unified events collector API for the whole nBold application platform.
        • Examples of collected events:
          • Client-side: navigation across pages, clicks...
          • Server-side: containers start/stop, exceptions, new team provisioned, team template created...
        • The events collector API is accessible through a unique endpoint
      • Events Multiplexer ETL: An workflow that sends collected events to our DWH (Data WareHouse).
        • Our DWH relies on an Azure-managed PostgreSQL database that can be accessed through our Reports Server.
    • Infrastructure:
      • EventNative docker image ksense/eventnative from Docker Hub
      • Custom docker image st-events-server
      • ACR (Azure Container Registry) as a private docker registry:
      • st-events-prd app service that hosts the API and multiplexer
      • Azure Front Door exposes the st-events-prd app service to
      • Events collected from are pushed to our DWH, an Azure-managed PostgreSQL service, exposed at, in the events database.
    • Learn more: See the README file from the Events Server repository.
  • added: Reports Server (
    • Abstract:
      • A self-service report server that may query multiple data source, especially our DWH
      • Relies on Redash
      • Accessible from
    • Infrastructure:
      • The Redash instance uses the Bitnami Redash image and hosts:
        • Redash server roles
        • An embedded Redis instance
        • An embedded PostgreSQL instance
      • The Azure VM is st-reports-prd
  • added: Mandatory Owners & Members (Security Policy) #623
  • changed: Pre-production Home Package
  • fixed: Mobile Icon format issue #642
    • Fixed by updating the accentColor property from manifests files from #a60a2d to #000000
  • fixed: #security Dependency Alert: build(deps): bump find-my-way from 2.2.3 to 2.2.5 #627
  • changed: Status monitoring
    • Services status is now monitored by both UptimeRobot and Azure Front Door
    • Alerts are now sent to:
    • Uptime Robot configuration:
      • Websites are monitored as usual (basic HTTP GET probe every 5 min):
        • Help Center
        • Tech Hub
        • Website
      • App Services: Use the HTTP method HEAD on /monitoring/ping on port 443. The only accepted UP status code is 200.
        • PPR health probe frequency: 15 min
        • PRD health probe frequency: 1 min
    • Azure Front Door configuration:
      • See:
      • Monitors all instances from the PPR and PRD backend pools
        • Use the HTTP method HEAD on /monitoring/ping on port 443. The only accepted UP status code is 200.
        • Since Front Door has many edge environments globally, health probe volume for your backends can be quite high - ranging from 25 requests every minute to as high as 1200 requests per minute, depending on the health probe frequency configured. With the default probe frequency of 30 seconds, the probe volume on your backend should be about 200 requests per minute.
        • PPR health probe frequency: 255 seconds (higher possible value)
        • PRD health probe frequency: 30 seconds
  • fixed: An unhandledRejection has been detected. (PRD) #607
    • Impact: In some circumstances, the provisioning service may shutdown unexpectedly if the cloning operation raises an unknown error
    • Resolution: Better processing of the error raised by Microsoft Graph
  • fixed: [Provisionning Issue] - Impossible to create a team #604
    • related ops issue: Error cloning missing tabs in /graphServices/cloneTabsSettingsAndContents/cloningMissingChannelsAndTabs. (PRD) #357899
    • Impacted code: GraphServices.js line 3100
      // Depending on App Id
      switch (localSourceTab.teamsAppId.toLowerCase()) {
    • Root cause: the teamsAppId property from the tab object is deprecated from the beta endpoint
    • Resolution: Instead of tab.teamsAppId, use
      "displayName":"Power Apps",
  • fixed: End-users are not able to see templates #594
  • fixed: Issue in templates Title in catalog #584
    • Removed 'UrlEncoding' in display
  • changed: Support for the German language, both inside the product and for the manifests
    • Supported language / countries:
      'de-at' // Austria
      'de-ch' // Switzerland
      'de-de' // Germany
      'de-li' // Liechtenstein
      'de-lu' // Luxembourg
  • changed: Teams packages generation
    • Now during the build, teams manifests are generated using a template that inserts localized strings from our internationalization repo.
    • Purpose, avoid future errors and make our localization process more simple
    • Related issue #585
  • fixed: Build process is never ending, generating deployment errors
    • Origin: Due to the new use of i18n server in the build process to dynamically insert locales variables to the teams manifests files, the default dev mode was using an "auto-reload" mode that prevented the build process to stop as it cas constantly listening for changes.
    • fix: Disable the live-reload mode of the i18n module even in dev mode
  • fixed: #security [INFODISC01] Verbosity errors leaks internal infrastructure information #566
    • Rationale:
      • During the audit of, SYNETIS auditors have identified a medium vulnerability, allowing them to disclose some internal information about โ€œCosmoDBโ€ and more.
      • When a POST request is made to the endpoint โ€œ/updateUserโ€ if a value of a field is incorrectly set, the server return an error in JSON. Instead of a simple message, the error display lot of interesting information regarding the infrastructure of CosmoDB and the Azure Storage. This could be useful to perform another attack like SSRF (Server-Side Request Forgery).
      • Example of POST request sent to the server with a bad value in โ€œuser%5Bid%5D=โ€:
    • Implementation:
      • Returned errors from CosmosDB are not returned anymore, replaced by custom one
  • fixed: #security [INFODISC02] The endpoint โ€œ/refreshTokenโ€ send a JWT token in GET #565
    • Rationale:
      • During the audit of, SYNETIS auditors have identified a medium vulnerability, which could be dangerous if the request was intercepted or if the content of this request was logged by a tool.
      • Sometimes, the application made a GET request to โ€œ/refreshToken/[TOKEN_HERE]โ€ to ask a Bearer token to Microsoft Graph API. The problem is, because the token is sent in GET, this could be present in logs and could be dangerous in case of compromising of the server, because all JWT tokens could be easily readable.
    • Implementation:
      • The /refreshToken endpoint is now implemented to only accept POST requests with the refresh token as the POST body
  • fixed: #security [IMPROP02] Admin of an organization can modify the data of another admin (not in the same org) which can lead to account takeover #564
    • Rationale:
      • During the audit of, SYNETIS auditors have identified a high vulnerability, allowing them to modify the data of another admin which is in another organization.
      • Modification to such data could compromise customers and users. This vulnerability can also be used to craft a malicious payload and to create a Cross-Site Scripting (XSS) stored on the victim profil configuration.
      • When an administrator open the configuration tab in, he can modify his data (Provider Id for example) and save them.
    • Implementation: The global former /updateCustomer endpoint is deprecated and not available anymore, now replaced by three more granular endpoints
      • /updateCatalog
      • /updateApprovalSettings
      • /deleteServiceAccount
  • fixed: #security [IMPROP03] A user can impersonate another user when sending the approval email for creating a team #563
    • Rationale:
      • During the audit of, SYNETIS auditors have identified a high vulnerability, allowing them to impersonate another user when a team creation need an approval step.
      • When a user create a new team, if the template used is configured to have a team approved, an email is sent to the user with the โ€œapprovalโ€ role for the team.
      • When user send the request, a POST request is sent to the endpoint โ€œ/v1.0/jobs/provisioningโ€ that includes information about the requester.
    • Implementation:
      • on the client side (createRequestFromForm), now only the minimal information are sent (content of the form and the template ID), using this structure:
        team: {
        name: '',
        description: '',
        welcomeMessage: '',
        membership: {
        owners: [],
        members: []
        template: {
        id: ''
      • On the server side (/jobs/createProvisioningJob), the requester information, template information and the organization information are retreived directly from the bearer token instead of passed by the client
  • fixed: #security [SXSS01] Cross-Site Scripting (XSS) stored on 'name' and 'description' field in template creation #567
    • Rationale:
      • During the audit of, SYNETIS auditors have identified a medium vulnerability, allowing them to create a stored Cross-Site Scripting (XSS) on templates by using a weakness in the field โ€œdescription.
      • This stored XSS could be dangerous because itโ€™s reflected on all users. In case of admin account compromised, this could be impactful against the organization.
      • When the creation of a model is saved, a POST request is sent to โ€œ/updateCustomerโ€. The vulnerable field is customer[formsSettings][templates][ID][templateConfiguration][description] and customer[formsSettings][templates][ID][templateConfiguration][name]
      • When userโ€™s try to create a new team, this will load all templates configuration and the JavaScript payload too
    • Implementation: Direct html tag injection through our templating engine is now prevented by encoding the strings to prevent js injection from the following fields:
      • template name
      • template description
      • team name
      • team description
    • N.B: Code injection is still possible through naming conventions as it is the expected and the main purpose of the application
  • fixed: #security Disable attachments in /Updateuser POST and other CosmosDB interactions #572
    • Rationale:
      • The user object (and the organization object too) have an _attachment property that may permit to upload attachments. As it's not required and may be used to inject malicious files, it should be disabled.
      • Also, in addition to _attachments, we'll also hide other system defined elements such as _rid, _ts, _self, _etag to prevent the leak of information about the underlying system.
    • Reference:
    • Implementation:
      • Hide these fields in the corresponding 'get' functions to prevent them from beeing visible from the client:
        • /getUser
        • /getCustomer
        • /getCustomer/:tenantId
      • Remove these fields from the corresponding 'update' functions before updating cosmosdb
        • /updateUser
        • /updateCustomer

[2.1.0] Codename "Hakuho" - (2020-09-03)โ€‹

  • fixed: Approval not working in PPR (issue not identified) #569
    • /locales/i18nServer.js was not initialized in api role (as opposed to the standalone role)
  • fixed: Error 404 in function: getUserPhoto with arguments #558
  • fixed: Invalid token when pushing alerts to the GitHub "ops" repository.
  • fixed: Error when saving approval settings when no template is present #551
    • Original Ops issue: An unhandledRejection has been detected. (UAT) #240102
  • added: New UI to use tags in naming conventions and audience targeting
    • While editing a naming convention (Name, description, email, welcome message) in a template, the user can select pre-made tags by typing either "@" or "#", then selecting the tag from the list.
    • Tags could be mixed with static content
    • Tags could coexist with dynamic contents (meaning other <% %> elements typed directly in the textbox)
    • Relies on the Tagify component
    • Available tags:
      • Naming conventions:
        { id: 1100, value: '<%= %>', title: i18n.__(''), bgColor: requestTagsBgColor, textColor: requestTagsTextColor },
        { id: 1101, value: '<%= %>', title: i18n.__(''), bgColor: requestTagsBgColor, textColor: requestTagsTextColor },
        { id: 1102, value: '<%= %>', title: i18n.__(''), bgColor: requestTagsBgColor, textColor: requestTagsTextColor },
        { id: 1103, value: '<%= %>', title: i18n.__(''), bgColor: requestTagsBgColor, textColor: requestTagsTextColor },
        { id: 1200, value: '<%= %>', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1201, value: '<%= %>', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1202, value: '<%= user.companyName %>', title: i18n.__('tags.user.profile.companyName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1203, value: '<%= %>', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1204, value: '<%= user.department %>', title: i18n.__('tags.user.profile.department'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1205, value: '<%= user.displayName %>', title: i18n.__('tags.user.profile.displayName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1206, value: '<%= user.employeeId %>', title: i18n.__('tags.user.profile.employeeId'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1207, value: '<%= user.givenName %>', title: i18n.__('tags.user.profile.givenName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1208, value: '<%= user.jobTitle %>', title: i18n.__('tags.user.profile.jobTitle'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1209, value: '<%= user.mail %>', title: i18n.__('tags.user.profile.mail'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1210, value: '<%= user.mailNickname %>', title: i18n.__('tags.user.profile.mailNickname'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1211, value: '<%= user.mobilePhone %>', title: i18n.__('tags.user.profile.mobilePhone'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1212, value: '<%= user.officeLocation %>', title: i18n.__('tags.user.profile.officeLocation'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1213, value: '<%= user.postalCode %>', title: i18n.__('tags.user.profile.postalCode'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1214, value: '<%= user.preferredLanguage %>', title: i18n.__('tags.user.profile.preferredLanguage'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1215, value: '<%= user.state %>', title: i18n.__('tags.user.profile.state'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1216, value: '<%= user.streetAddress %>', title: i18n.__('tags.user.profile.streetAddress'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1217, value: '<%= user.surname %>', title: i18n.__('tags.user.profile.surname'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1218, value: '<%= user.usageLocation %>', title: i18n.__('tags.user.profile.usageLocation'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1219, value: '<%= user.userPrincipalName %>', title: i18n.__('tags.user.profile.userPrincipalName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1251, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute1 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute1'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1252, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute2 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute2'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1253, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute3 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute3'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1254, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute4 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute4'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1255, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute5 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute5'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1256, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute6 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute6'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1257, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute7 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute7'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1258, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute8 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute8'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1259, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute9 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute9'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1260, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute10 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute10'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1261, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute11 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute11'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1262, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute12 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute12'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1263, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute13 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute13'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1264, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute14 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute14'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1265, value: '<%= user.onPremisesExtensionAttributes.extensionAttribute15 %>', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute15'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 1300, value: '<%= (new Date).getTime(); %>', title: i18n.__('tags.uniqueId.fromDate'), bgColor: dynamicTagsBgColor, textColor: dynamicTagsTextColor }
      • Audience targeting:
        { id: 2200, value: '', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2201, value: '', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2202, value: 'user.companyName', title: i18n.__('tags.user.profile.companyName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2203, value: '', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2204, value: 'user.department', title: i18n.__('tags.user.profile.department'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2205, value: 'user.displayName', title: i18n.__('tags.user.profile.displayName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2206, value: 'user.employeeId', title: i18n.__('tags.user.profile.employeeId'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2207, value: 'user.givenName', title: i18n.__('tags.user.profile.givenName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2208, value: 'user.jobTitle', title: i18n.__('tags.user.profile.jobTitle'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2209, value: 'user.mail', title: i18n.__('tags.user.profile.mail'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2210, value: 'user.mailNickname', title: i18n.__('tags.user.profile.mailNickname'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2211, value: 'user.mobilePhone', title: i18n.__('tags.user.profile.mobilePhone'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2212, value: 'user.officeLocation', title: i18n.__('tags.user.profile.officeLocation'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2213, value: 'user.postalCode', title: i18n.__('tags.user.profile.postalCode'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2214, value: 'user.preferredLanguage', title: i18n.__('tags.user.profile.preferredLanguage'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2215, value: 'user.state', title: i18n.__('tags.user.profile.state'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2216, value: 'user.streetAddress', title: i18n.__('tags.user.profile.streetAddress'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2217, value: 'user.surname', title: i18n.__('tags.user.profile.surname'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2218, value: 'user.usageLocation', title: i18n.__('tags.user.profile.usageLocation'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2219, value: 'user.userPrincipalName', title: i18n.__('tags.user.profile.userPrincipalName'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2219, value: '', title: i18n.__(''), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        // { id: 2219, value: 'user.groups.transitive', title: i18n.__('tags.user.groups.transitive'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2251, value: 'user.onPremisesExtensionAttributes.extensionAttribute1', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute1'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2252, value: 'user.onPremisesExtensionAttributes.extensionAttribute2', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute2'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2253, value: 'user.onPremisesExtensionAttributes.extensionAttribute3', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute3'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2254, value: 'user.onPremisesExtensionAttributes.extensionAttribute4', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute4'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2255, value: 'user.onPremisesExtensionAttributes.extensionAttribute5', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute5'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2256, value: 'user.onPremisesExtensionAttributes.extensionAttribute6', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute6'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2257, value: 'user.onPremisesExtensionAttributes.extensionAttribute7', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute7'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2258, value: 'user.onPremisesExtensionAttributes.extensionAttribute8', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute8'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2259, value: 'user.onPremisesExtensionAttributes.extensionAttribute9', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute9'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2260, value: 'user.onPremisesExtensionAttributes.extensionAttribute10', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute10'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2261, value: 'user.onPremisesExtensionAttributes.extensionAttribute11', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute11'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2262, value: 'user.onPremisesExtensionAttributes.extensionAttribute12', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute12'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2263, value: 'user.onPremisesExtensionAttributes.extensionAttribute13', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute13'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2264, value: 'user.onPremisesExtensionAttributes.extensionAttribute14', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute14'), bgColor: userTagsBgColor, textColor: userTagsTextColor },
        { id: 2265, value: 'user.onPremisesExtensionAttributes.extensionAttribute15', title: i18n.__('tags.user.profile.onPremisesExtensionAttributes.extensionAttribute15'), bgColor: userTagsBgColor, textColor: userTagsTextColor }
  • added: Support for Azure Active Directory schema extensions (aka custom attributes) in #naming-conventions and #audience-targeting
    • WARNING: The Azure AD schema extensions are different from the Microsoft Graph specific Open extensions and Schema extensions (that we may also support in the future if requested).
    • Usage: Azure AD extension attributes may be located in two different locations depending on their origin:
      1. Right at the root of the user profile for attributes created by a specific application, for instance:
      { "extension_e3049e305790413ca1b11bb53526f057_extensionAttribute10": "REDACTED" }
      These attributes are named by using the convention extension_<extensions-app-id>_attributename, and the <extensions-app-id> is specific to each tenant. To find this identifier, navigate to Azure Active Directory > App registrations > All applications. Search for the app that starts with "aad-extensions-app" and select it. On the app's Overview page, note the Application (client) ID. Usage in naming conventions and audience targeting:
      1. In the onPremisesExtensionAttributes property of the user profile for attributes synchronized by Azure Ad Connect (Also available from the M365 Exchange Admin UI as mailbox properties), such as:
      "onPremisesExtensionAttributes": {
      "extensionAttribute1": "REDACTED",
      "extensionAttribute2": "REDACTED",
      "extensionAttribute3": "REDACTED",
      "extensionAttribute4": "REDACTED",
      "extensionAttribute5": "REDACTED",
      "extensionAttribute6": null,
      "extensionAttribute7": "M",
      "extensionAttribute8": "10/03/1982",
      "extensionAttribute9": null,
      "extensionAttribute10": "REDACTED",
      "extensionAttribute11": null,
      "extensionAttribute12": null,
      "extensionAttribute13": null,
      "extensionAttribute14": null,
      "extensionAttribute15": null
      Usage in naming conventions and audience targeting:
    • To see the available extensions for a specific user, you can use this link that requests all the user profile properties:
    • Notes for later:
  • added: Requests Approval Workflow #approval
    • To be applied, the following conditions have to be true (Approval is just ignored if any of these conditions are not met):
      • Actionable message mode set to 'organization' from the settings tab
      • A provider ID has to be set
      • Approval has to be enabled from the template
      • At least one approver has to be defined
    • Notification email: 1 email is sent per approver
      • The email content is personalized using the following variables:
        • request
        • approver
        • template
        • Locale: Approval workflow uses the language specified in the template (just like provisioning notifications in a channel)
      • The email is comprised of:
        • The actionable card
        • An HTML footer
      • Process:
        • Each approver receives the notification email, from which he can:
          • Review and update the inputs from the requester
          • Approve the request
            • The card is replaced by a confirmation card summarizing the approval process, including the approver and approval date
          • Reject the request including a rejection comment
            • The card is replaced by a confirmation card summarizing the approval process, including the approver, rejection message and its rejection message
    • "My Requests" now shows 2 kinds of requests, approval and povisioning (A different icon)
      • Process:
        • The approval request is Created as "saved" ร  20%
        • move to 50% when the email are sent as "approval"
          • When approved:
            • Moves to 100% as "approved" (green bar)
          • When rejected
            • Moves to 100% as "rejected" (red bar)
            • The approver name and rejection message is shown in "My requests" with a "talk to approvers" button
        • If the approval request is approved, A new provisioning request is created at 10% as "saved". Everything else on this request is similar to a request created without approval
    • Security:
      • Authentication:
        • When executed from outlook (Desktop, web or mobile), the actionable card sends the current user token as part of the action transmitted to our API, ensuring that the request is authenticated
      • Signing:
        • Sending actionable messages relies on a principle similar to app registrations, meaning that by default it's only available in your own tenant (with a unique sender email from the tenant domain). This is the only option enabled as of today, we'll enable the generic multi-tenant option later after the Microsoft validation.
        • Generate a new certificate and signing key:
          openssl genrsa -out private.pem 2048 # Generate a new 2048 bits key pair using openssl
          openssl rsa -in private.pem -out public.pem -outform PEM -pubout # Outputs the public key from the pair (the public key is the one that has to be send to MS)
 # Use this online converter to convert the public key from PEM to XML (MS uses the XML format)
        • Publish the app description + public key to the Actionable Email Developer Dashboard
        • Sample: Sign the card from the server before sending it to the client:
          // Generate a JWS signed card payload
          // Reference:
          // Node.js sample:
          const cardMinified = JSON.stringify(JSON.parse(generatedCard)) // Clone the generated card as string
          const originator = env.vars.MAIL_ACTION_MSG_ORIGINATOR // The Actionable Message provider ID generated during provider registration
          const sender = // Set the email sender
          const recipients = [[approverId].profile.mail] // Set the email recipients (array of strings)
          // Combine all parameters into one payload
          const payload = {
          sender: sender,
          recipientsSerialized: JSON.stringify(recipients),
          adaptiveCardSerialized: cardMinified,
          originator: originator,
          iat: Math.floor( / 1000) // Include a generation timestamp
          // Sign the payload using the private key (uses the jsonwebtoken package)
          const cardAsJwt = jwt.sign(payload, privateSigningKey, { algorithm: 'RS256' })
          // The generated JWS could be tested using the public key
          jwt.verify(cardAsJwt, publicSigningKey, (err, res) => {
          if (!err) {
          console.debug('jwt token OK')
          } else {
          console.debug('jwt token KO')
      • Configuration:
  • fixed: graphServices/createTeamFromTemplate/sendMessage error. (PRD) #540
    • added a control to check if a message to send is not empty
    • added: control to replace some characters with their html code counterpart:
      • .replace(/'/gim, '&apos;')
      • .replace(/[\r\n]/gim, '<br/>')
  • added: New security report available online about our SSL certificates
  • added: Daily security scan using OWASP ZAP scan
    • This scan is performed every day at 1am and generates a detailed report as a new issue in the main repository (see #538 as an example)
  • changed: checked compatibility of our Redis client with TLS 1.2 that will be enforced by Microsoft soon
  • fixed: Requester not added in private channels #528
    • We were using the requester ID from the request object which is nBold ID. Now, instead, we use the msUserId (from AD) from the user object.
  • fixed: Error 404 in function: addChannelOwner #192827
    • Manage 404 error in case of bad provisioning
  • changed: Updated manifests to v1.7, including the following properties:
    • showLoadingIndicator: false (always false as it seems to break the app)
    • isFullScreen: false for standalone packages, true for targeted packages
  • changed: Handbook is now restricted to "Members" (aka employees) from the nBold tenant
  • changed: Documentation about naming convention and audience targeting tags
    • The tech hub documentation has been updated to reflect these changes.
  • fixed: Audience targeting issue
    • Cause:
      • Related to how the api returns the user profile (and the necessary work to handle profile custom attributes)
    • Consequences:
      • The user profile used for the audience targeting and the naming conventions is now entirely based on the strict Graph API definition, and therefore changes all our naming conventions and audience targeting rules, especially the tags we can use.
    • Resolution:
      • The new schema is taken into account in both the naming convention and the audience targeting, server-side and client-side.
      • All customers have been automatically upgraded to the new schema, and their configuration updated (for instance, user.msEmail is replaced by user.mail)
    • The tech hub documentation has been updated to reflect these changes.
  • fixed: Implement an option to fix the security issue: "EJS server-side templating is vulnerable to code injection" #477
    • Related security alert: EJS server-side templating is vulnerable to code injection
    • Resolution:
      • Removed all the direct server-side calls to EJS ejs.render() that may use the eval function (N.B: client-side use of ejs is safe and therefore is not impacted) in the following files:
        • requests-processer.js: was using ejs to apply naming conventions
        • catalog.js: was using ejs to apply audience targeting in our api
      • Implementation of a new sandbox.js module that encapsulates the vm2 npm package which seems the most secure
  • fixed: Private channel name is truncated after using our new workaround #516 Avoid planner throttling
  • changed: Upgraded all environments to node.js v12 LTS
    • Rationale: Better support for the enforcement of TLS v1.2 on Cosmos DB (and probably Redis too)
    • See Announcement
  • fixed: Naming Convention Issue in Welcome Message and Description #287
    • Symptom: about the Naming convention on the welcome message and description is good at the preview level on the form but when the team is generated it's taking the whole team name and not only what the user enter in text
    • Resolution: The request object was updated by reference not by value. THe code is updated to clone values before applying any naming convention.
  • added: Deletion of automatically generated wiki tabs
    • During the provisioning, the process controls the number of wiki tabs in the source channel, and keeps only the same number of wiki tabs (keeping the first one in priority, that should be the original one with the right tab name)
  • fixed: Requester and Permanent owner not added in private channel #408
  • changed: Planner provisioning is too long due to multiple throttled requests #515
    • Resolution: Created a new plannerLimiter similar to graphLimiter with specific default configuration values, especially:
      MICROSOFT_PLANNER_LIMITER_MINTIME=500 # Max 2 requests per second
      MICROSOFT_PLANNER_LIMITER_HIGHWATER=null # No queue limitation or leak rule
  • changed: Rendering of templates in the catalog tab is now vastly faster, especially with a large number of templates
    • Code optimization of rendering that was previously doing an ajax request for each template.
  • fixed: Unknown and undocumented error in function: cloneTeamLogo. (PPR) #188236
    • Cause: Locale files were not loaded as the jobs role was not loading the webapp.
    • Resolution: The workersLauncher.js service is now requiring i18nServer.js so that it's loaded systematically
  • fixed: Unable to save template in PPR
    • Cause: Misconfigured blob container for PPR in stsaprd storage account
    • Related issue: Unexpected error in /blobServices/savePicture/createBlockBlobFromStream. (PPR) #188030
  • security: bump standard-version from 7.1.0 to 8.0.1 #505
  • added: PPR dedicated app, api and jobs roles
    • PPR is now hosted with an architecture similar to PRD, with dedicated instances for each role
    • Now dynamically assigning the right service URL based on environment:
  • security: bump jquery from 3.4.1 to 3.5.0 #460
    • Related issue:
      • Audit Button in My Request - not working #452
      • Cause: Incompatibility between bootstrap v4.4.1 and jquery v3.5.0 > Downgraded jquery to v3.4.1. See Bootstrap Issue
      • Resolution: Upgraded JQuery to 3.5.1 to avoid conflicts with bootstrap
  • fixed: Infinite retry loop when trying to clone a team where the service account is not an owner
    • Resolution:
      • In case of error "403_FORBIDDEN", the provisioning process tries to add the service account as an owner of the source team
      • The pre-processing entries (everything before the actual team cloning) in the audit trail will therefore be visible twice, indicating that the provisioning process has been restarted.
  • fixed: Infinite retry loop when adding the requester as an owner of a private channel.
    • Cause: The graph is supposed to return a 400 error in case of duplicate (trying to add a user when he's already a member), but sometimes returns a 500 error...
    • Resolution: Just skipping outside the addChannelOwner method when error 500 is reached.
  • fixed: In audit trail, the private channels requested owners and permanent owners names are "undefined"
    • Now retreiving the user displayName during provisioning
  • fixed: In audit trail, the private channels names are not displayed
    • Now retreiving the channel displayName during provisioning (instead of the "name" property)
  • fixed: Planner plan cloning takes a large amount of time and may fail as it gets throttled while exporting the original plan
    • Refactored the exportPlannerPlanAsJson and provisionPlannerContent functions to use the graphLimiter to schedule calls to the Graph
  • fixed: infinite retry loop in copyDriveItem
    • Cause: In case of channels that have been renamed, the drive copy process fails and loops on retry for error 500 (as the original folder could not be found)
    • Resolution: Changed the retry mechanism to limit the number of retry to 3 in any case
  • Added: Provisioning retry on fail
    • In case of major crash (the main process is stopped and automatically restarted), if a request has still not yes created the new team, the newly started process restarts the provisioning process using the same request.
    • The pre-processing entries (everything before the actual team cloning) in the audit trail will therefore be visible twice, indicating that the provisioning process has been restarted.
  • fixed: In some cases, the provisioning process was stopped after configuring tabs:
    • Cause: multiple wiki tabs with the same name (such as wiki tabs automatically added by the standard cloning process) were generating confusion in our code, preventing the tabs configuration to end properly
    • Resolution: better error management in the tabs configuration process
  • changed: Tabs types that doesn't support configuration (Wiki, PowerBI, OneNote) are now visible in the audit trail with a descriptive message
  • fixed: Unsupported tabs names in the audit trails are now "URL-decoded", preventing weird codes to be visible such as %20,
  • fixed: graphServices/createTeamFromTemplate/sendMessage error. (INT) #174802
    • Added a token refresh handler in case of expiration during a provisioning process
  • fixed: Redis connectivity issue in UAT
    • Related issues:
      • Alert job error (UAT) #174317: Error initializing Lua scripts
      • Job Logging job error (UAT) #174234: connect ETIMEDOUT
      • An unhandledRejection has been detected. (UAT) #174236: connect ETIMEDOUT
    • Resources: See "Connection time out during queue add" #1366
    • Fix: Increase the ioredis connectTimeout property to 30000 (ms) so that queues have time to connect during startup
  • fixed: Unknown and undocumented error in function: getMyRequestsCount. (INT) #174131
    • Better error management in case of network latency issues
  • changed: jobs queues are now prefixed with the current environment for better isolation
  • fixed: An unhandledRejection has been detected. (UAT) #172834
    • The service is now restarted if an unhandledRejection is detected, for instance a Redis connectivity issue during boot.
  • changed: better log levels management with distinction between verbose and debug
    • Now using the npm logging levels prioritized from 0 to 6 (highest to lowest):
      error: 0,
      warn: 1,
      info: 2,
      http: 3,
      verbose: 4,
      debug: 5,
      silly: 6
    • Reference: Winston logger logging levels
  • added: Support for en-my locale (English - Malaysia) #172551
  • fixed: typo in es-es locale, replaced "% s" by "%s" #172547
  • added: Support of italian language
    • Applies to:
      • nBold UI based on Teams / Browser language
      • Template lang for notifications
    • The following lang / region pairs are supported:
      • it-IT Italian (Italy)
      • it-CH Italian (Switzerland)
  • changed: #provisioning Tabs configuration support
    • Supported tabs: Tab cloning and configuration works and is officially supported by nBold (SUPPORTED by Microsoft)
      • Custom tabs
      • Website tabs
      • Word, Excel, PowerPoint, and PDF tabs
      • Document library tabs
      • YouTube tabs
      • Yammer tabs
    • Unsupported tabs: Tab cloning and configuration SHOULD work but cannot be officially supported by nBold (UNSUPPORTED by Microsoft)
      • Planner tabs
      • Microsoft Stream tabs
      • Microsoft Forms tabs
      • SharePoint page and list tabs
    • Ignored: Tab cloning without configuration
      • Power BI tabs
      • Wiki tabs
      • OneNote tabs
  • fixed: #provisioning 1 Private Channel Missing - Systra #480
    • Symptom: Sometimes, the Graph accepts to create a channel (and returns an ID), but then the channel is not visible anymore from the graph.
    • See "Error in graphHelper/updateTabConfiguration" #169114
      "message":"No active channel found with channel id: 19:2110ddd4c6ab4906a0cec78bf6d13459@thread.tacv2",
      • Basically, after the creation of a private channel:
        • Wait for 10sec
        • Check if the /tabs endpoint for this channel is responding (returns a 404 in case of error)
        • If the /tabs returns an error:
          • Delete the channel
          • Restart the private channel provisioning process (every 10 sec, max 3 times), using a different name:
            • Adding " (1)", " (2)" or " (3)" respectively for retry #1, #2 and #3
          • Retest the /tabs endpoint
  • fixed: #provisioning Missing Tabs 481
  • fixed: #provisioning 3 tabs missing in the provisionning #482
  • fixed: #ui My requests not working correctly #484
    • Happened when the requests list was empty due to a bug in the /me/jobs api
  • fixed: #provisioning Tabs provisioned in the wrong channel
    • Fixed by reordering (alphabetically on the displayName) channels after the full provisioning, as they may have been created in a different order.
  • fixed: #provisioning Apps not cloned in private channels
    • Error undefined in function: createTab with arguments: #165395
    • Resolution: Implement a control process that install missing apps automatically during the provisioning
  • fixed: #login Unable to login in dev mode when using wsl

[2.0.0] Codename "Kisenosato" - (2020-06-18)โ€‹

  • fixed: Provisioning issues
    • Implement query replay for Microsoft Graph erors 502 and 503
    • Better management after a query has been throttled by managing the "replay-after" header
    • Tabs are now using "displayName" instead of "name"
    • More granular tasks priorisation in bottleneck
    • Fixed replay operations in createTeamFromTemplate
    • Better error management in files cloning in case of renamed channel
    • Replaced error by warn level in case of error 502 to reduce noise in the ops repo
  • changed: Store performance optimizations
    • Removed all JQuery dependency in components and removed the library from bundle.min.js
  • added: Doc procedure to optimize templates assets
  • added: Intercom chat UI is now available from the template store
  • fixed: Tabs in private channels are sometimes not provisioned
    • Fixed the cloningMissingTabs function to add a "tabs" property when it is missing to private channels
  • fixed: Provisioning process crashes with wrong number of provate channels
    • Updated the cloningMissingChannels function to take into account the asynchronous private channels creation
  • fixed: Planner tab plans are not provisioned #462
    const tabVersion = '&tabVersion=20200228.1_s' // Temporarly added, to be checked regularly
    const targetContentUrl = `{tid}/Home/PlannerFrame?page=7&auth_pvr=OrgId&auth_upn={userPrincipalName}&groupId={groupId}&planId=${}&channelId={channelId}&entityId={entityId}&tid={tid}&userObjectId={userObjectId}&subEntityId={subEntityId}&sessionId={sessionId}&theme={theme}&mkt={locale}&ringId={ringId}&PlannerRouteHint={tid}${tabVersion}`
    const targetWebsiteUrl = `${tenantId}/Home/PlanViews/${}?Type=PlanLink&Channel=TeamsTab`
    const targetRemoveUrl = `{tid}/Home/PlannerFrame?page=13&auth_pvr=OrgId&auth_upn={userPrincipalName}&groupId={groupId}&planId=${}&channelId={channelId}&entityId={entityId}&tid={tid}&userObjectId={userObjectId}&subEntityId={subEntityId}&sessionId={sessionId}&theme={theme}&mkt={locale}&ringId={ringId}&PlannerRouteHint={tid}${tabVersion}`
    • In addition, the plan id is not set as the entityId of the tab configuration... For reference, see Identifiers in Planner
  • fixed: Tabs created in wrong private channels #441
    • updated code to reflect the new graph schema
  • changed: Template Store: SEO, social sharing and categories
    • Header Metadata
      • Automatically generated by this VuePress plugin:
      • The Template Store is now optimized for SEO through automatically generated meta, for instance:
        <meta name="description" content="Digital Strategy and Transformation, a Microsoft Teams template by EY">
        <meta name="image" content="">
        <meta name="twitter:title" content="Digital Strategy and Transformation">
        <meta name="twitter:description" content="Digital Strategy and Transformation, a Microsoft Teams template by EY">
        <meta name="twitter:card" content="summary_large_image">
        <meta name="twitter:image" content="">
        <meta property="og:type" content="article">
        <meta property="og:title" content="Digital Strategy and Transformation">
        <meta property="og:description" content="Digital Strategy and Transformation, a Microsoft Teams template by EY">
        <meta property="og:image" content="">
        <meta property="article:tag" content="ey">
        <meta itemprop="name" content="Digital Strategy and Transformation">
        <meta itemprop="description" content="Digital Strategy and Transformation, a Microsoft Teams template by EY">
        <meta itemprop="image" content="">
      • Better social Sharing experience:
        • LinkedIn and Twitter are now using the "socialPicture" field defined in the manifest as their card picture
    • A new navigation section in the sidebar called "Integrations", right now with Salesforce, Dynamics and ServiceNow
    • Categories now have a description that appears between the category page title and the templates cards.
  • fixed: Requester and membership not fully provisioned
    • Related issues:
      • Team Not Fully Provisioned - IQ Business #449
      • Requester not added to membership list, provisioning blocked @ 80% #451
  • fixed: Cannot access audit trail from the "My Requests" screen
    • Related issue: Audit Button in My Request - not working #452
    • Fixed incompatibility between bootstrap v4.4.1 and jquery v3.5.0 > Downgraded jquery to v3.4.1. See Bootstrap Issue
  • added: New open source repository tech-hub
    • Contains multiple SDKs for various clients and servers
    • Levels of support:
      • javascript: beta (Target as GA in API v1)
      • powershell: alpha (Target as GA in API v1)
      • apex: experimental
      • csharp-netcore: experimental
      • aspnetcore: experimental
      • nodejs-express-server: experimental
  • security: Audit reports are now generated as part of the app-platform build.
  • added: New open source repository internationalization
    • Contains the raw json files resource files used by the nBold Platform
    • Now updated versions of the resource files are automatically downloaded during build (taking the latest release)
    • Public URL:
    • Governed by:
      • nBold Security Policy
      • nBold Open Source Code of Conduct
    • Usage instructions are detailed in the README file
  • added: nBold API Explorer
  • added: nBold Open Source Code of conduct
  • fixed: Logs files naming convention
    • The switch to a fully global architecture generated conflicts in github
    • The new naming convention is: <environment>-<role>-<hostname>-<date>.log
    • For example: prd-api-api01-2020-05-14-18.log
  • added: New public doc "Security Policy"
  • changed: New network infrastructure based on Azure Front Door
    • Benefits
      • Improved operations & availability
        • Decorrelates our infrastructure from the public domains and urls, enabling our new Microservices Architecture.
        • Reduce downtime by enabling hot-patching of our container instances
        • Managing redundency is easier as Front Door provides an global HTTP load balancing with instant failover across pools of containerized instances
        • SSL certificates are now 100% automatically managed by Front Door, reducing our maintenance workload and risks of unexpected expiration / invalidation
      • Increased performance
        • Users are automatically routed to the closest available backend
        • Static assets can now be cached and served from Azure CDN across the multiple Azure PoP Worldwide
        • TLS traffic encryption is now offloaded to Azure Front Door, reducing our servers workload
      • Improved security
    • Now Azure Front Door manages access, certificates and routing to:
      • Non-Production environments
      • Production environments
        • Former production VM
  • added: New "/dist" directory
    • Public URL:
    • Exposes:
      • App packages (Related links are up to date here
      • API definition (openapi) and json schemas (Links updated on
  • changed: Isolation of tech-hub and template-store repos and websites
    • Why: Previously, sites "tech-hub" and "template-store" were hosted in the main "app-platform" repo, resulting in longer build times and possible issues.
    • How: Now techhub and template-store sources are hosted in their own isolated repos:
      • tech-hub:
        • New Repo
        • The website is still available here, and is hosted right from the repository through the GitHub Pages service.
      • template-store:
        • New Repo
        • Now hosts both .json templates and the template-store website
        • The store website is now available here instead of
        • N.B: The template-gallery repo previously hosting .json templates is now archived and should not be used anymore
  • fixed: Fallback language for sv-SE generates i18n errors #135919
    • How: Added a specific fallback entry for sv-se in i18nConfig.js
  • added: Support of spanish language
    • Applies to:
      • nBold UI based on Teams / Browser language
      • Template lang for notifications
    • The following lang / region pairs are supported:
      • es-AR Spanish (Argentina)
      • es-BO Spanish (Bolivia)
      • es-CL Spanish (Chile)
      • es-CO Spanish (Colombia)
      • es-CR Spanish (Costa Rica)
      • es-DO Spanish (Dominican Republic)
      • es-EC Spanish (Ecuador)
      • es-ES Spanish (Spain)
      • es-GT Spanish (Guatemala)
      • es-HN Spanish (Honduras)
      • es-MX Spanish (Mexico)
      • es-NI Spanish (Nicaragua)
      • es-PA Spanish (Panama)
      • es-PE Spanish (Peru)
      • es-PR Spanish (Puerto Rico)
      • es-PY Spanish (Paraguay)
      • es-SV Spanish (El Salvador)
      • es-UY Spanish (Uruguay)
      • es-VE Spanish (Venezuela)
  • changed: Increasing membership limits
    • Now you can select up to 20:
      • Requested owners & members in the new team request form
      • Permanent owners & members in the template settings
  • changed: Improved user selection
    • Why: It's sometimes hard to select users from directories when there is a large number of users sharing the same first or last name
    • How: In user selection box (approvers selection from a template, permanent members...), filtering is now performed on the following fields:
      • givenName
      • surname
      • email
      • userPrincipalName
  • changed: The "approval" tab in templates is now flagged with a "Pro" badge
  • fixed: Error updating mail nickname. (PRD) #121353
    • Implemented a retry on 404 error (if the mailbox is not yet fully provisioned)
  • fixed: email naming conventions
  • changed: Updated doc "Service Account" and "Data Management Practices" sections
  • fixed: Unexpected error in /sameSiteMiddleware/ensureCookieCompatibility. #120782
    • The issue was raised in case of empty user-agent header for some browsers

[1.5.0] Codename "Yokozuna"โ€‹

  • fixed: SameSite Policy update in chrome and edge
    • Why:
    • How:
      • Implementation of a new middleware (sameSiteMiddleware)
      • Set express to trust the first proxy
        app.set('trust proxy', 1) // trust first proxy
        // @see
      • Define cookie policy in express session
        cookie: {
        httpOnly: true,
        sameSite: 'none',
        secure: true
  • fixed: The same template may appear multiple times in the "New team" form in the "Catalog" tab after creating a new template
    • Related issue: Not able to search for the Original Team in creating a template #360
  • fixed: When creating a new template, the template picture remains the same as a previously created or updated template
  • fixed: Salestim Web Experience Appears in Microsoft Teams App #363
  • fixed: Check service account screen is empty
  • fixed: Freeze when adding Permanent owner - Members #354
  • fixed: Teams Picture not added #355
  • fixed: Unexpected error in I18n __(). (DEV) #115582
    • Created i18n keys for crm configuration
  • fixed: Error in isOwnerOf: Resource 'ad9d747a-737a-4f72-b1d1-fceaffaa54ba' does not exist or one of its queried reference-property objects are not present. Detail: {"statusCode":404,"code":"Request_Resource (PRD) #115535
    • Resolution: Better graph error management
  • fixed: Error in requestsEventsQueueListener/processRequestEvent/requestsProcesser/processNewRequest: {} (DEV) #115312
    • Error message: Error message: waitForTeamsAsyncOperation status is "failed"
    • Resolution: Implement retry mechanism
  • fixed: Jobs execution error
    • Related issues:
      • index/exitHandler received a signal: SIGINT. Message: SIGINT Description: User pressing Ctrl+C and is an interrupt App will exit in 30000ms. (DEV) #115116
      • JOB DELETETESTTEAMSDEV: Task execution failed with unexpected error: {} (DEV) #115110
      • Task executed with errors (DEV) #115111
    • Root cause: Bad async loading of jobs module instance, resulting in an uncatched exception in jobScheduler trying to call the 'start' method.
  • fixed: Client-side exceptions
    • Error in getGeneralChannelId: Failed to execute backend request. Detail: {"statusCode":502,"code":"BadGateway","message":"Failed to execute backend request.","requestId":"7d898e23-7baf-4dae-b3ae-08fe (PRD) #114249
    • Error in getTeamProperties: Failed to execute backend request. Detail: {"statusCode":502,"code":"BadGateway","message":"Failed to execute backend request.","requestId":"a8ad671b-3d90-4eee-9556-86ec8e (PRD) #114251
    • Resolution: Implemented a graphErrorHandler client-side global error handler
  • fixed: An unhandledRejection has been detected. (INT) #114867
    • Error message: Error message: scroll already exists for this workspace
    • Resolution: Prevent parralel queries that use paging (scroll) in extrectIntercomData job
    • Schedule jobs more evenly to prevent conflicts:
    dev: '*/30 - - - *',
    int: '0 2 - - *',
    uat: '0 3 - - *',
    ppr: '0 11 - - *',
    prd: '0 23 - - *'
  • fixed: Enable / Disable template is now working properly
  • fixed: An uncaught exception has been detected at origin: undefined (DEV) #113328
    • Resolution: Better andling of Intercom API exceptions
  • feat: new ๐Ÿ“ก Stream tabs content cloning capability.
    • Now you can clone Stream tabs as part of your teams templates.
  • fixed: Intermittently user is not able to clone a team #112477 and #112481
    • Error:
    {"status":502,"response":{"req":{"method":"POST","url":"","data":"{\"displayName\":\"Test team janapp2-TIM","description":"Team created by jantestapp2. Description: test","mailNickname":"TIM-Test-team-janapp2-TIM-EN","partsToClone":"apps,tabs,settings,channels","visibility":"private"}",
    {\r\n "code": "BadGateway",\r\n "message": "Failed to execute backend request.",\r\n "innerError": {\r\n "request-id": "eb2fb2fa-ef6e-4b23-9035-b9ae28564e10",\r\n "date": "2020-01-17T19:26:11"\r\n }\r\n }\r\n}"}}
  • improvement: Web Store
    • Web Store categories are now multilingual
    • Template pages now have recommendations "Other templates from the same category" and "Other templates from the same publisher"
  • fixed: User without preferred language in their Office 365 profile.
    • Root cause: Under certain circumstances, for instance with accounts automatically provisionned from Office 365 demo/test tenants, a user may have an empty empty preferred language. Therefore the user profile property in nBold is
      { msPreferredLanguage: null }
    • Background: Default templates (Basic EN and Basic FR) relies on this property for audience targeting
    • Impacts: Default templates were not visible by these users
    • Resolution: Now when checking the audience targeting, if the msPreferredLanguage property is empty, it is dynamically filled with (Ordered by priority):
      1. Microsoft Teams language
      2. Browser language
      3. en-us in last resort
  • security: Teams packages manifests updates
    • in DEV environments, both root and sub-domains are now authorized *. and *.\-, to cope with NGROK sub-domains such as eu in
    • in non-DEV environments, we're now using wildcards to authorize * and *
    • Added the openExternal permission to devicePermissions to future-proof nBold on mobile devices.
    validDomains: [
    devicePermissions: [
  • feat: Web store is now accessible from dev, int and uat environments
    • The store is accessible anonymously from https://[ENVIRONMENT], and is embedded as an iframe in the "Catalog" tab.
    • Store templates could be filtered by:
      • Category
      • Industry
      • Language
    • Store categories and industries hav their own landing pages.
  • fixed: Job Scheduler
    • Source error: Error writing jobs audit trail. (UAT) #97625
  • fixed: Error in getGroupImage: null Detail: {"statusCode":404,"code":null,"message":null,"requestId":null,"date":"2019-12-05T07:12:35.019Z","body":null} (PRD) #100049
    • Better handling of 404 error when a team has no associated photo
  • improvement: Mail nickname formatter
    • Mail nickname generated from the email naming convention is now automatically formatted using the following rules:
      • Remove domain part to only keep the nickname (aka local part) (Remove everything after the first "@" character)
      • Remove or replace spaces and special characters:
        whitespace > '-'
        " > ''
        ( > ''
        ) > ''
        , > '-'
        : > '-'
        ; > '-'
        < > ''
        > > ''
        @ > ''
        [ > ''
        \ > ''
        ] > ''
      • Limit nickname to 64 characters
      • In case of email nickname duplicate:
        • Limit nickname to 51 characters
        • Add a unique suffix based on current datetime using the format: -YYMMDDhhmmss

[1.4.0] Codename "Ozeki"โ€‹

  • feat: API /jobs endpoints
    • Manage nBold's platform jobs
    • Operations:
      • GET /jobs
        • Get all available jobs for the current environment (Meaning all jobs that is authorized to be executed in the current environment, actually scheduled or not)
      • GET /jobs/scheduled
        • Get all scheduled jobs for the current environment
      • POST /jobs/tasks
        • Create a new job instance (aka "task")
  • feat: API root & versions URL scheme: https://[ENVIRONMENT][VERSION]
  • feat: Files cloning
  • fixed: Deeplinks to provisioned tabs in channels notification messages are not working.
    • The tab webUrl property returned by the graph api just after tab provisioning is incorrect (at least the deeplink is not supported).
    • Now we're using the webUrl generated after tab configuration
  • improvement: Use $expand=teamsApp QSP when calling "/tabs" endpoint to get more infos about cloned tabs
  • feat: Improved onboarding
    • New customers now have two default templates, one for FR language and one for EN language, automatically enabled and configured with 2 source teams with a "General" channel and a "๐Ÿ™‹๐Ÿผโ€โ™€๏ธ Discover nBold" channel
  • security: Enforce TLS v1.2
  • ops: New environments. nBold now has 4 fully-functional Azure environments. | ๐Ÿ’ Ring | Environments | Code | Root URL | Deployment | | :-----: | --------------- | ---- | --------------- | ----------------------------------------------------------------------- | | 4*- | production- | PRD | | Pull request from the "ppr" branch to the protected "production" branch | | **3.5- | staging*- | PPR | | Pull request from the "uat" branch to the protected "ppr" branch | | 2- | **uat- | UAT | | Pull request from the "int" branch to the "uat" branch | | 0*- | integration*- | INT | | CI (Continuous Integration) from the "master branch |
  • feat: new ๐Ÿ“บ Youtube tabs content cloning capability.
    • Now you can clone Youtube tabs as part of your teams templates.
  • fixed: Group mail nickname update operation now has its own entry in request's audit trail.
  • improvement: "New Team" template selection.
    • The full template card is now clickable
    • When a template is selected, the "Update template" : change button label + move button to header
  • fixed: The "New Team" form is now reinitialized after a new team request has been submitted
  • improvement: Action menus are now responsive
  • fixed: The homepage is stucked at the "Loading your teams" stage
  • feat: "New team" and "My requets" are now available from the catalog tab.

[1.3.0] Codename "Sekiwake"โ€‹

  • improvement: Mail nickname naming convention
    • In email naming convention template configuration, only the nickname (aka Local part) is required
    • The naming convention is applied after group cloning as the cloning api doesn't support it so far
    • In case of empty or wrong naming convention expression, a nickname is generated from the requested team name
  • fixed: Cannot clone an archived team
    • Related errors:
      • Unable to retrieve tabs in getTeamStructure/listTabs. #99924
      • Error in graphHelper/listTabs. #7723
        • Error: Unable to retrieve tabs in getTeamStructure/listTabs.
          "message": Forbidden
          "status": 403
          "response_text": {
          "error": {
          "code": "Forbidden",
          "message": "Entitlements cannot be retrieved because this team is archived.",
          "innerError": {
          "request-id": "571f9937-036f-4b2e-a037-740972c41f63",
          "date": "2019-12-04T14:51:31"
    • Resolution: A new pre-processing is now checking if the source team is archived, and stops provisionning with an appropriate error message.
  • fix PowerApps audit log labels in fr-fr
    • In fr-fr locale, PowerApps logs message were wrong (handled as a generic tab)
  • refactor: Login process
    • Usins nBold outside of Microsoft Teams is now supported (prepping a future SharePoint component for integration in an Intranet for instance)
    • Original requested URL including parameters ("?" "#") are now preserved after login
    • Page size optimization through JS and CSS minification, resulting in a slightly faster response time.
    • "Please wait" animated logo is smaller and aligned with the new cleaner design
  • improvement: App design
    • New lighter and cleaner design in menus, labels and icons
    • In "Browser" mode (outside of Microsoft Teams), a global navigation header is now visible
  • ops: Actions tracking
    • The following events are now tracked in Intercom:
      clickEvents: {
      tim: {
      closed: ,
      initiatedTalkToSupport: Talking to Support,
      initiatedBackToHome: Back to home...,
      initiatedLgoutUnauthorized: Signing-out...,
      teamTabConfig: {
      saved: Saving...
      login: {
      started: Signing-in...
      home: {
      myRequests: {
      opened: My requests,
      closed: Home
      newTeam: {
      opened: New Team,
      canceled: Home,
      saved: Home
      searched: Search,
      team: {
      opened: Opening...,
      initiateTalkToOwners: Starting conversation...
      loggedOut: Sign-out...
      catalog: {
      templates: {
      newModal: {
      opened: New Template,
      sourceTeamSelected: New Template
      editForm: {
      opened: Template edition,
      saved: Template saved,
      closed: Catalog
      filtered: {
      disabled: Catalog (Disabled templated),
      enabled: Catalog (Enabled templates),
      all: Catalog
      loggedOut: Signing-out...
      settings: {
      serviceAccount: {
      panel: {
      opened: Service account
      updated: Service account (update),
      check: {
      opened: Checking service account prerequisites,
      closed: Service account (checked)
      removed: Service account (removed)
      customization: {
      panel: {
      opened: Customization
      crm: {
      panel: {
      opened: Salesforce
      api: {
      panel: {
      opened: Integrations
      targeted: {
      panel: {
      opened: Targeted deployments
      systemInfo: {
      panel: {
      opened: System information
      loggedOut: Signing-out...
      loggedError: {
      closed: Closing...
      logged: {
      redirected: Redirecting...
    • Events description:
      • Event name: "Clicked"
      • Event metadata:
        action_code: actionCode,
        action_label: eventActionTitle

[1.2.0] Codename "Maegashira"โ€‹


  • fixed: Unexpected error in searchMyTeams. (PRD) #7098
  • fixed: "My Requests" counter badge breaks toolbar alignment


  • improvement: My Requests count badge is now hidden if there is no request.
  • improvement: "๐Ÿ“ฎ My Requests" audit trail now shows the last operation and date in the request summary
  • fixed: The "New team" form appeared as blank after a previous submission
  • improvement: "My teams" ๐Ÿ”Ž search from homepage
    • The search box is now always visible
    • Search is performed instantly, on client-side
    • Search is case-insensitive
    • Search is applied to teams title and description, including partial words
  • improvement: Unauthorized access when when accessing the "Catalog" or "Settings" tab as a non-Office365 administrator:
    • The warning message now has more options:
      • Use the Intercom chat to ask for help
      • Button "๐Ÿ’ฌ Talk to our Support": Launch an intercom chat session with our support team
      • Button "๐Ÿ”™ Back to Home": Deeplink to the "Home" tab
      • Button "๐Ÿ” Sign-in with another account": Logout the user from the current session
    • fixed: An error appeared after a first login into an unthorized page.
      • Error message: Unexpected error in isAdminFromSession. (UAT) #6837
      • Related issues:
        • Error in /loadComponent route: TypeError ERR_INVALID_ARG_VALUE: The argument 'id' must be a non-empty string. Received '' (UAT) #6838
        • Error in /loadComponent route: AssertionError ERR_ASSERTION: missing path (PRD) #6845
  • improvement: The "New team" button is now disabled if there is no service account configured
  • improvement: Template creation
    • The "Clone members" option is now disabled by default when creating a new template
  • ops: New intercom tracking company attribute: template_count
    • Updated during each catalog update
  • feat: New ๐Ÿงฑ PowerApps tabs cloning capability.
  • improvement: "๐Ÿ“ฎ My Requests"
    • The counter badge on the "๐Ÿ“ฎ My Requests" button is automatically updated every 5 seconds every 5sec
    • The audit trail is automatically refreshed when clicking on the "๐Ÿ“ฎ My Requests" button (during opening)


  • feat: New tabs cloning capabilities. nBold now supports the cloning of the following tabs type:
    • ๐Ÿ’ฌ Yammer tabs: both configured for Yammer groups and Yammer topics
    • ๐Ÿ“‹ Microsoft Forms tabs: both data collect through questions and responses view
    • ๐Ÿ“š SharePoint Document Library
    • ๐Ÿ“˜ Word
    • ๐Ÿ“— Excel
    • ๐Ÿ“• PowerPoint
    • ๐Ÿ’ผ PDF
  • improvement: "๐Ÿ“ฎ My Requests" audit trail
    • Now tab with names including special characters (URL encoded) are shown properly in the audit trail
    • Each cloned tab message has its own icon:
      • ๐Ÿงญ Website
      • ๐Ÿ“… Planner
      • ๐ŸŽฆ Stream
      • ๐Ÿ“‹ Forms
      • ๐Ÿ“˜ Word
      • ๐Ÿ“— Excel
      • ๐Ÿ“• PowerPoint
      • ๐Ÿ’ผ PDF
      • ๐Ÿ“ Wiki
      • ๐Ÿ“š SharePoint Document Library
      • ๐Ÿ“‘ OneNote
      • ๐Ÿ“Š Power BI
      • ๐Ÿ“ฐ SharePoint Page
      • ๐Ÿ’ฌ Yammer
      • ๐Ÿงฑ Unknown type


  • fixed: Notifications messages localization in new tenants
  • improvement: Service account status in Intercom
    • The "renewServiceAccountTokens" job now set the company property "serviceaccount_status" to true or false, indicating if the last renewal job was successful
  • improvement: "๐Ÿ“ฎ My Requests" audit trail
    • All dates (request creation and individual events) are now stored in ISO format (aka 2019-11-26T21:49:25.983Z)
    • All dates (request creation and individual events) are shown in the current user locale format
    • Requests are now sorted by date (Most recent on top of the list)
    • Progress bar color now reflects the current status of the request
      "REQ_STA_SAVED": "bg-info", // (blue) Just saved after user request
      "REQ_STA_PREPROCESSING": "bg-default", // (purple) prepping things before approval (or direct processing)
      "REQ_STA_PROCESSING": "bg-default", // (purple) Provisionning is running
      "REQ_STA_POSTPROCESSING": "bg-default", // (purple) Applying post-cloning operations
      "REQ_STA_APPROVAL": "bg-info", // (blue) Waiting for approval
      "REQ_STA_APPROVED": "bg-info", // (blue) Approved
      "REQ_STA_REJECTED": "bg-warning", // (yellow) Rejected
      "REQ_STA_PROCESSED": "bg-success", // (green) Processed (Done)
      "REQ_STA_ERROR": "bg-danger", // (red) Error
      "REQ_STA_UNKNOWN": "bg-warning", // (yellow) Unknown


  • improvement: New "๐Ÿ”ฅ Remove" button in the "๐Ÿค– Service account" tab, to remove a service account from the current configuration
  • improvement: Prevent double-click actions in settings
    • The following buttons are disabled until action completion and their label replaces by a "please wait" label:
    "select": {
    "button": "๐ŸŽญ Update",
    "waitMessage": "โณ Updating service account..."
    "check": {
    "button": "โœ… Check Requirements",
    "waitMessage": "โณ Checking requirements..."
    }"delete": {
    "button": "๐Ÿ”ฅ Remove",
    "waitMessage": "โณ Removing service account..."
    "logout": {
    "title": "๐Ÿ’จ Sign-out",
    "waitMessage": "โณ Signing out..."
  • improvement: When an Office 365 admin account is signing-in, if there is no previously defined service account, this admin account is now automatically defined as the default service account.
  • improvement: Request processing optimization for large teams (multiple Planner plans, many tasks...)
    • Implemented Microsoft Graph requests priority in our middleware
      • Team cloning as high
      • Team photo cloning as high
      • Tabs configuration as high
      • Tabs content provisioning (including planner) as low
      • Post-processing as high
      • Notifications as high
  • improvement: "โž• New Team" form
    • if there is no templates available for a user (zero templates in the catalog or only system templates or only disabled templates or no templates due to audience targeting), a message is shown to ask the user to contact their Microsoft Teams administrators.
  • improvement: "๐Ÿ“ฎ My Requests" form
    • The form title is now "๐Ÿ“ฎ My Requests" just like the related button title


  • ops: Error: Admin Consent is required. #5894
    • When a user tries to login without admin consent, an alert is sent to the CSM team
  • fixed: Error in getGeneralChannelId: Failed to execute Skype backend request GetThreadsRequest. #5917
    • Detail: {"statusCode":500,"code":"GeneralException","message":"Failed to execute Skype backend requestt..."}
    • Root cause: Microsoft Graph may send a 500 error sometimes
  • fixed: Microsoft Graph error status code
    • The Microsoft Graph api sometimes generates error status code as a "status" property, sometimes as a "statusCode" property
  • fixed: Microsoft Planner API throttling
  • fixed: Microsoft Graph Error 404 in function: waitForTeamsAsyncOperation with arguments (PRD) #5419
    • Root cause: Sometimes, there is a delay between starting cloning a team and the moment where you can call the /operations endpoint
    • Solution: In case of error 404, try to replay call to /operations later
  • ops: Issues are now affected to different teams depending on their type.
    • For instance:
      • CSM: admin consent approval, service account issues
      • OPS: Generated audit trails and logs
      • DEV: Exceptions
  • improvement: Microsoft Graph inner exceptions
    • Sometimes, the Microsoft Graph api returns internal errors or misleading error messages, such as:
    // ...
    "text":"{\r\n "error": {\r\n "code": "",\r\n "message": "You do not have the required permissions to access this item, or the item may not exist.",\r\n "innerError": {\r\n "request-id": "REDACTED",\r\n "date": ""\r\n }"
    • Resolution: Implement bottleneck retry mechanism for some Graph exceptions
  • fixed: Error generating notification message
    • Related issue: graphHelper/createChatThread error: {"status":400,"response":{"req":{"method":"POST","url":"" (PRD) #5219
    • Root cause: The /chatThreads endpoint is deprecated
    • Solution: Moved to the /messages endpoint
  • fixed: Error getting team photo
    • Related issue: Error in generateTeamLogo/cloneTeamLogo: {"statusCode":406,"code":null,"message":null,"requestId":null,"date":"2019-11-24T19:09:58.789Z","body":null,"arguments":[""] (PRD) #5203
    • Root cause: The /beta/teams/TEAM_ID/photo/$value endpoint raise an error 406
    • Solution: Moved to the v1.0 version
  • fixed: Error saving jobs audit trails
    • Related issues:
      • JOBSSCHEDULER: Error writing jobs audit trail: {"errno":-2,"code":"ENOENT","syscall":"open","path":"./audit/jobs/uat-renewServiceAccountTokens-2019-11-24.csv"} (UAT) #5119
      • JOBSSCHEDULER: Cleaning Job: Error in saveTaskExecutionHistory (UAT) #5148
  • fixed: Error saving extractIntercomData job export data
    • Related issues:
      • JOB extractIntercomData: Error writing events export file: {"errno":-2,"code":"ENOENT","syscall":"open","path":"REDACTED"} (PRD) #5413
      • JOB EXTRACTINTERCOMDATA: Task execution failed: extractIntercomData done (PRD) #5412
      • JOB extractIntercomData: Error writing companies export file: {"errno":-2,"code":"ENOENT","syscall":"open","path":"REDACTED"} (PRD) #5411
      • JOB extractIntercomData: Error writing users export file: {"errno":-2,"code":"ENOENT","syscall":"open","path":"REDACTED"} (PRD) #5410


  • improvement: Email naming convention
    • If the email naming convention results in an empty address, the generated team name is now used instead.
  • fixed: Service account token expiration after 90 days
    • Error message: The refresh token has expired due to inactivity.
    • Error log:
      "text":"{\"error\":\"invalid_grant\",\"error_description\":\"AADSTS700082: The refresh token has expired due to inactivity. The token was issued on XXXTXXXZ and was inactive for 90.00:00:00.",\"error_codes\":[700082]\"error_uri\":\"\"}"
    • Error code:
    • Root cause: After 90 days, the refresh token used to get a new access token for the service account is expiring automatically. For the first 90 days, the newly acquired refresh token was used but not persisted.
    • Resolution:
      • Each access token refresh now persists the new refresh token
      • A scheduled job renews service accounts token daily
  • improvement: Service Account initialization
    • The first Office 365 administrator to login is now used as the default service account.
  • fixed: User names case is now preserved in Intercom


  • improvement: Notifications messages localization #231
    • Service Account provisioning messages are now generated using:
      • The associated template language.
      • As a first-level fallback the requester language
      • As a second-level fallback to 'en-us'
  • fixed: Error in postProcessRequest: {} (DEV) #4634
    • Error message: Cannot read property 'length' of undefined
  • fixed: Prevent error in loadIntercomAuthenticated when a user has empty profile fields (such as preferredLanguage)


  • fixed: Microsoft Graph exception: isTenantAdmin error
  • fixed: Microsoft Graph exception: addGroupMember error
  • fixed: Microsoft Graph exception: getPlannerPlanDetails error
  • fixed: Microsoft Graph exception: getTeamStructure error
    • Error 503 on /teams /channels / tabs endpoint
    • Related exceptions:
      • Error exporting source team structure in getTeamStructure. (UAT) #4458
      • Unable to retrieve tabs in getTeamStructure/listTabs. (UAT) #4457
      • Error in graphHelper/listTabs. (UAT) #4456
      • Error in graphHelper/listTabs. (UAT) #4455
  • fixed: Microsoft Graph exception: cloneTeamLogo error
    • Error 504 on /teams /photo/$value endpoint
    • Related exceptions:
      • Error cloning team photo: {"statusCode":504,"code":"UnknownError","message":"","requestId":"REDACTED","date":"REDACTED","body":"{\"code\":\"UnknownError\",\ (UAT) #4452
      • graphServices/updateTeamPhotoByFile error (UAT) #4451
      • Error in generateTeamLogo/cloneTeamLogo: {"statusCode":504,"code":"UnknownError","message":"","requestId":"REDACTED,"date":"REDACTED","body":"{\"code\":\"U (UAT) #4450
  • improvement: During the provisioning process, cloned Planner tabs are now configured to use the user language #213
    • Planer tab configuration now respects the following scheme:
    contentUrl: '[TENANT_ID]/Home/PlannerFrame?page=7&planId=[PLAN_ID]&auth_pvr=Orgid&auth_upn={upn}&mkt={locale}'
    websiteUrl: '[TENANT_ID]/Home/PlanViews/[PLAN_ID]'
    removeUrl: '[TENANT_ID]/Home/PlannerFrame?page=13&planId=[PLAN_ID]&auth_pvr=Orgid&auth_upn={upn}&mkt={locale}'
  • fixed: An arror was generated for user profiles without photo
    • Related exception: {"statusCode":404,"code":null,"message":null,"requestId":null,"date":"2019-11-20T11:28:31.129Z","body":null} (UAT) #4632


  • fixed: Planner plan creation error #4192
    • When a Graph api internal error occurs during the creation of a Planner plan, the function that handles the creation of a new audit log may fail due to an empty callback. #4195


  • improvement: nBold's publisher domain validation by Microsoft
    • Configuring the publisher domain has an impact on what users see on the app consent prompt.
    • Especially, an applicationโ€™s publisher domain is displayed to users on the applicationโ€™s consent prompt to let users know where their information is being sent.
    • Implications on the app consent prompt
  • improvement: "My Requests" popup
    • Larger popup (max width to 1140px)
  • fixed: In some edge cases (misconfigured tabs or tabs in an inconcictent state), the wrong number of tabs is shown in audit trail.


  • ops: Better client-side error tracking
    • If an error arises client side (teams client or browser), the following tags are automatically populated:
      • Before login:
      loginHint, // Usually user email
      teamSiteDomain, // *
      tid // tenant id
      • After login:
      msEmail, // user email
      msTenantInitialDomainName, // Tenant initial domain name
      msTenantDefaultDomainName, // Tenant default domain name
      tid // tenant id
  • fixed: Teams photo update changes the request status
    • Context: The photo update process may last for a long time due to the asynchronous Exchange Mailbox provisionning process it depends on.
    • Previous behavior: If the photo update happens after the "Teams Provisionning Done" event, it changes the request status to "processing" after the "done" event.
    • New behavior: The "photo updated" audit log entry now doesn't change the request status, therefore it will be seen as:
      • "Processing" or "Post-Processing" if the photo update happens before the "done" event
      • "Done" if the photo update happens after the "done" event
  • fixed: Better management and reporting of edge cases during provisionning
    • Handles properly unconfigured tabs (Website, Planner...)
    • Handles properly deleted channels
    • Handles teams without any tab
    • Handles Planners plans without buckets and buckets without tasks
    • Zero requested members or owners
    • Zero permanent members of owners
    • Better audit logs for tabs processing:
      • Each tab shows the tab type and name
      • The tabs summary shows the number of processed tabs
    • New log message when an error occurs in tab provisionning (including unsupported tab)
    • Cleaner tab names in audit trail (URL decode)
    • New all tabs configured message (even if a tab is in error)


  • fixed: i18n: Incorrect translations with Indian english locale (en-in)
  • ops: Asynchronous Jobs Engine
    • This new scheduler is meant to execute scheduled batch processes in a secured environment
    • Supports different execution environments and schedules for dev, uat, ppr and prd
    • Follows the CRON syntax for scheduling, including second-level scheduling
    • Jobs are defined using the following JSON representation:
      id: 'JOB_ID',
      description: 'JOB_DESCRIPTION',
      module: 'MODULE_PATH',
      dev, uat, ppr, prd
      dev: '- - - - *',
      uat: '- - - - *',
      ppr: '- - - - *',
      prd: '- - - - *'
      options: {JOB_OPTIONS}
      • Jobs should be implemented as a regular nodejs module, exporting a 'start' method with the following prototype:
      - Module main entry point
      - @param {string} logFile - Relative log file path
      - @param {function} Callback - (err, res, msg)
      let myJob = (options, (err, res, msg) => {
      // Job implementation
      exports.start = myJob
      • Jobs execution history are persisted at regular intervals as csv audit trails files and in our GiHub ops repository as issues with the 'jobs' tag, as serialized objects:
      let taskExecutionRecord =
      jobId: 'JOB_ID', // String
      startDate: 'START_DATE', // Date
      endDate: 'END_DATE', // Date
      duration: 'EXECUTION_DURATION', // Int, as ms.
      succeeded: EXECUTION_RESULT, // Boolean
      message: 'EXECUTION_MESSAGE', // String
      errorPayload: 'ERROR_PAYLOAD', // String (Stringified JSON)
      successPayload: 'SUCCESS_PAYLOAD', // String (Stringified JSON)
  • fixed: Log files persistance from Windows containers
    • Handling both "\" and "/" path separators
  • fixed: Missing requests from the "My requests" page
    • Root cause: For certain users, the number of requests returned from our cache may vary
    • Resolution: Fix the SCAN Redis operations
  • fixed: Error generating team logo #2409
    • Now using the "teams" Microsoft Graph beta API endpoints
  • improvement: Team photo update in requests audit trail
    • Now the "Team photo updated" event is visible in audit trail as part of post-processing operations
  • fixed: Random error in team photo update
    • Root cause: Trying to update the underlying group photo of a team just after its provisioning may fail as the related Exchange Mailbox may not be fully provisioned yet (required to store group photo)
    • Resolution: Handling specific returned error codes and implement a retry mechanism
  • refactor: Microsoft Graph SDK
    • Using the nodejs Microsoft Graph SDK instead of native REST requests for streams operations (binary files, photos updates...)
  • improvement: Users without profile pictures
    • For users without profile pictures, our front-end dergrades gracefully, hiding the user profile picture zone without unnecessary latency.
  • fixed: Permanent membership missing information in audit trail
    • Permanent membership notifications in audit trail are now showing members and owners names individually
  • refactor: Our mail module is now abstracted from its service provider implementation
  • refactor: Our GitHub module is now fully independent and dependency free


  • improvement: Template management analytics
    • Tracking a new event on user profile 'template_created' and 'template_updated' with the following metadata:
      template_id: REDACTED,
      template_name: REDACTED
    • Tracking a new attribute on company profile 'template_count' (# of templates)


  • fixed: Analytics Events
    • References:
      • Error creating analytics event #2322
      • fixed: Events: "Template Created" event is not raised #271
      • fixed: Intercom exception: Multiple existing users match this email address REDACTED #255
    • Fixes:
      • user email and id are now forced to lower case to prevent duplicates
      • Intercom user id is now based on:
        • user upn in identified mode (in teams without beeing authenticated yet)
        • user email in authenticated mode (in teams authenticated)
      • Intercom company id is now based on tenant initial domain name (*
      • Intercom company name is now based on tenant initial domain name (*
      • Tracking a new event on user profile 'serviceaccount_updated' with the following metadata:
        serviceaccount_id: REDACTED,
        serviceaccount_name: REDACTED,
        serviceaccount_upn: REDACTED
      • Tracking new attributes on company profile:
        • 'company_customer_id': nBold internal customer id
        • 'serviceaccount_initialized': Initialized to 'true' the first time a service account is defined #259
  • fixed: Planner cloning exceptions in case of empty planner or empty buckets
    • Error in allTasksProcessed: {} #1139
    • Error in allTasksProcessed: Cannot read property 'length' of undefined #2076
  • improvement: Better anomaly tracking. The following exceptions are now properly logged and surfaced with a meaningful message in audit log:
      • Message: The generated email address for this team is empty or incorrect...
      • Explanation: The naming convention applied to this template has generated an invalid email address for the underlying group related to the team. For instance:
        • The total prefixes, address and suffixes string length is restricted to 53 characters.
        • Avoid using the following characters in your email policy: #, [, ], <, and >
      • Required action: Fix the template's naming conventions
      • Processing behavior: The provisioning process is stopped and flagged in an "error" stage
      • Message: Trying to clone an app without related app...
      • Explanation: You're trying to clone a team that contains tabs using custom apps.
      • Required action: Fix template configuration to either:
        • Include apps during cloning
        • Exclude tabs during cloning
      • Processing behavior: The provisioning process is stopped and flagged in an "error" stage
      • Message: The template you're using is linked to a deleted team...
      • Explanation: The team to be cloned from the template has been deleted.
      • Required action: Either:
        • Restore the deleted team
        • Associate template with another team
      • Processing behavior: The provisioning process is stopped and flagged in an "error" stage
      • Message: nBold Service account doesn not have Teams licences...
      • Explanation: The service account defined in nBold's settings doesn't have the required licenses to access Microsoft Teams
      • Required action: Add the required Microsoft Teams licences to your service account
      • Processing behavior: The provisioning process is stopped and flagged in an "error" stage
      • Message: Microsoft Graph. An unknown error occured during processing on Microsoft Servers...
      • Explanation: An error occured on Microsoft servers during a Microsoft Graph operation.
      • Required action: None
      • Processing behavior: The provisioning process will automatically retry the operation after a few seconds until is works properly


  • ops: Logging improvements
    • Log files are now rotated every 14 days
    • Now generating an audit trail of file logging operations:
      "date": "REDACTED",
      "name": "REDACTED.log",
      "hash": "REDACTED"
  • fixed: 2 teams created per Request #247
    • The "Send request" button is now disabled immediately while processing the request to prevent double clicks
    • Better "click" handlers to prevent multiple registrations
  • fixed: Messages in 2 different languages appear on the same page #260
  • improvement: Locale is now set using a fallback mechanism, that uses the following order of priority to determine the right locale to be used:
    1. From Microsoft Teams context (Language defined in the Microsoft Teams client)
    2. From the browser client language
    3. Set to en-us in any other case
  • improvement: Locale is now detected and updated during each request.
    • Therefore you can update the language of your Microsoft Teams client, and you don't need to logout from nBold to see change.
  • feat: Template Language
    • You can now associate a language with each template, within the following list:
      • en-au
      • en-bz
      • en-ca
      • en-gb
      • en-ie
      • en-jm
      • en-nz
      • en-ph
      • en-tt
      • en-us
      • en-za
      • en-zw
      • fr-be
      • fr-ca
      • fr-ch
      • fr-fr
      • fr-lu
      • fr-mc
    • Structure:


  • fixed: Deep links not working on home page #261
  • fixed: Naming convention not shown in request form #262
    • Updated online documentation about Naming Conventions
    • Includes a descriptive error message in case of bad naming convention configuration
  • fixed: Deep links not working on home page #261
  • improvement: Better management of template configuration issues:
    • Tabs cannot be cloned without cloning Apps as well
    • Reference: #265
  • improvement: Better management of service account configuration issues:
    • Managed exception: "User Login. Teams is disabled in user licenses"
    • Reference: #264
  • improvement: Deeplink visual feedback
    • From the homepage, when clicking on a deeplink (open or talk), the button text is updated to reflect the action
  • ops: Browser alerts are now raised in our GitHub ops platform, including:
    • Catched error
    • Stack trace
    • Browser infos
    • Teams Context
    • Screenshot
  • security: Self-hosted fonts.
    • Now all fonts resources are loaded from the nBold platform instead of using Google Fonts CDN
    • Not necessarily a security issue, but:
      • Reduces the number of domains to whitelist
      • Prevents any data flow with Google
    • Updated doc: ๐Ÿณ Domains to whitelist
  • refactor: Improved ChecknBoldTenant method
    • New logging capabilities
    • Externalized nBold tenant id per environment
  • refactor: Check for Microsoft Accounts (personal accounts)
    • New logging capabilities
    • Externalized Microsoft tenant id
  • fixed: User events tracking in case of duplicates
    • "Multiple existing users match this email address REDACTED - must be more specific using user_id #255
  • fixed: Error caching picture #254
    • Added new logging capabilities to blob storage helper
  • ops: An alert is now raised in our GitHub Ops when a login attempt is made without admin consent.
    • This alert includes session id, locale and tenant id
  • improvement: Request additional owners and members.
    • When requesting the creation of a new team from a template, you can now select up to 5 owners and 10 members.
    • Limits are now surfaced as help messages and tooltips: "You can select up to X additional owners/members."
  • ops: Logging and alerting improvements.
    • Logs persistence and alerting in our GitHub Ops platform is now disabled in development environments
    • Our analytics platform is now collecting users sign-in and sign-out events
    • When an alert is raised, it's now collected to our GitHub Ops platform
    • Log files are now collected and persisted in our GitHub Ops platform
    • The nBold app and services are now handling gracefully process shutdown, on any platform.
  • improvement: When defining security policies for a specific template, you can now select up to:
    • 5 approvers per template.
    • 5 permanent owners per template.
    • 10 permanent members per template.
  • doc: New platform contents in our Help Center
  • improvement: Admin and non-admin users can now sign-out of the app from any page.
  • fixed: In Firefox browser, the non-admin user is unable to access the โ€˜Back to Homeโ€™ button.
  • fixed: In Edge browser, the admin & non-admin user is unable to access the โ€˜sign-inโ€™ button.
  • fixed: In Chrome browser, when non-admin user is accessing the โ€˜Back to Homeโ€™ button, user is redirected to a new tab.

[1.1.0] Codename "Reiwa"โ€‹

  • fixed: App store publishing
    • Issue #1: App version is not as per guidelines. (Closed)
    • Issue #2: Please elaborate the full description such that it states about the value proportion of the app. - (Closed)
    • Issue #3: Emojis / special characters are not allowed in the manifest. (Closed)
    • Issue #5: To have consistency in naming please rename the logout to sign out. (Closed)
    • Issue #6: User is getting an error message after clicking on the links available in the โ€œservice status tab. (Closed)
    • Issue #7: When user clicks on the GitHub link, user is navigation to 404 error page. (Closed)
    • Issue #9: Please add a graceful message in the catalogโ€ and โ€œsettingsโ€ tabs when non-admin users access the tab. (Closed)
  • fixed: Non-admins accessing admin-restricted tabs (Catalog, Settings) are just seeing a blank page
    • Now non-admins are presented with a clear message requesting them to log as an Office 365 administrator, and a "back to home" button
  • ops: Approval button and Adoption tab are hidden for now in ppr/prd
  • ops: Set up pre-production environment - Ring 3.5 #228
    • New standalone + targeted packages
  • fixed: The export / import feature is now hidden in UAT, PPR & PRD
  • fixed: Not Able to Create New Solution #216
  • fixed: Issue with Account Creation - account in de-de #229
    • All languages and regions variants supported by Office 365, either with a proper translation, or through a fallback to english.
  • security: prototype pollution in _.defaultsDeep
    • Dependency: lodash
    • Upgrade lodash to 4.17.14
    • Upgrade lodash.template to 4.5.0
  • fixed: Tab configuration screen now has a default value and is enabled by default
  • security: disallow access to the constructor in templates to prevent RCE
    • Dependency: handlebar
    • Upgrade handlebar to 4.1.2
  • fixed: <%> in description in Teams Template creation forms #126
  • improvement: Improved nBold Targeting Package 1st connection experience #207
  • fix All tabs not replicated #155
  • fixed: Events not raised in intercom #203
  • fixed: Internationalization issues
    • Locale issue : Issue with package language and App #204
    • fr-fr : issue with french and english in same page #202
    • fr-fr : packaging showing up settings and paramรจtres #200
    • FR version : Talk to owners and open in home are not translated #187
    • Language in teams desktop client is always en-us
    • "New Team" form: Tooltips, Preview...
  • improvement: My Teams cards "Tags"
    • Now my teams cards have visual clues for:
      • Visibility
      • Archival
      • Classification
  • fixed: Login page
    • Outside links in login menu to help and status
    • nBold version number in menu

[1.0.0] Codename "Makuuchi"โ€‹

  • improvement: Behavioral Analytics

    • Attributes
      • Client-side implementation
      • Attributes structure: OBJECT_PROPERTY
      • Attributes sources:
        • Environment: nBold App environment-based information
        • Context: Microsoft Teams context-based information
        • Profile: Microsoft Graph user profile-based information
      • Attributes by stage (Additive):
        • Anonymous: (If used outside of Teams)
          • None
        • Identified: (Using Teams context, before nBold login)
          "profile.intercomId": context.upn, // Not yet authenticated, use the upn
          "profile.intercomEmail": context.upn,
          "profile.locale": context.locale,
          "profile.msTenantId": context.tid,
          "profile.msUpn": context.upn,
          "profile.theme": context.theme,
          "profile.msUserId": context.userObjectId,
          "profile.environment": env.environments.current,
          "profile.version": env.environments.manifest.version
        • Authenticated: (Using Microsoft Graph Profile, after nBold login)
          "profile.intercomId": user.msEmail, // Once authenticated, use the email instead of UPN
          "profile.intercomEmail": user.msEmail,
          "profile.msEmail": user.msEmail,
          "profile.tld": userTld,
          "": user.msDisplayName,
          "profile.msLocale": user.msPreferredLanguage,
          "profile.license": user.userLicense,
          "profile.msIsTenantAdmin": user.isMsTenantAdmin,
          "company.companyName": customer.msTenantInitialDomainName,
          "company.msTenantId": customer.msTenantId,
          "company.msTenantInitialDomain": customer.msTenantInitialDomainName,
          "company.msTenantDefaultDomain": customer.msTenantDefaultDomainName,
          "company.license": customer.customerLicense
    • Events
      • Server-side implementation using the Intercom SDK
      • Events structure: OBJECT_ACTION
      • Captured events and metadata:
        request_created: {
        request_id: '',
        team_name: '',
        request_additionalMembers: '',
        request_additionalOwners: '',
        template_id: '',
        template_name: ''
        request_approved: {
        request_id: ''
        request_rejected: {
        request_id: ''
        request_processed: {
        request_id: ''
        request_error: {
        request_id: ''
        team_created: {
        team_id: '',
        team_name: '',
        template_id: '',
        template_name: ''
  • improvement: "My Teams" deep links for "๐Ÿ’ฌ Talk to owners" and "๐Ÿ‘“ Open"

    • Now links are opened without opening a new browser window
  • fixed: Issue with login in browser #186

  • refactor: Dynamic teams packages generation

  • security: is now a verified publisher domain

  • ops: Production App is now called "nBold"

  • refactor: Update manifest to v1.5 schema

  • fixed: New Template in Business Solution creation #194

  • ops: Cosmos DB Throttling Management

    • Each environment has its own configuration (connectionPolicy)
    • An Azure alert sends a notification to the Teams DevOps \ Ops channel if more than 5 requests are throttled during the last 15min.
  • improvement: Service account is now explicitely added as a member of the created teams, in addition to be an owner.

    • This fix is a workaround to an issue while using the Microsoft Graph
  • feat: Requests management

    • See your requests with their status, progress, log and actions
      ๐Ÿ“ฎ saved: 'REQ_STA_SAVED', // Just saved after user request
      ๐Ÿ• preprocessing: 'REQ_STA_PREPROCESSING', // prepping things before approval (or direct processing)
      ๐Ÿ approval: 'REQ_STA_APPROVAL', // Waiting for approval
      โ›” rejected: 'REQ_STA_REJECTED', // Rejected
      โœ… approved: 'REQ_STA_APPROVED', // Approved
      ๐Ÿ•“ processing: 'REQ_STA_PROCESSING', // Provisionning is running
      ๐Ÿ“ฆ processed: 'REQ_STA_PROCESSED', // Processed (Done)
      ๐Ÿšฉ error: 'REQ_STA_ERROR', // Error
      ๐Ÿ›ธ Unknown: 'REQ_STA_UNKNOWN' // Unknown
    • fixed: Request card doesn't take into account the naming convention #112
    • fixed: My Request showing all Teams request created with no approval in Pending #110
    • fixed: No information for Teams Request with error, displayed in "pending" #111
  • improvement: Search for teams processing is now delayed by 500ms before each typing, to prevent multiple executions

  • feat: My Teams are now sorted by display name (including in search results)

  • fixed: Service Account processing #189

  • refactoring: All scheduled jobs are now using the CRON syntax

    • Allowed fields:

      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ second (optional)
      โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ minute
      โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ hour
      โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ day of month
      โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€ month
      โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€ day of week
      โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
      โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
      - - - - - *
    • Allowed values | field | value | | ------------ | --------------------------------- | | second | 0-59 | | minute | 0-59 | | hour | 0-23 | | day of month | 1-31 | | month | 1-12 (or names) | | day of week | 0-7 (or names, 0 or 7 are sunday) |

    • Using multiples values

      cron.schedule('1,2,4,5 - - - *', () => {
      console.log('running every minute 1, 2, 4 and 5')
    • Using ranges

      cron.schedule('1-5 - - - *', () => {
      console.log('running every minute to 1 from 5')
    • Using step values

      cron.schedule('*/2 - - - *', () => {
      console.log('running a task every two minutes')
    • Using names

      cron.schedule('- - - January,September Sunday', () => {
      console.log('running on Sundays of January and September')
    • Using short names

      cron.schedule('- - - Jan,Sep Sun', () => {
      console.log('running on Sundays of January and September')
  • feat: nBold tab configuration page

    • When adding nBold as a tab in a channel, a new configuration page is available
      • Choose your tab name + "save" button status control
      • ToS reminder
      • New design
  • refactor: Improved performance for "My Teams" widget on homepage

    • Now results are paginated by pages of 20 teams
    • Search results are also paginated
  • security: Enforced tokens security

    • Encryption in transit and at rest for server-side services:
    • Client-side:
      • Tokens are only used in memory, and never stored in cookies or browser local storage.
      • Access to tokens via API is protected using Azure AD authentication.
  • refactor: Enabled sign-in to nBold from a webpage outside of the Teams Clients

    • Now, in addition to our stEntityId parameter, tabs urls have the following parameters dynamically provided by Teams clients:
    • See Tabs Context for reference
  • doc: Help Center now have a new accentuation color aligned with Microsoft Teams branding

  • refactor: All string-based messages are now externalized for internationalization

    • Except for the "Settings" tab
    • Using:
      • Server-side: i18n
      • Client-side: custom i18n module
  • improvement: Improve experience with "enabled" / "disabled" in catalog #133

  • improvement: Text truncating for teams and templates cards

    • Templates cards texte are truncated to one single line
    • Fully responsive, truncating is recalculated on window resize event
    • Using Dollar Shave Club Shave Module
  • fixed: The "Sign-in" button is now disabled while a login popin is opened top prevent multiple login windows to open.

  • improvement: Audience Targeting Settings

    • Now audience targeting settings have their own tab in template settings
    • Rule editor has more space through a height of 200px
  • doc: New Audience Targeting scenario: "Domain-based targeting"

  • doc: New conditional naming convention scenario

  • fixed: Issue with "male icone" that appears only in client #151

  • improvement: Prevent user to login with a Microsoft Account and demand an Office 365 account.

  • fixed: Intercom not displayed correctly #168

    • Error message:
      "something's wrong", "we're unable to load the messenger"
    • References: Difficulty accessing the support chat
    • The Intercom security check is now based ont the current user email instead of its UPN.

[0.9.11] Codename "Juryo"โ€‹

  • security: App Permissions and Scopes
  • fixed: Double-Login Bug
    • No more "double-login". Fixed in all environments
  • doc: Help Center Layout and Navigation
  • doc: Audience Targeting Configuration
  • security: Fixed GitHub security alerts
    • Dependency: concat-with-sourcemaps
  • fixed: Width issue in template creation #169
    • form width is now at 75%
  • ops: UAT deployed with Azure DevOps Pipeline
  • refactor: Teams Apps Packaging
    • One package for each supported language
    • Packages are now downloadable from the Help Center
  • doc: GitHub Automated Security Fix & environment isolation
  • ops: Static Code Analysis in BO
  • improvement: Templates in the Catalog now have a fixed height #128
    • Description and cloned team name are now truncated to fit into one single line
  • ops: Automated GitHub Release Process (Bump, Commit, Push, Tag) using Gulp
  • ops: Updated Back-Office with docs, process, operations manual and logs
  • refactor: Globally Applying Standard JavaScript Style Guide
  • improvement: Template Form Design
  • fixed: Salestim Admin shown to regular users #113
    • Enforced security checks with additional server controls
    • Security improvement using the current user directory role for tabs catalog, reports and settings.
      "@odata.type": "#microsoft.graph.directoryRole",
      "id": "OBFUSCATED",
      "deletedDateTime": null,
      "description": "Company Administrator role has full access to perform any operation in the company scope.",
      "displayName": "Company Administrator",
      "roleTemplateId": "62e90394-69f5-4237-9190-012177145e10"
  • improvement: Teams and Templates Search design
  • improvement: Templates Audience Targeting rules editor
    • Audience targeting is now disabled by default
    • The rules eeditor is therefore hidden by default
  • refactor: Help Center is now hosted in the app-platform repository
    • Improved navigation
  • improvement: Better rendering of "โš™ Settings \ System Information" contents
  • feat: Templates Audience Targeting
    • A targeting rule can now be applied to each template to define who can use it, based on the user profile data.
    • A "Check Syntax" button is available to test the rule against the current user
    • Rules could be defined using standard javascript expressions.
    • Known Issue:
      • Due to our caching mechanism, an update to the user profile may not be reflected immediately and therefore the targeting rule may not be applied immediately.
      • Known Workaround: Login to nBold from a browser window in "inprivate/incognito" mode to force user profile refresh.
  • ops: Persisted logs in UAT and PRD environments
    • Using winston-daily-rotate-file
    • UAT and PRD default configuration
      filename: 'ENV-salestim-%DATE%.log',
      dirname: 'OBFUSCATED',
      datePattern: 'YYYY-MM-DD-HH',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d'
  • security: Removed some external / public CDN dependencies
  • refactor: Externalized English & French translations
    • Using i18n module server & client-side
    • Applying locales with EJS template engine, based on the browser language
    • Initialized "i18n" internal documentation
  • refactor: Selective server resource public sharing with client
    • Applies to node modules, locales and enums
  • docs: Using classification in documents
    - ๐Ÿ“ข PUBLIC: Anonymous access
    - ๐Ÿ”‘ EXTERNAL: Authenticated access to external users (customers, partners...)
    - ๐Ÿ” PRIVATE: Internal-only
    - ๐Ÿ’ฅ CONFIDENTIAL: Secret and privy
  • docs: Internal and External Documents

[0.9.10] Codename "Makushita"โ€‹

  • fixed: Opportunities channels are not created
  • fixed: Opportunities channels are not updated
  • fixed: Team owners unable to access planner plans
    • Symptom: Team owners may have an error trying to access a related plan:
      Oops, something went wrong ...
      You do not have access to the requested entity.
      Date and Time
      Planner Version:
    • Root cause:
    • Solution
      • Requester is now also explicitely added as members (in addition to owner is the option is enabled)
      • Requested owners are now also explicitely added as members
      • Permanent owners are now also explicitely added as members
  • refactor: Tracking nBold build number as a pre-release version number
  • feat: Targeted packages to use Teams App Policies
    • A specific package is now available for each key feature
    • Tabs now has its own unique URL per environment to enable Intercom onboarding
  • fixed: Template pictures disappear after a few days #124

[0.9.9] Codename "Sandanme"โ€‹

  • improvement: Unique tabs URLS
  • fixed: Intercom - Multiple Company entities #121
    • Updated the Intercom company tracking code with company json payload:
      "company": {
      "company_id": "OBFUSCATED",
      "name": "OBFUSCATED"
    • [USER_HOSTNAME] is the user email full hostname (not only TLD) if available. For instance:
      "domain": "",
      "hostname": "",
      "isIp": false,
      "isValid": true,
      "publicSuffix": "com",
      "subdomain": "TENANT_NAME",
      "tldExists": true
    • If email is not available, the user tenant id is used instead.
    • References: Intercom Company Object
  • fixed: Planner Tabs Provisioning
    • With large teams, under some circumstances, planner tabs are not provisionned
    • Wiki tabs are now fully ignored (as the default cloning feature creates new "Wiki" tabs automatically). So any Wiki tab in the source team will be cloned without configuration in the new one

[0.9.8] Codename "Jonidan"โ€‹

  • fixed: Requests history log stores in the request object
  • fixed: Random addGroupOwner error
    • A random error appears sometimes when trying to add a group owner:
      "status": 401,
      "message": "Unauthorized",
      "body": {
      "code": "invalidauthenticationtoken",
      "message": "CompactToken parsing failed with error code: 80049217"
    • Resolution: Exception catched and operation replayed
  • improvement: Unauthorized access to admin-restricted tabs 118
    • Now the "Unauthorized message" has a specific button with a deeplink to the "๐Ÿ  Home" tab
    • The popin cannot be closed (nor by ESC keyboard, nor by the close button or "x" button)
    • Deeplinks reference...
  • improvement: Added "Known Issues" to the "โš™ Settings" tab
  • fixed: updateGroup Logo exception if executed too early after cloning
    • Delayed by 10 sec after cloning to prevent exception
  • fixed: Documents (CHANGELOG, KNOWNISSUES...) rendering optimization
    • Showdown options:
      openLinksInNewWindow: true,
      ghCodeBlocks: true, // Enable support for GFM code block style.
      ghMentions: true, // Enables github @mentions, which link to the username mentioned
      ghMentionsLink: true, // Changes the link generated by @mentions. Showdown will replace {u} with the username.
      tasklists: true, // Enable support for GFM tasklists.
      emoji: true // Enable emoji support. Ex: this is a :smile: emoji
    • Showdown Flavor:
    • Showdown Syntax...

[0.9.7] Codename "Jonokuchi"โ€‹

  • refactor: Request processing is now fully asynchronous
  • improvement: Requests objects now have a message history to help error diagnostic
  • refactor: Externalize "Bottleneck" package configuration for MS Graph to env vars
    • Options:
      • maxConcurrent: How many jobs can be executing at the same time.
      • minTime: How long to wait after launching a job before launching another one.
      • highWater: How long can the queue be?
      • strategy: Which strategy to use when the queue gets longer than the high water mark.
      • penalty: The penalty value used by the BLOCK strategy.
      • reservoir: How many jobs can be executed before the limiter stops executing jobs.
      • reservoirRefreshInterval: Every reservoirRefreshInterval milliseconds, the reservoir value will be automatically updated to the value of reservoirRefreshAmount.
      • reservoirRefreshAmount: The value to set reservoir to when reservoirRefreshInterval is in use.
      • reservoirIncreaseInterval: Every reservoirIncreaseInterval milliseconds, the reservoir value will be automatically incremented by reservoirIncreaseAmount.
      • reservoirIncreaseAmount: The increment applied to reservoir when reservoirIncreaseInterval is in use.
      • reservoirIncreaseMaximum: The maximum value that reservoir can reach when reservoirIncreaseInterval is in use.
    • Constructor Options References...
  • fixed: Team Creation not working (ownership error) #108
    • This issue is due to a requirement from the MS Graph that expects the logged in user to be an owner of the team to operate on it. Ref...
  • fixed: Sync delay between O365 Group owners and members with Team owners and members
  • fixed: Preview info issue for Template with no default name and no naming convention #109
    • The default system templates now are using the new dynamic tagging convention based on the EJS templatinf syntax:
  • doc: Known issues
    • A file is now released as part of our release process in the "dist" folder
  • doc: Added a known issue "Missing teams in list all teams when creating a new template"
  • fixed: Cloned team selection filter
    • Moved to the beta endpoint to use filters (only available through the beta endpoint):
    $filter=resourceProvisioningOptions/Any(x:x eq 'Team')
  • fixed: Text preview not displayed when no info is entered with a Naming Convention configured Template #107
    • Now the previews for name, description and welcome message are shown even if the related fields are empty.


  • improvement: Tracking basic anonymous informations to streamline support operations.
    • locale: Microsoft Teams Language
    • tid: Azure AD Tenant ID
    • upn: Azure AD User UPN
    • uid: Azure AD User ID
    • stuid: nBold User ID
    • sttid: nBold Customer ID
    • stlic: nBold License
    • environment: Last Visited Environment
    • version: Last Visited Version
  • fixed: Salestim Admin shown to regular users #113
    • Now access is restricted to Office 365 global administrators
  • improvement: Check Service Account
    • Now service account check results are displayed in the Tim message popin
  • fixed: Approver configured template not displayed for users in "+Team" #115
  • fixed: Requester not added as a Team Owner #114
  • fixed: Handle empty email convention error and email alias bad format
    • Better error handling with end-user message
  • fixed: Teams Creation not working (deleted team error) #108
    • Better error handling with end-user message
  • improvement: Better exception handling
    • Visibility of the underlying exception and technical infos
    • Direct talk to nBold support through Intercom
  • improvement: Empty / invalid email nickname used for team provisionning
    • Better error handling + End-user message
    • The error is logged into the related request
  • improvement: Deleted / invalid cloned team used for team provisionning
    • Better error handling + End-user message
    • The error is logged into the related request
  • feat: Try a template directly from the "๐Ÿ“š Catalog" tab
    • N.B: You always have to choose the template explicitely (to see how it looks like from the template selection)


  • improvement: App package including tabs with emojis
  • fixed: Sessions isolation enforcement #102


  • feat: Check requirements for the service account
    • A new "Check Requirements" button is available from the "โš™ Settings \ Service Account" tab
  • feat: Logout button from the "โš™ Settings" tabs
    • N.B: Kills the nBold session, not AAD session used by Microsoft 365
  • fixed: the "My Requests" menu sometimes doesn't work properly
  • improvement: No more popin flickering when loading the "๐Ÿ  Home" tab
  • improvement: User are notified when trying to enable a template without associated team to clone
  • improvement: Template are automatically enabled / disabled if there is / no cloning team associated
  • fixed: Selecting a team to clone should not updates system templates names and description
  • fixed: Template "Export" button should be disabled in production before GA
  • fixed: "system and "singleton" template properties are lost after an update
  • fixed: parts to clone bad formating
  • feat: Removed App status in UAT from service status
  • feat: Added API status from service status


  • fixed: i18n Internationalization
    • i18n is now dynamically configured per environment
    • All ccurrently unsupported languages (DE, ES) are now defaulted to EN
  • fixed: FR translations for the login page
  • feat: "System Information" from the "โš™ Settings" tab
  • feat: "Environment" infos from the "โš™ Settings \ System Information" tab
  • feat: "Changelog" infos from the "โš™ Settings \ System Information" tab


  • fixed: Templates without cloned team are automatically disabled at creation / update
  • improvement: System templates handling
    • System templates are disabled by default as long as a cloning team has not been assigned
    • System templates are hidden from end-user team request form except for "Default"
    • The following fields cannot be updated in system templates:
      • Name
      • Description
      • Approval / Approval Team
    • The following actions are not available from system templates:
      • Export
      • Delete
      • Enable / Disable
  • improvement: System templates versionning aligned with app versionning
  • fixed: Not all enabled templates were visible in the team request form


  • fixed: Default templates appears disabled on first launch #103
  • improvement: Services Account Login #104
    • When login for the first time the service account in the app, the app automatically refreshs just after the login so that Admin are seeing that the account is actually connected.
  • fixed: Template info card update with false informations #105
  • fixed: Preview of naming conventions
  • improvement: Enabled Azure App Insights Live Metrics
    • Application Insights Live Metrics allows to view telemetry like CPU and memory in real time.


  • improvement: Service account selection from the "โš™ Settings" tab
  • fixed: Hide api beta features for rings < 4
  • feat: Delete a template


  • feat: Naming Conventions & User tags
    • Naming conventions for fields "Name", "Email", "Description" and "Welcome Message" now supports the following tags from the user profile:
      <%= user.msDisplayName %>
      <%= user.msUPN %>
      <%= user.msEmail %>
      <%= user.msPreferredLanguage %>
      <%= user.msGivenName %>
      <%= user.msCountry %>
      <%= user.msCompanyName %>
      <%= user.msDepartment %>
      <%= user.msCity %>
      <%= user.msJobTitle %>
      <%= user.msSurname %>
      <%= user.msUsageLocation %>
    • Tagging follows the EJS syntax:
      <%= TAG_NAME %>
  • feat: Email default domain
    • The "Email" naming convention is now prefilled with the default tenant domain as a suffix
  • fixed: Check disabled templates from request form
    • Better error handling
  • fixed: Requester as a team owner
    • Better error handling
  • fixed: Owners and members at creation
    • Better error handling
  • fixed: Permanent Owners and Members at creation
    • Better error handling


  • feat: Naming Conventions & Requests tags
    • Naming conventions for fields "Name", "Email", "Description" and "Welcome Message" now supports the following tags from the request:
      <%= %>
      <%= %>
      <%= %>
      <%= %>
      <%= %>
      <%= %>
    • Tagging follows the EJS syntax:
      <%= TAG_NAME %>
  • fixed: Naming conventions with bad tags
    • Now manages mispelled tags properly by skipping templating
  • fixed: Apply team security / visibility
    • Better error handling
  • refactor: Manage parts to clone from template
    • Performance optimization and better error handling
  • feat: Group email MailNickName naming convention
    • Admins can now configure an "Email" (of the underlying group) naming convention, distinct from the "Name" naming convention
  • fixed: Template icon from team picture
    • Fixed picture cache issue
  • fixed: Template editing / save
    • Fixed template cache issue
  • improvement: Caching template pictures
    • Template pictures are now cached for later use
  • refactor: Dynamic Alpha / Beta features loading
    • Alpha and Beta features are now enabled and visible only in rings lower than "Production" (= Development & UAT)
  • fixed: Enable / disable a team template
    • Better error handling
  • security: Configure 2FA for npm
    • NPM dependency integration into our repository are now protected by 2FA authentication
    • References...
  • fixed: Manage emoji in teams channels and tabs names
    • Better error handling
    • Fixed the messsage size issue with Microsoft Graph API
  • refactor: Handle Graph throttling with bottleneck
  • feat: Clone team logo for user requests
    • Following a user manual request, cloned team now are provisioned with the picture coming from the source team
  • feat: Apply team logo from account domain
    • Following a CRM event, cloned team now are provisioned with the picture coming from the source team


  • feat: Website tab Cloning
    • Tabs configuration of type "Website" from the source team are now cloned
    • Applies only if "Tab Cloning" is enabled for a template
  • feat: Planner tab Cloning
    • Tabs configuration of type "Planner" from the source team are now cloned
    • Applies only if "Tab Cloning" is enabled for a template


  • feat: Split Packages to bring more granular deployment capabilities


  • improvement: Instrumentation with Azure Application Insights
  • tests: Check server-side and client-side implementation
  • tests: Ensure environments segragation & customers partition at cache and db level


  • refactor: Unified team cloning across AUT and SF
  • security: Customer segragation at cache and db level
  • refactor: Instrumentation with App Insights
  • fixed: Updated destroy session url
  • improvement: Added emoji for uber rides requests
  • improvement: Added Uber Deeplinks
  • refactor: Updated client app id
  • fixed: Fix SSL hosting for bot in PRD
  • feat: Bot with mockup data
  • refactor: Included bot mode
  • fixed: Fix undefined parameter using redis
  • refactor: Include crm integration in UAT and PRD
  • tests: Use Azure Redis & CosmosDB for DEV
  • fixed: Fixed cosmosdb sdk & emulator version mismatch
  • fixed: Updated scripts for pm2
  • fixed: native node ssl hosting
  • security: Export cert & pfx
  • improvement: Express SSL mgmt
  • improvement: Dynamic app port from env file


  • BREAKING CHANGE: Running from src frolder
  • feat: Enabled SF integration with team templating
  • fixed: Fix teams deeplinks
  • fixed: Fix UAT & PRD env vars
  • refactor: Updated STAUT tabs & discovery features
  • feat: Added Discovery "My Teams" search
  • feat: Added new templates icons
  • refactor: Updated static tabs and manifests versions


  • doc: Updated technical documentation
  • fixed: Multi-crm configuration
  • improvement: Multiple environments and roles mgmt
  • feat: Added bot status endpoint