Skip to main content

IntraVox - Releases

← App details

Nextcloud 34

IntraVox 1.6.0
Release Details
UpdatedJune 13, 2026, 11:59 a.m.
Changelog

Major release with three themes: Nextcloud 34 compatibility, community translations via Transifex, and admin-curated language activation. Plus PhotoStory lightbox fullscreen + "Open in Files" originally drafted for 1.5.6 are folded into this release. No data loss on upgrade — existing installs keep their four configured languages enabled by default.

Upgrade safety contract

This release respects seven rules so existing installs cannot break:

  1. No language folder is ever deleted automatically — not on toggle-off, not on upgrade, not by cleanup.
  2. Default for installs upgrading from 1.5.x is ["nl","en","de","fr"] — exactly the previous hardcoded set.
  3. The Version10600 migration only seeds the config key; it never creates or removes content folders.
  4. English cannot be disabled — it is the guaranteed fallback for every code path.
  5. License page-counts stay per-language and are not reset when a language is toggled.
  6. Cache invalidation runs automatically when the admin changes the enabled set.
  7. occ upgrade from 1.5.x → 1.6.0 produces zero user-visible changes (until the admin acts).

Added

  • Nextcloud 34 compatibility declaredinfo.xml now ships <nextcloud min-version="32" max-version="34"/>. Audit results: zero removed-in-NC34 OCP PHP APIs referenced in lib/; all five OC.* JS globals IntraVox uses (OC.dialogs.filepicker, OC.MimeType.getIconUrl, OC.L10N.translate, OC.requestToken, OC.webroot) remain functional in NC34 stable (deprecated, scheduled for migration in 1.7); bundled @nextcloud/vue (9.8.1) and Vue (3.5.22) match NC34's ship versions; PHP >=8.2 matches NC34's >=8.2 <8.6 requirement.
  • Transifex-ready translation pipeline — IntraVox is now packaged for community translations via Nextcloud's Transifex pool (o:nextcloud:p:nextcloud:r:intravox). New .tx/config + .l10nignore + l10n/.gitkeep + committed POT template enable the Nextcloud l10n sync-bot to open pull requests with new translations as they land. Resource provisioning requested via docker-ci#951. The four existing languages (NL/EN/DE/FR) continue to ship in l10n/*.json until the resource is online.
  • Admin-curated language list — new "Available languages" section at the top of the Demo Data tab in admin settings. Each language IntraVox ships a translation for appears as a checkbox; the admin ticks which ones should be active in the intranet. Disabled languages disappear from IntraVox menus, navigation, and the demo-data table, but all their content stays on disk and reappears the moment the language is re-enabled. English is always enabled and cannot be unticked.
  • Empty homepage on language activation — when an admin enables a new language (one without bundled full-intranet demo data), IntraVox creates an empty homepage in the content folder so the language is immediately usable. Idempotent: never overwrites existing content.
  • New LanguageService, LanguageController, LanguageHomepageService under OCA\IntraVox\Service\* and OCA\IntraVox\Controller\* — the single source of truth for "what languages are shipped" (auto-discovered from l10n/*.json) versus "what languages are active" (admin-controlled, persisted in oc_appconfig.intravox.enabled_languages).
  • PhotoStory lightbox: "Open in Files" button in the lightbox topbar, plus a clickable filename in the details panel. Both open the photo's parent folder in the Files app in a new tab. A new server-side endpoint /api/photo-story/open-in-files?file_id=N resolves the user-relative parent path (including federated/GroupFolder mountpoints) and 302-redirects to the Files view — the API's path field is storage-internal, so building the URL client-side would 404 on those mounts.
  • PhotoStory lightbox: swipe-down-to-close on mobile — vertical swipe over 100px closes the lightbox, alongside the existing horizontal swipe for prev/next.

Changed

  • All hardcoded SUPPORTED_LANGUAGES constants replaced — 12 services that each defined their own copy of ['nl','en','de','fr'] (PageService, DemoDataService, LicenseService, NavigationService, SetupService, FooterService, SystemFileService, FeedService, OrphanedDataService, ExportService, PagePathHelper, plus 2 OCC commands) now read from the central LanguageService. License page-counts only enumerate enabled languages; RSS feeds only include enabled languages; the orphaned-data scan recognises any language that's ever been shipped or enabled so it can never accidentally flag legitimate content as orphaned.
  • Navigation fallback unified on EnglishNavigationService::getCurrentLanguage() used to fall back to 'nl' for unknown user-locales. It now falls back to the universal English default, matching the rest of the codebase and the Transifex source-of-truth.
  • SetupService upgrade migrations now language-awaremigrateResourcesFolders(), migrateTemplatesFolders(), and migrateVersioningFolders() now iterate over admin-enabled languages and skip language folders that don't already exist on disk. The result: occ upgrade from 1.5.x → 1.6.0 touches exactly the four folders the install already had, never creates phantom folders for new Transifex-discovered languages.
  • Demo Data tab filters by enabled languages — only ticked languages appear in the install-status table. The "Full intranet" content option remains bundled for NL+EN only; other enabled languages show "Homepage only" and use the empty-homepage flow.
  • POT generation uses Nextcloud's official translationtool.pharscripts/generate-pot.js is now a thin Node wrapper around the same binary the sync-bot runs (create-pot-files task). Zero drift between local extraction and what Transifex sees. Replaces a custom en.json-based extractor that produced inflated POTs containing ~820 stale msgids the bot would have stripped anyway.
  • Plural-form overrides for JA/KO/ZH/TH/VI/ID (1 form), FR/PT (n > 1), PL/RU/UK/CS/SK (3 Slavic forms), SL (4 forms), AR (6 forms) — ported from IntroVox's regenerate_js_translations.py so non-Germanic languages render correctly when their pluralForm field is absent. Without these overrides Asian and Slavic translations rendered with the wrong plural rule.

Fixed

  • PhotoStory lightbox: Nextcloud header overlapped the topbar — the lightbox sat at z-index: 100000 but the NC header (z-index 2000) stayed visible because parent containers create stacking contexts (transforms/filters) that trap position: fixed children. Wrapping the template in <Teleport to="body"> escapes the trapped context; the lightbox now genuinely covers the full viewport.
  • PhotoStory lightbox: date/location pill unreadable against light photos — the translucent pill background disappeared against bright photos (white walls, snow, paper). Darker background, stronger backdrop-blur with saturation, subtle border, heavier drop-shadow, plus a text-shadow fallback for browsers without backdrop-filter.
  • PhotoStory lightbox: body scroll-lock on open — the page underneath could be scrolled with the trackpad while the lightbox was open. body.style.overflow = 'hidden' is now applied on open and restored on close.
  • PhotoStory lightbox: iOS notch / Android status bar in fullscreen — topbar now uses env(safe-area-inset-*) padding so the close button doesn't hide behind the notch.

Removed

  • Stray l10n/*.po files — replaced by the canonical Transifex output path translationfiles/<lang>/intravox.po. The PO files in l10n/ were never used by the Nextcloud runtime (which reads .js + .json) and only created dual-source confusion. Bundled translations remain in l10n/{nl,en,de,fr}.json until Transifex onboarding completes.
  • PageService::SUPPORTED_LANGUAGES constant — and 11 sibling constants across the service layer. All logic now routes through LanguageService.

Internal

  • New migration Version001600Date20260609000000 — pure config-init, seeds intravox.enabled_languages with the legacy default on first upgrade. Idempotent.
  • PagePathHelper stays a pure helper — its language-code set is static-class state synchronised once per request from Application::boot(). Avoids piping LanguageService through every caller of a previously side-effect-free helper.
  • AdminSettings initial state expanded — admin UI receives availableLanguages, enabledLanguageCodes, and defaultLanguage server-side, no separate fetch needed on tab open.
  • RELEASE_CHECKLIST.md rewritten with the full Transifex pipeline diagram and two adopted IntroVox v1.7.1 gotchas (GitHub-bot divergence, near-empty-language conflict resolution) so the next release doesn't repeat IntroVox's mistakes.
  • scripts/generate-pot.js rewritten as wrapper around translationtool.phar (downloaded + cached under scripts/.cache/ for 7 days).

Notes

  • The first Transifex sync PR will land only after a Nextcloud team member provisions o:nextcloud:p:nextcloud:r:intravox on the Transifex server. A GitHub issue on nextcloud/docker-ci requests this. Until then, translation files remain manually maintained for NL/EN/DE/FR.
  • Disabled-language pages don't count toward the free-tier 50-pages-per-language limit. This is the intended behaviour: organisations get back unused-language capacity once they curate the list. Re-enabling a language re-counts.
  • The bundled LANGUAGE_META map in DemoDataService still hardcodes display names and the "has full intranet demo" flag for NL/EN/DE/FR. New Transifex-shipped languages will appear in the admin UI with their base code as the name (e.g. "es") until they're added to the meta map. Cosmetic-only; activation and content management work either way.
  • Cosmetic legacy still in code: five OC.* JavaScript globals (deprecated since NC 26-30) — migration to @nextcloud/* equivalents is planned for 1.7. Works on NC32-34 today, may break on NC35 if Nextcloud removes them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTf7ZtlGWgI9TvkiQXT6xXf2fHFVS7KIq4LEB/evxDo4c/+mV4vL14flkwjF+dH6wtwnwbgjdFXGW3YPGcpWb5EU/ulDXwplwsPL3M+JxJGOgUtVR3DpMufuel27aggb9QKJeV1MGmlqyZivWUn9PgHtHciWghT1F2Xab3ui7YSFtC0UYlZm94f1J54payg2/5eQWZBr2odtZ0yIUc8IlIlYaYApDWcMr0NX52EX9DRFE33G0SqpB9L06WDu2BRxbesistv1KNp0IN6CDajkrs9dNPe0O6IIPW+9Ryo4oO2xjAzKKfwu+84egH611IkMhheumimFL7zeQZ3GE2VDQC26A/fE0S8Xo+uoHF63NliWIZvtvKPCDecHsVozYGoLm9Tdu3R+V1vNRgy8OeNg6VF1qNAup+YN6WFOxw+ftpKe526KCNHETQOdwp7JqEU4I0miYRJdo8GT6nEOC/MD4eBNsMLUxubt4iH1emd/PzvGPmUppF+iCudLzUCPYHG2xMyTDQprnW0hoBlb/9BCD3csE6lQwqwFsbzX+ITzd5PoMWbHX7Cy7AKQ6Izc3F2ZfAUrCVcoqFwAEiH3c/7RGRCXPxvQ2H50m9vKk8pn7gW8Lo5zu4E+66QaHUjUueLzeQd0AmHfCDdgbicqev0xrWwhk6wQsCLilRmLrpVdy7sw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0

Nextcloud 33

IntraVox 1.6.0
Release Details
UpdatedJune 13, 2026, 11:59 a.m.
Changelog

Major release with three themes: Nextcloud 34 compatibility, community translations via Transifex, and admin-curated language activation. Plus PhotoStory lightbox fullscreen + "Open in Files" originally drafted for 1.5.6 are folded into this release. No data loss on upgrade — existing installs keep their four configured languages enabled by default.

Upgrade safety contract

This release respects seven rules so existing installs cannot break:

  1. No language folder is ever deleted automatically — not on toggle-off, not on upgrade, not by cleanup.
  2. Default for installs upgrading from 1.5.x is ["nl","en","de","fr"] — exactly the previous hardcoded set.
  3. The Version10600 migration only seeds the config key; it never creates or removes content folders.
  4. English cannot be disabled — it is the guaranteed fallback for every code path.
  5. License page-counts stay per-language and are not reset when a language is toggled.
  6. Cache invalidation runs automatically when the admin changes the enabled set.
  7. occ upgrade from 1.5.x → 1.6.0 produces zero user-visible changes (until the admin acts).

Added

  • Nextcloud 34 compatibility declaredinfo.xml now ships <nextcloud min-version="32" max-version="34"/>. Audit results: zero removed-in-NC34 OCP PHP APIs referenced in lib/; all five OC.* JS globals IntraVox uses (OC.dialogs.filepicker, OC.MimeType.getIconUrl, OC.L10N.translate, OC.requestToken, OC.webroot) remain functional in NC34 stable (deprecated, scheduled for migration in 1.7); bundled @nextcloud/vue (9.8.1) and Vue (3.5.22) match NC34's ship versions; PHP >=8.2 matches NC34's >=8.2 <8.6 requirement.
  • Transifex-ready translation pipeline — IntraVox is now packaged for community translations via Nextcloud's Transifex pool (o:nextcloud:p:nextcloud:r:intravox). New .tx/config + .l10nignore + l10n/.gitkeep + committed POT template enable the Nextcloud l10n sync-bot to open pull requests with new translations as they land. Resource provisioning requested via docker-ci#951. The four existing languages (NL/EN/DE/FR) continue to ship in l10n/*.json until the resource is online.
  • Admin-curated language list — new "Available languages" section at the top of the Demo Data tab in admin settings. Each language IntraVox ships a translation for appears as a checkbox; the admin ticks which ones should be active in the intranet. Disabled languages disappear from IntraVox menus, navigation, and the demo-data table, but all their content stays on disk and reappears the moment the language is re-enabled. English is always enabled and cannot be unticked.
  • Empty homepage on language activation — when an admin enables a new language (one without bundled full-intranet demo data), IntraVox creates an empty homepage in the content folder so the language is immediately usable. Idempotent: never overwrites existing content.
  • New LanguageService, LanguageController, LanguageHomepageService under OCA\IntraVox\Service\* and OCA\IntraVox\Controller\* — the single source of truth for "what languages are shipped" (auto-discovered from l10n/*.json) versus "what languages are active" (admin-controlled, persisted in oc_appconfig.intravox.enabled_languages).
  • PhotoStory lightbox: "Open in Files" button in the lightbox topbar, plus a clickable filename in the details panel. Both open the photo's parent folder in the Files app in a new tab. A new server-side endpoint /api/photo-story/open-in-files?file_id=N resolves the user-relative parent path (including federated/GroupFolder mountpoints) and 302-redirects to the Files view — the API's path field is storage-internal, so building the URL client-side would 404 on those mounts.
  • PhotoStory lightbox: swipe-down-to-close on mobile — vertical swipe over 100px closes the lightbox, alongside the existing horizontal swipe for prev/next.

Changed

  • All hardcoded SUPPORTED_LANGUAGES constants replaced — 12 services that each defined their own copy of ['nl','en','de','fr'] (PageService, DemoDataService, LicenseService, NavigationService, SetupService, FooterService, SystemFileService, FeedService, OrphanedDataService, ExportService, PagePathHelper, plus 2 OCC commands) now read from the central LanguageService. License page-counts only enumerate enabled languages; RSS feeds only include enabled languages; the orphaned-data scan recognises any language that's ever been shipped or enabled so it can never accidentally flag legitimate content as orphaned.
  • Navigation fallback unified on EnglishNavigationService::getCurrentLanguage() used to fall back to 'nl' for unknown user-locales. It now falls back to the universal English default, matching the rest of the codebase and the Transifex source-of-truth.
  • SetupService upgrade migrations now language-awaremigrateResourcesFolders(), migrateTemplatesFolders(), and migrateVersioningFolders() now iterate over admin-enabled languages and skip language folders that don't already exist on disk. The result: occ upgrade from 1.5.x → 1.6.0 touches exactly the four folders the install already had, never creates phantom folders for new Transifex-discovered languages.
  • Demo Data tab filters by enabled languages — only ticked languages appear in the install-status table. The "Full intranet" content option remains bundled for NL+EN only; other enabled languages show "Homepage only" and use the empty-homepage flow.
  • POT generation uses Nextcloud's official translationtool.pharscripts/generate-pot.js is now a thin Node wrapper around the same binary the sync-bot runs (create-pot-files task). Zero drift between local extraction and what Transifex sees. Replaces a custom en.json-based extractor that produced inflated POTs containing ~820 stale msgids the bot would have stripped anyway.
  • Plural-form overrides for JA/KO/ZH/TH/VI/ID (1 form), FR/PT (n > 1), PL/RU/UK/CS/SK (3 Slavic forms), SL (4 forms), AR (6 forms) — ported from IntroVox's regenerate_js_translations.py so non-Germanic languages render correctly when their pluralForm field is absent. Without these overrides Asian and Slavic translations rendered with the wrong plural rule.

Fixed

  • PhotoStory lightbox: Nextcloud header overlapped the topbar — the lightbox sat at z-index: 100000 but the NC header (z-index 2000) stayed visible because parent containers create stacking contexts (transforms/filters) that trap position: fixed children. Wrapping the template in <Teleport to="body"> escapes the trapped context; the lightbox now genuinely covers the full viewport.
  • PhotoStory lightbox: date/location pill unreadable against light photos — the translucent pill background disappeared against bright photos (white walls, snow, paper). Darker background, stronger backdrop-blur with saturation, subtle border, heavier drop-shadow, plus a text-shadow fallback for browsers without backdrop-filter.
  • PhotoStory lightbox: body scroll-lock on open — the page underneath could be scrolled with the trackpad while the lightbox was open. body.style.overflow = 'hidden' is now applied on open and restored on close.
  • PhotoStory lightbox: iOS notch / Android status bar in fullscreen — topbar now uses env(safe-area-inset-*) padding so the close button doesn't hide behind the notch.

Removed

  • Stray l10n/*.po files — replaced by the canonical Transifex output path translationfiles/<lang>/intravox.po. The PO files in l10n/ were never used by the Nextcloud runtime (which reads .js + .json) and only created dual-source confusion. Bundled translations remain in l10n/{nl,en,de,fr}.json until Transifex onboarding completes.
  • PageService::SUPPORTED_LANGUAGES constant — and 11 sibling constants across the service layer. All logic now routes through LanguageService.

Internal

  • New migration Version001600Date20260609000000 — pure config-init, seeds intravox.enabled_languages with the legacy default on first upgrade. Idempotent.
  • PagePathHelper stays a pure helper — its language-code set is static-class state synchronised once per request from Application::boot(). Avoids piping LanguageService through every caller of a previously side-effect-free helper.
  • AdminSettings initial state expanded — admin UI receives availableLanguages, enabledLanguageCodes, and defaultLanguage server-side, no separate fetch needed on tab open.
  • RELEASE_CHECKLIST.md rewritten with the full Transifex pipeline diagram and two adopted IntroVox v1.7.1 gotchas (GitHub-bot divergence, near-empty-language conflict resolution) so the next release doesn't repeat IntroVox's mistakes.
  • scripts/generate-pot.js rewritten as wrapper around translationtool.phar (downloaded + cached under scripts/.cache/ for 7 days).

Notes

  • The first Transifex sync PR will land only after a Nextcloud team member provisions o:nextcloud:p:nextcloud:r:intravox on the Transifex server. A GitHub issue on nextcloud/docker-ci requests this. Until then, translation files remain manually maintained for NL/EN/DE/FR.
  • Disabled-language pages don't count toward the free-tier 50-pages-per-language limit. This is the intended behaviour: organisations get back unused-language capacity once they curate the list. Re-enabling a language re-counts.
  • The bundled LANGUAGE_META map in DemoDataService still hardcodes display names and the "has full intranet demo" flag for NL/EN/DE/FR. New Transifex-shipped languages will appear in the admin UI with their base code as the name (e.g. "es") until they're added to the meta map. Cosmetic-only; activation and content management work either way.
  • Cosmetic legacy still in code: five OC.* JavaScript globals (deprecated since NC 26-30) — migration to @nextcloud/* equivalents is planned for 1.7. Works on NC32-34 today, may break on NC35 if Nextcloud removes them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTf7ZtlGWgI9TvkiQXT6xXf2fHFVS7KIq4LEB/evxDo4c/+mV4vL14flkwjF+dH6wtwnwbgjdFXGW3YPGcpWb5EU/ulDXwplwsPL3M+JxJGOgUtVR3DpMufuel27aggb9QKJeV1MGmlqyZivWUn9PgHtHciWghT1F2Xab3ui7YSFtC0UYlZm94f1J54payg2/5eQWZBr2odtZ0yIUc8IlIlYaYApDWcMr0NX52EX9DRFE33G0SqpB9L06WDu2BRxbesistv1KNp0IN6CDajkrs9dNPe0O6IIPW+9Ryo4oO2xjAzKKfwu+84egH611IkMhheumimFL7zeQZ3GE2VDQC26A/fE0S8Xo+uoHF63NliWIZvtvKPCDecHsVozYGoLm9Tdu3R+V1vNRgy8OeNg6VF1qNAup+YN6WFOxw+ftpKe526KCNHETQOdwp7JqEU4I0miYRJdo8GT6nEOC/MD4eBNsMLUxubt4iH1emd/PzvGPmUppF+iCudLzUCPYHG2xMyTDQprnW0hoBlb/9BCD3csE6lQwqwFsbzX+ITzd5PoMWbHX7Cy7AKQ6Izc3F2ZfAUrCVcoqFwAEiH3c/7RGRCXPxvQ2H50m9vKk8pn7gW8Lo5zu4E+66QaHUjUueLzeQd0AmHfCDdgbicqev0xrWwhk6wQsCLilRmLrpVdy7sw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.5
Release Details
UpdatedMay 30, 2026, 8:59 p.m.
Changelog

Patch release that fixes #57: clicking-save on a Link widget item whose URL is mailto:, tel:, or sms: would silently empty the URL on save. After page refresh the link rendered as #. No DB migration, no API breaking changes.

Fixed

  • Link widget: mailto:, tel:, and sms: URLs were stripped on save (#57) — Service\Sanitize\UrlSanitizer::sanitize() only allowed http(s)://, root-relative paths, and # anchors. Any other scheme — including the universally-accepted communication shortcuts mailto/tel/sms — was rewritten to an empty string at save time. The widget then rendered href="#" after a page refresh, even though the in-memory edit showed the correct URL until then. The Navigation editor used a different sanitization path (FILTER_SANITIZE_URL without the scheme allowlist) which is why mailto links worked there but not in Link widgets. Allowlist extended to include mailto:, tel:, sms: — three schemes with no JavaScript execution path, part of the default allowlist of DOMPurify and HTMLPurifier. javascript:, data:, file:, xmpp:, matrix:, and bare domains remain blocked. New unit tests cover both the accept and the continued-reject cases.

Notes

  • Existing Link widgets that lost their mailto/tel/sms URL still need to be re-edited and saved once — the empty value is persisted on disk. There is no automatic migration; once saved with 1.5.5 the URLs stick.
  • xmpp: and matrix: remain blocked. They are safe in principle (no JS execution) but unlikely to be intentional in most intranets; add per-need with an explicit code review if you want them. Open an issue if your installation needs them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCh/CmZ8aQnDr2XuBCui2CiOFzzX9RnHEHBISRDwUZISNfh8j+W8l9zbtlV5dsZ2tjgpT9EfMQCcK0O7Rms0xrEl7tGFWeGB4+3Nr6RlfhR59CFDtiXB1eg/mHhFR5uJBOB8CMhhhCTnN/dkD1np0PCRFJjDbn3lmij92xMOLMwFsaPAvhvRFA1wHn0cy+hUl5ZQyFDHivA7OLdadsh+eMth/Z0WaZJXvHuoWqbUFpGOMGzRmeeIYubZj5NsVslZg6gL93XSul9y5Jllh6IsMCcEwMLdhA3N+G9rLF9QzKUjev3aV1OzH+vVyY6LAhRYTN7k3bAZLOEt7HhuwA5f2bgEPbbjzNgW867foQA8HpAHeczfKSjbWiCOPCFhJ7q0OCIsAf9RJzCXHLUsBbSIDuxQyH35rd0sRL1qmg7hSikMBCs4G2d4/ajzZo34WA5k+R4WFmqhsJiMAm0By5ENBs9dVkAS+E6hxJruM9W/BevyftUjV/guD8YfLy1yByTuUICpA13pnJjo0rxFZmv6Iyo2uwDFZUVzag4RfLok80mXSY6icuKLWsH6mdX+7WaoT1n0v5NqFT38v7dVGG/DWZpF/edJSW5koAJMcr0gHTJ6h0wJzXFf+vx+1XOkJ/1184HStnxv9W9CabTkxRybcwHPwH7AtdH/GytDDG4qVi0k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.4
Release Details
UpdatedMay 30, 2026, 1:53 p.m.
Changelog

Patch release that closes an information disclosure issue introduced by 1.5.3.1, fixes a Leaflet/sticky-topbar layering bug, and brings the bundled @nextcloud/vue in line with what Nextcloud 33 itself ships so IntraVox widgets visually match NC's own apps again. No DB migration, no API breaking changes.

Security

  • FileStory / PhotoStory: source folder path leaked to users without access — 1.5.3.1 added a "You do not have access to this folder" empty-state that showed the configured folder path (e.g. Shalution/Administratie/2026) as context. For a user who is deliberately excluded from that folder, this disclosed the existence and naming of paths they shouldn't be aware of — path names can carry sensitive context (client names, project codes, person names, dated boundaries). The empty-state now renders a minimal lock icon + "You do not have access to this widget" with no folder name and no scan hint. The folder path remains visible only for users who do have access but happen to see an empty result (legitimate context).

Fixed

  • PhotoStory: Leaflet map overlapped the sticky IntraVox topbar on scrollPhotoStoryMap.vue and PhotoStoryDayMap.vue had position: relative with no z-index, so Leaflet's internal panes (default z-index 200–700) rendered over .intravox-topbar (z-index 100) when the page scrolled past the map. Both map containers now establish their own stacking context with position: relative; z-index: 0; isolation: isolate;, capping the Leaflet panes below the topbar without touching Leaflet's own z-index conventions.
  • PageDetailsSidebar tabs visually diverged from NC Files — IntraVox bundled @nextcloud/vue 9.5, while NC 33 ships 9.6+ with a refreshed sidebar-tab look. The result was a different (often "double-underline" feeling) active-tab rendering versus what users see in NC's own Files sidebar. Bumped the bundled @nextcloud/vue to ^9.6.0 (resolved to 9.8.1) so PageDetailsSidebar now renders identically to NC's own sidebar tabs.

Changed

  • Bundled @nextcloud/vue upgraded from 9.5.0 → 9.8.1 (within ^9.6.0 range, matching the version NC 33 itself bundles). No public IntraVox API changes; some Nc* components may have minor visual refinements that come along with the upgrade.

Removed

  • Obsolete .app-sidebar-tabs__nav border-bottom override — the 1.5.1-era CSS workaround in css/main.css was meant to fix a double-underline on NcAppSidebarTabs in NC 32+. With the @nextcloud/vue 9.6+ refresh that override became counter-productive (it removed the hairline that NC's new active-tab rendering visually anchors against, producing the misaligned look reported on 1.5.4-rc). The override has been removed; the look is now exactly what NC Files renders.

Internal

  • RELEASE_CHECKLIST: new section 1b "Dependency parity with Nextcloud core" — codifies the lesson from this release. Before tagging, check node_modules/@nextcloud/vue/package.json against the version NC ships for the target NC min-version (table maintained in the checklist). Visual canary: PageDetailsSidebar tabs vs. NC Files sidebar.

Notes

  • The defensive backend guard PhotoStoryService::assertNotResolvedToUserRoot() added in 1.5.3.1 stays in place. It already returns reason: 'folder_not_accessible' on the 404 response which the new empty-state branches on.
  • Known follow-up: News widget's empty-state still shows Source: {path} for unauthorised users. Same pattern, lower severity (source is usually a page-id, not a filesystem path); tracked separately.
  • Future direction: SharePoint-style audience targeting per widget will eventually let admins hide widgets entirely from users who shouldn't see them. The lock-state introduced here is the fallback for the edge-case where audience-target users lose folder permissions after configuration.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturebdeRHVR20/nH1R+zH2h19G2oU3imUS1G7ErSfoE76L06c1ZdJWAxX3IRoU0uXXw6g1riRPttaiwpkXuype8kPK/9mDqdXZT0WKUtYqSV+dkBjdpe1ODKCrXZhR4WZsDfGpuvzA68HeCYLTk5Zb9LgSwZIcwBfLDaAKK+DzgBuosLV/WepscTkKBAtjb0jOGyfYRQQRXScO4ywNS4Ke9kzTkvqpqlSgStQ8yMVer6cwb7/ToxjGhMSeUy7w0IKS69K2usogY79m28XVmLpaUp/5ky0BxA1+ggtv8Z9tdLCxy+G3S59ndDIXqgCXT6G1eShRFP7PuoQg3rJZK2rhM6hn2oOFX3ZUHDVE9hxpA2Iv67B3u1alq5ZYdmbtppwCFyFmUuOl5juZLHAZc5MG4T0USxIdgorxh2A2rBmuGAdrQk3vJlby8G+apL/hhFaZoUeBi1i7wFS1f62ucSJUKO6IAfAYJUxBDkIVFNboaZeRI30hPAa2yJGbYgAq2vuDuj1eGpewDQ65SNvaitI0LBjj0IQiPYs3DdnLVXDOqpva+VhaiQnA8Iq8TFK55tMyQiCn6QFNWCfTApT6L3W7X1j1GsiMutzjSS3GLLt27SeB/8948hXeR1JqcCLmiqaYt9C5KsbFH/UiMq6AGTungHCm4mxz1jSaGEAXBpsPlAqb4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.3
Release Details
UpdatedMay 30, 2026, 11:35 a.m.
Changelog

Patch release that fixes a "file no longer exists" toast when clicking documents in FileStory, and makes click-to-open behaviour consistent across all mount types. No DB migration, no API breaking changes.

Fixed

  • FileStory: "file no longer exists" toast on click for legacy shared-storage GroupFoldersFileStoryWidget.openFile() preferred OCA.Viewer.open({path}) for inline preview, deriving the path from file.path by stripping a leading files/. That works for personal storage and per-folder jail GroupFolders, but in legacy shared-storage GroupFolders the cache row stores __groupfolders/<id>/... and the user-visible mount-point name (e.g. Shalution) isn't carried on the row. The Viewer received /__groupfolders/4/Administratie/2026/Boekhouding.xlsx, couldn't resolve it against the user's tree, and NC raised the "file no longer exists" toast. Federated shares hit a similar dead-end via a different code path.
  • FileStory click behaviour now consistent across mount types — documents always open in a new tab via NC's /f/<id> handler, which resolves the right mount server-side for personal storage, both GroupFolders mount strategies, internal shares and federated shares. Removed the path-derivation entirely (resolveDisplayPath() deleted).

Notes

  • Behaviour change: clicking a document in FileStory no longer opens the inline NC Viewer overlay — every click now opens a new tab at the file's NC Files location. This trades inline-preview ergonomics for "actually works on every mount type" reliability.
  • PhotoStory is unaffected; its widget uses an internal Lightbox component and never touched OCA.Viewer.open().
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureAJvUlLcI5LNjLuz5DDx6QDyCAMh6j7PTBvzanLh5i26TsW2mHudGF/mCkxku08w9eJvE8ZY0VKFEzkLbbBc0v16RHQ1YO0slEGvbTv6QdrECl8JdmGwU0oDHpWAKlrGOeKRO0b9oDSu7D+Z1mVGlhxxMexJAnpugWDkevjeI1aznx0Di8FNa5KMxT9apIvceQfuHPbBOBPnE2BgjJMQTBWwR0sel8DYmdcd4y5FVKwY/3TlcTqzNLKwujDpqPt4Ihu4GVjS/dltaJqhSVlKJCiyh/w+kmB/RujnoEwLVru+GNhfgggvtr+YbQrwxoCqsoP1xiHeNoIA60/VCINwB0NkZHxXkrjGuTG7lInhzhEgwbl5sDg1JpG3BfQv1Z4R9VIHDXhCxyJT6oH7WbrssaUI0RlZQ2amYMu7a+FBe4+wHau4vD/KkvfOj62YZ6jPksvS140seB7IMYw9gxsw45bjjFS0COXGeIado8437PU17MBvwVGshcQHwdkwSyGTl3HWvXeQ5i4Gt9TiYTjjfmU4KFk83X8PcwB4qYho0yHLsMTZpdEApYTmLMkCrIKkJSk/mKnUQdiLkNnCjCTvZI1YvajTqzZxlNFy7IudFrvP6lyGosRum7OSdCACTQGSauuRMw7bB+J5x6aME6islckUuqmc9vxce92r6/brSurs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.2
Release Details
UpdatedMay 28, 2026, 5:52 p.m.
Changelog

Patch release with two production-blocking PhotoStory fixes (groupfolder albums and federated-file thumbnails), three UX improvements requested from real use, and one admin-tool clarification. No DB migration, no API breaking changes.

Fixed

  • PhotoStory shows "No photos found" for every groupfolder albumPhotoStoryService::extractStorageAndPath() returned the jailed Node path (e.g. Albums/Doris Synchroonzwemmen) while oc_filecache.path stores the unjailed form (__groupfolders/7/Albums/Doris Synchroonzwemmen or files/Albums/Doris Synchroonzwemmen, depending on which mount strategy the groupfolder uses). The SQL path LIKE predicate matched zero rows, the widget rendered its empty state, and the hint text misleadingly pointed admins at occ files:scan — even though the files were already indexed. The path is now reconstructed by walking the cache wrapper chain for the first CacheJail::getGetUnjailedRoot(), which covers both groupfolder mount layouts as well as any other jailed mount (federated, encryption-wrapped). Root-mode / enumeration also benefits — separate groupfolder mounts no longer collapse into the personal-storage scope.
  • PhotoStory/FileStory tile previews missing for federated files — NC's /core/preview returns 404 for any file on a Files_Sharing\External\Storage mount: the preview providers (Image, Office, PDF) need a local file path or a Collabora/LibreOffice render, and federated files only exist on the remote NC's disk. Result: PDFs, docx, xlsx and even jpg tiles from an OCM share rendered as a generic mime-icon instead of a thumbnail. New shared PreviewController at GET /api/preview?file_id=N&x=400&y=400 closes the gap: local files 302-redirect to /core/preview (no overhead, NC's own preview cache stays hot); federated files are handled by the new FederatedPreviewService which calls the owner instance's /index.php/apps/files_sharing/publicpreview/{token} endpoint and caches the result in appdata/intravox/federated-preview/ keyed by {fileId}-{etag}-{x}-{y}. Cold response ~250–400 ms (~5–15 KB transfer per file, not the file body), warm ~180 ms.

    Three protection layers stack to keep this scalable and friendly to the remote: a per-user rate throttle (UserRateThrottle(600/min)) bounds individual misuse; in-flight deduplication via NC's distributed cache ensures that 50 users opening the same uncached tile at once produce a single outbound HTTPS call (49 wait for the cache to materialise, then read); a per-remote concurrency semaphore (default 8 simultaneous outbound calls per remote host) prevents an IntraVox-server from saturating one owner instance and tripping its IP-throttle. When the cap is hit the request degrades gracefully to the mime-icon fallback. A companion POST /api/preview/warmup endpoint pre-warms up to 16 federated tiles per call; PhotoStoryWidget and FileStoryWidget call it fire-and-forget after every paged fetch so most tiles are already warm by the time the user scrolls into view. Bandwidth scales with viewed files, not with corpus size — fine on 1M-file federated mounts.

Added

  • PhotoStory: hide RAW sidecars when a JPG/HEIC variant exists — DSLRs and mirrorless cameras in "RAW + JPG" mode write two files per shot (IMG_5432.CR2 + IMG_5432.JPG) that show up as visual duplicates in any folder view. New hideRawDuplicates widget option (default on) groups files by (parent_dir, basename-without-extension) and prefers the browser-displayable variant over the RAW. Covers Canon (CR2/CR3), Nikon (NEF/NRW), Sony (ARW), Adobe (DNG), Fujifilm (RAF), Olympus (ORF), Panasonic (RW2), Pentax (PEF), Samsung (SRW) and Sigma (X3F). Implemented as over-fetch + dedup + slice so paginated infinite scroll stays correct; total continues to count physical files (honest source-of-truth for storage cost).
  • Sticky page navigation — header (title + Save/Edit) and navigation bar are now wrapped in a position: sticky; top: 0 topbar so they stay reachable on long pages. Previously a 300-photo Photo Story timeline forced you to scroll all the way back up to reach another page. Dropdowns/megamenus continue to position via getBoundingClientRect(), so their placement is unaffected.
  • Orphaned GroupFolder admin: show what's actually in the folder — the "Content" column used to render the literal "Unknown data" for non-IntraVox orphans, leaving admins to delete blind. OrphanedDataService::analyzeOrphanedFolder() now returns a sampleContents field with the first 8 top-level entries (name, type, size) sorted alphabetically, and the admin UI renders them as a small listing under the badge. The empty-state label also changes from "Unknown data" to "Non-IntraVox data" for accuracy (#56).

Notes

  • The PhotoStory groupfolder fix activates on every groupfolder-hosted album with zero config — existing widgets pointing at a groupfolder path will start returning their photos immediately after upgrade.
  • The federated preview proxy degrades gracefully: if the owner instance can't produce a thumbnail (no Collabora/LibreOffice on their side, or the file format is unsupported there), the endpoint serves a 302 redirect to the matching mime-icon SVG. No broken-image placeholders.
  • hideRawDuplicates defaults to enabled also for existing widgets (the param is absent → backend reads its default). Users with RAW-only albums can untick the new editor checkbox.
  • No DB migration; widget configs are read back through the new optional field transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturemyEi+pL/zo6IBucOaSFT5mI0lcpEe1D/O6I6fF/yEeHWYWnAeylyogGH5pDKz1TFn0b5mhCXPr2bwZDXRq4gkW8dpXkLVDPC9ox3kX/7jwULrvSzXbn7okB18UC0eGDvG3O0VXrVPl0XMveQCjlZ3GYvSi3p2mukoN6vKYXJazEwnioFhh18W39wUZ+/rxQz5MnQKfaWnOBisrv1Js1z4TAOITDII1gSnMcJFFWKepzSaUQbXNjsAjieaV0qshjTM9JAPZiAOGIQEJH6mGM60LgvV9czXdd5g5StTDinr2zK7O/kHe0qia5Z2GjmN50KrLAsmff7nFS4P2qDTov4H8p7Kw+qEClC+Wm0F6p/E3yZ7XWc3KkwU8vk96gXuYJ8yF4zCswLx4YAwSS1QvuACxQBnC+fF42jh/wXJpPylbMrJqeKKY3Ql24TTzUkSX+ZMweoQ4qkb3BQRQPQY/9pyiQrxc/OvpMdicJkl2IGIIYPG/5pLhTEZEZCXtlVRMpcO9LKzLzU1e+Otddyz3DsyXBwcTawwWknmZPhhD7fvSYpQb6dp0pgjWjBnoI7+YCcMI4sKONQUYrTzwA6eCjYRCiAcW30bTsUG27xHGvHT2cTg/JnNfaeYPIEVvWE+qCXKPON39QL/SMPfSJPrCMOptTuW35mpF4A/w4AF+BCq8k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.1
Release Details
UpdatedMay 28, 2026, 10:58 a.m.
Changelog

Patch release that fixes legibility on themed page rows and tightens a handful of widget rough-edges that surfaced in production after 1.5.0. No new features, no API changes.

Fixed

  • PhotoStory/FileStory contrast on dark row backgrounds — filenames, day-headers and meta lines used --color-main-text (dark) regardless of the row's background colour. On Primary (--color-primary-element) rows that produced unreadable dark-on-dark text. Both widgets now accept rowBackgroundColor from the parent Widget.vue (closing a gap with the existing widgets that already consume it) and switch internal text + tile surfaces to a WCAG-paired colour set via two CSS variables (--fs-text/--ps-text + their muted siblings). Tile bodies become a tinted-glass card on dark rows instead of cutting a hard white rectangle through the coloured backdrop.
  • FileStory tile filenames invisible on dark rows — regression from the same root cause: tile bodies kept their --color-main-background (white) while inheriting the now-white filename colour. Tile surfaces, hover state, preview-fallback bg and mime-icon placeholder all lift to translucent white on fs--on-dark.
  • Folder-path "/" silently collapses to empty after savePageService::sanitizePath strips leading/trailing slashes, so a configured PhotoStory/FileStory folderPath = "/" (root) was persisted as "" and rendered as "no folder selected" after reload. New sanitizeFolderPath() wrapper preserves / (and \) as a meaningful "whole drive" marker before delegating to the generic sanitizer.
  • 502/503 during page save — entering edit mode after a FileStory widget existed triggered four expensive folder=/ queries within ~250 ms (the legacy debounce). Apache workers saturated on large libraries. FetchKey watcher debounce raised from 250 ms to 700 ms in both widgets.
  • NcAppSidebarTabs double underline (NC 32 regression)@nextcloud/vue 8.x renders both a 1 px hairline on the tab-strip wrapper and a 4 px coloured indicator on the active tab, producing a stacked double underline in the PageDetailsSidebar. Global override in css/main.css removes the redundant hairline; scoped Vue CSS couldn't reach the data-v--tagged third-party selector.
  • Photo previews missing for common web formatsPhotoStoryService::MEDIA_MIMES was narrower than what users actually drop into their photo folders. Now also includes webp, gif, svg+xml, bmp and video/webm.
  • Empty folder picker returning "" instead of / — NC's OC.dialogs.filepicker returns an empty string when the user picks the root; both editors now normalise that to "/" so the configured value matches the sanitizer's accepted shape.

Notes

  • Default-themed rows (transparent / --color-background-hover / --color-primary-element-light) are visually unchanged; the new contrast logic only activates on saturated row colours.
  • No DB migration. Existing PhotoStory/FileStory widget configs are read back through the new sanitizer transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJUDu14MZav9zDCdwASLwOt9QfZFE4mkGdJjWn05l54CySpeTxrouul/CjST66UGcUmHOIM4gNXCBgrEkSACF0vpv1XWOWu6/PWHUmTsoZWretFLxxA/OXlcO6h3/Q0gHqS9TnIAxFCk1fnHbHHD3hGgYAnISLj6gL6s4axrs+h0/JpIon1ZMloUFxt3759D8Oc+LAgV5kNtYIndBkwb1BM89kb3Ri8NfCzZo3+5wo688lAty1cWjjqkOhzoxw6ERPWxRlek4XXB+4V/9a3wY0/gPWXdHb7YlSOgQpS2KB2m+F/YW64NUfCGOdTE8m/jAvw4Mz/ZDWVhtEk8vFgI3P3Sn1n4WxjArYYE5bChuDHa3A+G2sHZAWQ+/FRUHqExcaoK+mRXQGavoih9WkwVS2Bk9bJ6lKAVFwZgkvgD8YuKwiT9xe3tIhaFceYx1OZq90s6xqijZ6Upm6uoNZO8zwY28LwMJpxlOxqy0lyXVbhKQMb5cU9M80S2kmXbWCHJ1Tech4ZMpTdfZTP/MyoDtdqN9AczNCaMoxMRbW42x2FgNMDwBxszBV4q2mWa0LODiqo3X3AubXvJScBL62d3cWbHhGiEoiB4OJP99YlahBMOw8HoOebDrDYYCUnznz3Hh4GZoNFgWk+wtzrbR3Lu/TBimWHEkkYYQZAHr5mIWjsc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.0
Release Details
UpdatedMay 27, 2026, 8:57 p.m.
Changelog

Major release. Introduces two new widgets — Photo Story for photo galleries with EXIF, location maps and an Apple-style lightbox; File Story for document libraries with multi-mode layouts, MetaVox-aware filtering and federated-share awareness. Adds a fresh wave of perf, security, accessibility and l10n polish across the photo + file widget surface.

Added — Photo Story Widget

  • Four layout modes: Timeline (Magazine, Apple or Travelogue style), Highlights (auto-curated top photos), Grid (masonry), and On-this-day (year-over-year retrospective).
  • Lightbox with keyboard navigation (Arrow/Home/End/Esc/Space), slideshow mode with adjustable speed, focus-trap and focus-restore for screen readers, semi-transparent date/location pill that toggles a mini-map for geo-tagged photos.
  • OpenStreetMap integration via Leaflet: optional overview map per widget, per-day mini-maps in Timeline mode, and a cross-folder cluster endpoint for browsable map-driven storytelling. Admin-config aware (NC admin can disable all map features instance-wide).
  • EXIF metadata rendered into a details flyout (people, subjects, camera, location). Reads from NC core oc_files_metadata when populated; falls back to the bundled lsolesen/pel reader as a last resort with a per-request eager-EXIF cap.
  • MetaVox-driven filtering, grouping and sorting when the MetaVox app is installed. Supports cross-folder discovery mode (empty folder + ≥1 filter) for "all my photos tagged X across the instance".
  • Geocoding cache with periodic warmup job for fast country/location lookup on GPS-bearing photos.

Added — File Story Widget

  • Four layout modes: Timeline (per-day / per-month / per-year granularity), List (flat sortable), Tiles (visual grid with first-page previews and three configurable sizes: Small/Medium/Large), and Grouped (by file-type or MetaVox field).
  • Federated-share awareness — incoming OCM shares are detected per-file via a single indexed SQL join (oc_storages × oc_share_external). Federated rows render with a subtle cloud-badge and silently skip MetaVox-fetch since the remote NC has its own metadata database we cannot reach cross-instance. Mixed sources (local + federated under one root) keep full controls; pure-federated sources hide the MetaVox UI with an explanatory banner.
  • Configurable visible columns: Date, File size, Folder path. Date column can render either filesystem mtime or EXIF/MetaVox taken_at. Filename + file-type icon are always present.
  • MetaVox filter-builder, sort, group-by identical to Photo Story but adapted to document use-cases (e.g. group-by archief_categorie for compliance views).
  • Open-in-Files-viewer click target on every row/tile with role="button", Enter+Space keyboard activation and aria-label per item.

Added — Page editor & widget plumbing

  • Widget registration for Photo Story and File Story in the picker, with iconography and descriptive copy.
  • Editors for both widgets with folder picker (NC FilePicker dialog), live capability detection (MetaVox available?, source-federated?), sortable filter builder with type-aware operators (equals, contains, in, year_equals), and persisted widget config validated by PageService::sanitizeWidget.
  • REST API under /api/photo-story/* and /api/file-story/* covering paged listing, capabilities, MetaVox field discovery, location clusters, EXIF detail and range-aware video streaming (Photo Story only).

Performance

  • Paged enumeration via oc_filecache for all primary widget modes — no more full-tree getDirectoryListing() on large libraries. Hard caps (5000 cross-folder, 20k filtered, 200k count) prevent OOM on massive folders.
  • Federated detection is one preloaded SQL query per request, O(1) lookups per file. The previous IMountManager::findIn('/') per-file approach (cause of the 2026-05-27 saturation incident on nc-dev) is gone.
  • clusters, highlights and on-this-day endpoints now go through listPhotosPaged with sane caps instead of the unpaged legacy path that risked the same blast radius as the federated-detect outage.
  • filterFileIdsByScope collapsed from chunks × scopes SQL roundtrips to one ORed WHERE per chunk — at filtered-MetaVox-page scale this drops ~400 queries per page to ~40.
  • extractGroupfolderId memoised per node within a request.
  • Frontend AbortController on every fetch + fetchMore: rapid config changes no longer race stale responses overwriting fresh data, and pending requests cancel on widget unmount.

Security

  • Per-file ACL guard on the slice in MetaVox cross-folder hydration (buildPagedResponseViaMetaVox) using $userFolder->getById(). Bounded to ≤page-size lookups, so sub-folder ACLs inside groupfolders are honored.
  • Filter payload caps: 16 KB JSON pre-decode rejection on both controllers, value-length cap of 200 chars per filter, max 32 filters and 64 array values per filter — prevents pathological-input DoS.
  • Generic 500 messages on both controllers (no $e->getMessage() reaching client); folder-not-found mapped to clean 404 with empty-state payload instead of generic 500.

Accessibility (WCAG 2.1 AA)

  • Tiles, rows and hero elements: role="button", tabindex="0", Enter + Space activation, meaningful aria-label derived from caption/location.
  • Lightbox: focus-trap (Tab cycles within modal, no escape to background), focus-restore on close, counter announced via aria-live="polite", icon-only buttons get descriptive aria-label + aria-pressed where appropriate.
  • Editors: orphan <label> without for= converted to <div class="editor-label"> to avoid mis-association; form controls properly labelled.
  • Reduced motion: @media (prefers-reduced-motion: reduce) honored for Ken-Burns animation, pulse skeletons, and pill transitions.
  • Status regions: role="status" / role="alert" on loading, empty and error states; map-cluster list items keyboard-reachable; federated cloud-badge gets role="img" + aria-label.
  • Alt-text: meaningful (caption / location / numbered fallback) instead of filename for photos; decorative alt="" for tile previews where the parent already labels the action.

Internationalisation

  • Backend month/category labels now route through IL10N::t() (PhotoStoryService::localizedMonth, FileStoryController::extractGroupKey). No more hardcoded Dutch in API payloads.
  • Frontend date formatters use getCanonicalLocale() from @nextcloud/l10n everywhere — toLocaleDateString / toLocaleString / Intl.DateTimeFormat calls in PhotoStoryWidget, FileStoryWidget and PhotoLightbox no longer pin nl-NL.

UX polish

  • Retry button in the error-state of both widgets. Users recover from transient API failures without reloading the page.
  • Context-aware empty messages: distinguishes "no folder selected" / "no documents match current filters" / "folder is empty".
  • Transparent date headers in FileStoryWidget Timeline mode — replaces the opaque white sticky bar that clashed with themed/coloured rows. Count-badge uses color-mix(in srgb, var(--color-primary-element) 14%, transparent) for a subtle tinted chip that adapts to the active theme.

Developer-side hardening

  • scripts/check-import-consistency.js runs in prebuild: detects mixed sync/async imports of the same .vue component (the root cause of a runtime TypeError we hit on 2026-05-27) and fails the build before it ships.
  • scripts/auto-bump-dev.js auto-bumps the patch level on dev deploys so NC's md5(appVersion) cache-buster always changes — browsers never serve a stale bundle after a deploy.
  • Translation files (en/nl/de/fr) synced for all 122 new UI strings added by Photo Story + File Story.

Notes

  • No DB migrations required for the widget functionality itself; existing pages keep working.
  • PhotoStory federated-share awareness is on the roadmap but not yet implemented (single-storage photo libraries are the typical case). FileStory has the full federated-aware code path.
  • MetaVox cross-instance sync remains out of scope: NC core exposes no federation tokens or remote-file-id mapping. Roadmap item.

New Vue components: src/components/PhotoStoryWidget.vue, src/components/PhotoStoryWidgetEditor.vue, src/components/PhotoLightbox.vue, src/components/PhotoStoryMap.vue, src/components/PhotoStoryDayMap.vue, src/components/PhotoStoryFilterBuilder.vue, src/components/FileStoryWidget.vue, src/components/FileStoryWidgetEditor.vue.

Composer: lsolesen/pel added for the optional in-process EXIF reader.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureFLZvFbovK9mQvZvpGHVOIIcY1Wkokfi3grl/FTH48JoSlk35yZ49frh91/2T0Bda+dcFMO1aCpsNd694iEd26hCMp66F+QA8nqYMB0+WCiEUwlDSVT1x7S9MdLch+7LGPrm2A6h1MWsTQGV9pOIOjWtP4rPGv1+Mw+LFEva+CmFep5Kh/w/RaEqvn9LwcDzxx5JEzzme+nYZurAgV6146olp+xl0rCtxM/IPvL5JlZ7NchtiEc0udMvLroBfdOHKRU0aIJY7ZzVdjJJB46a911krwyn9jfcJmqGVrHZtNlp6uwpFKKlXo1fZDdnMsu/YxnVH5XTJOEflsQTB8GWntZa//R5zRRGXX0jj4o/dWNxvRMPD9jvCTO7Wq5oEvyorRcHVCJ70QatCHKNhOqXtq/vvywVZODt3BZk9gtQ5ssv9FFe7JB7zZWS69ZhHcTS9HqzV0UJ3SpSZfjXN0gsCdTlSi6hknGP9X4wvShSjV+DeHeBJoM4EZHVLSZiRjBWBYpqg0ffwj5X5U8VrXIFtIUHwUMXUJzl7Ta3Uwo4liP77h5AA2xInz+IxLAcpAP/ncaLtlrqCvm0PN1QRz3zq9IBaxE0VI7UDIn6S6ojzXQDWHTPaTPfS/e9v7WqPUB4t/o+6PyEulzq8TXq2jpmXcMsEDHQaRAJl5XT4W3h7TMM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.1
Release Details
UpdatedMay 20, 2026, 6:01 a.m.
Changelog

Patch release that resolves all open frontend security advisories flagged by GitHub Dependabot shortly after the v1.4.0 push. No functional or API changes — npm audit fix lifted eight vulnerable transitive packages to patched versions within their declared semver ranges, no package.json edits required. Build, PHPUnit (258/413) and dev-server smoke tests all green.

Fixed

  • axios → 1.16.1 — resolves 11 advisories (prototype pollution gadgets, CRLF injection, header injection, NO_PROXY/SSRF bypasses, DoS via deep toFormData recursion, streamed upload/response body-size bypasses, null-byte injection in URLSearchParams, XSRF token cross-origin leak)
  • dompurify → 3.4.5 — resolves four XSS bypasses (SAFE_FOR_TEMPLATES/RETURN_DOM, ADD_TAGS/FORBID_TAGS short-circuit and function-form, prototype-pollution via CUSTOM_ELEMENT_HANDLING)
  • fast-uri → 3.1.2 — path-traversal via percent-encoded dot segments + host-confusion via percent-encoded authority delimiters
  • fast-xml-builder / fast-xml-parser — XML comment/CDATA injection and attribute-value quote-bypass
  • brace-expansion → 5.0.6 — DoS via numeric range that defeated documented max protection
  • follow-redirects → 1.16.1 — custom auth-header leak on cross-domain redirects
  • postcss → 8.5.15 — XSS via unescaped </style> in CSS stringify output

After the bump npm audit reports zero vulnerabilities.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDc0e6XrFG/+dkBa2rqaitf3dwAEkyMJA/wqM2F2ZDIp+L9644GrNvZpexYR5xe/IEL4TR6gu1JHpUs2nqxnQ/Wgm8miJwi8+/9Jgg1bjc93k11siFiM8ca+ljWMlJ9Ai1UofzB8tdX2UqOPc1jzPMJwttj1+vYNBIrmD8Ypdubmnw6U3VDP/vSVwwR7I9O08D0DT/f6YGPRa4reXbqHRRllXRUgKXCXL0EWITQ1uwV/XoipV2U35G/BjFwOsQV370teRvY9aMarNl1j86d9N2O+cFMRokMVD/feZNeDXJ1jKh6UxOGPSuJZiQFEVdwMmyyH1MXYy3xh52ZI01G+je1GvGPwzpouTvZzDMYYdsNFepGZtNl1nDBH8THuNnEnMCyBxCPabrlNfBPH9GFdDSPjFptQjZ+ec3/UJHCIqAQHV2no41W5KEBCJTHGf/ex4tU3LIUGGZeTPGmdYCHvH4VNqqqHffL88FqFCKHNO6kWrqnHaFGNwfxsM5uNeYKlZttEzinZzg0Y+ka+e6p0Ko6YNlzG98rpngbyWFM/CVEliEoVYnOsPGHhoV2/GLxMc9JjjRJEBSrRCU7WXCqVQNr8hOLy/qlfvkCnKv2E9YHv4lTKKMayDmJWE0iFCF8DfoA2eHyfLt/6bWSsMzEGERpu4Z/N6EDeoEAws+tfk3No=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.0
Release Details
UpdatedMay 19, 2026, 8:39 p.m.
Changelog

This release lays down the foundation IntraVox needs to scale cleanly to Nextcloud Enterprise customers with thousands of users on multi-node deployments. Two themes: PageService gets split into focused, testable services, and the caching layer gains group-aware keys + a content-addressable distributed cache + a frontend prefetch pipeline.

User-visible: pages and navigation are noticeably faster on warm caches, especially for groups of users that share the same permission profile. Cold-cache latency is bounded by a new background warmup job. No breaking changes; every public API is unchanged.

Added

  • Subtree support on GET /api/pages/tree — Optional rootPageId query parameter narrows the response to the subtree rooted at the page with that uniqueId. Resolves #45 from JustinDoek (teamhub app builder) who previously had to combine listPages + getBreadcrumb to list pages under one anchor. Backward compatible — without the parameter the full tree is returned as before. The same parameter is available on the <PageTreeSelect> Vue component (rootPageId prop) for in-app subtree pickers (lib/Service/Path/PagePathHelper.php::findSubtree, lib/Service/PageService.php, lib/Controller/ApiController.php, src/components/PageTreeSelect.vue)
  • ETag / 304 conditional responses on GET /api/pages/{id} — Browser revalidation now returns a 304 with zero body when the cached page is still current. Per-user group hash is included in the ETag so a permission change automatically invalidates the cached entry without leaking content across users (lib/Http/EtagBuilder.php, lib/Controller/HasConditionalResponse.php, lib/Controller/ApiController.php)
  • Group-hash cache key for page tree + permission map — Tree and navigation caches are now keyed by a hash of the user's group memberships instead of their user-id. At enterprise scale (1000+ users in ~10 groups) this turns thousands of cache entries into dozens — same correctness, two orders of magnitude less memory. Permission path-maps are cached per-language (one entry per supported language, shared across all users) (lib/Service/GroupContextService.php, lib/Service/PageService.php, lib/Service/PermissionService.php)
  • Event-based cache invalidation on group changes — Adding or removing a user from a group flushes the affected distributed caches via UserAddedEvent / UserRemovedEvent listeners. Group permission updates propagate within one request cycle instead of waiting for TTL expiry (lib/Listener/GroupMembershipChangedListener.php)
  • Page-content distributed cache with mtime-indexed keys — Sanitized page output is cached under content_{uniqueId}_{mtime}; a write bumps mtime, the next reader misses cache and rebuilds. The expensive sanitize-pipeline (~500 lines of widget processing) only runs on cache miss (lib/Service/PageService.php)
  • News widget result cache with version countergetNewsPages() results are cached per {lang}_{groupHash}_v{counter}_{paramHash}. Mutations clear the cache; subsequent reads rebuild from a fresh counter state (lib/Service/PageService.php)
  • Frontend prefetch servicesrc/services/PrefetchService.js speculatively loads pages on hover (desktop, 100ms delay) and IntersectionObserver entry (mobile, 200px rootMargin). Respects navigator.connection.saveData so users on metered connections aren't surprised by extra requests; max 3 concurrent in-flight requests. Writes through the existing CacheService so real navigations pick up the prefetched data instantly
  • LRU eviction on localStorage quotaCacheService.set() now catches QuotaExceededError, drops the persistent entry with the earliest expiry, and retries once. Prevents silent cache-write failures on heavy intranets
  • Background cache-warmup job — Runs every 15 minutes (TIME_INSENSITIVE) and pre-warms the path-map + tree + navigation caches for each supported language. Prevents the cold-cache thundering herd after a deploy or after a page mutation (lib/BackgroundJob/CacheWarmupJob.php)
  • RequestTimer infrastructure — Light static utility for measuring p50/p95 latency of expensive operations. Used internally for ad-hoc profiling; not yet wired into TelemetryService (lib/Performance/RequestTimer.php)

Changed

  • PageService.php is 615 lines smaller — From 6135 to ~5520 lines. Ten pure helpers extracted into focused, individually-testable services. PageService remains the orchestrator for filesystem + cache + permissions, but the sanitize, format, search, path and template logic now live in dedicated modules:
  • lib/Service/Sanitize/HtmlSanitizer.php (strip_tags + style-property whitelist + entity decode)
  • lib/Service/Sanitize/UrlSanitizer.php (schema-whitelist for link URLs)
  • lib/Service/Sanitize/ColorSanitizer.php (NC theme-vars + hex + rgb/rgba)
  • lib/Service/Sanitize/MediaSanitizer.php (filename + SVG + image-header validation)
  • lib/Service/Version/PageVersionFormatter.php (NC-style "X sec/min/hour/day ago" + metadata accessors)
  • lib/Service/Template/TemplateMetadataExtractor.php (preview summary: column count, widget mix, complexity bucket)
  • lib/Service/News/NewsContentExtractor.php (excerpt, first-image, markdown strip)
  • lib/Service/Search/PageSearchHelper.php (snippet extraction, per-widget-type scoring)
  • lib/Service/Path/PagePathHelper.php (depth, page-type, department slug, current-page marking)
  • lib/Service/Util/PageIdUtils.php (sanitizeId, RFC 4122 v4 UUID, php.ini size parsing, formatBytes)
  • Test suite grew from 78 (with 36 errors) to 252 / 401 assertions, all green — Existing Controller tests were updated to match the current constructor signatures; a fresh unit-test layer covers every extracted service

Fixed

  • Cache-invalidation gaps closed across page/nav/media/import flows — Discovered during dev verification of the new caching layer: several mutation paths wrote to disk without flushing the distributed caches introduced by PR-3 / PR-12 / PR-13, so changes were invisible for up to 5 minutes after a save. Now resolved:
  • PageService::createPage flushes after writing — without this, the new page sat behind the 5-minute tree-cache TTL (visible on "Create from template" — page appeared in the breadcrumb but the editor mounted blank until reload).
  • PageService::createPageFromTemplate re-fetches through getPage() so the response includes enrichWithPathData + the sanitize pipeline. Previously the API returned half-populated page data and the editor rendered blank until a manual save round-tripped through the real read path.
  • App.vue::handleCreatePageFromTemplate uses the enriched backend response directly instead of doing a second selectPage() round-trip that occasionally 404'd against a freshly-created folder and bounced the user back to the home page. URL hash, local pages array and frontend CacheService are all warmed in one synchronous block before the editor mounts.
  • ImportService::importFromZip flushes all PageService caches after a bulk import — without this, 50+ imported pages were invisible in tree, navigation and news widgets for the next 5 minutes.
  • NavigationService::saveNavigation flushes intravox-pages + intravox-permissions after writing — previously a menu edit landed on disk but the path-map cache (PR-3) served the old menu for 5 minutes.
  • PageService::uploadMedia + uploadMediaWithOriginalName flush the per-page content cache so the next page-render reflects the just-uploaded asset (important for image overwrites where users otherwise got the cached old version back).
  • Public PageService::invalidateAllCaches() introduced as the cross-service hook for the import path (kept internal clearCache() private; only the audit-driven external use case opens it up).
  • Actionable error messages on failed ZIP imports — Resolves #52 from @apesorguk, who saw only "Import failed. Please check the ZIP file format and try again" when uploading a cloudron Nextcloud backup. The five validation errors in ImportService (invalid ZIP, missing export.json, invalid JSON, unsupported version, incomplete export) now bubble through a typed InvalidImportException and reach the user with copy that tells them what went wrong and how to fix it ("Make sure you uploaded an IntraVox export, not a Nextcloud Files backup..."). HTTP status is now 400 for these instead of 500. Generic failures still hide behind an errorId so server paths don't leak. A NcNoteCard above the import form spells out the supported format up front. Error messages translated to NL/DE/FR via a stable errorCode (INVALID_ZIP, MISSING_EXPORT_JSON, INVALID_JSON, UNSUPPORTED_VERSION, INCOMPLETE_EXPORT) the frontend maps to localized strings (lib/Exception/InvalidImportException.php, lib/Service/ImportService.php, lib/Controller/ApiController.php, lib/Controller/ImportController.php, src/components/AdminSettings.vue)
  • Broken Controller test suiteApiControllerTest, BulkControllerTest, AnalyticsControllerTest now compile against the current Controller constructor signatures. The OCP stub gained ISession, ICache, ICacheFactory, IGroup, group-membership events and Files_Versions\IVersion to keep unit tests runnable without a full Nextcloud install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturer9Dvf1Sv0MUqG5zMrZC7vrTGxJ/b/FMFLIQaX9apeRGFYpfb4hH4Zsbt+aKCbyoRj3zOGtdytKpqUDEXZ9jFexiNrkKjfWOvW8XSH1dlFHc6Vo/z+h7Ms+02xgNdSxajfN0yJK0WnDDfhEUn1j9VaByfKuF9VaMVwHL0u4A+k2LwCW0izMkZVjLtiJk/1VyA7pc4Olz+6eWyF0QaKkTXyMmbibugQNrRjRCAylR8up/tSlgi4aTobGMZKkoeZg+HK5KfQXiZHoC4B3GiP3Vf/CfzU0WYyhq7sOZ4LM7PUtgZwcJyUMk5i12oS56Nf+4Umubrn6OaupdmOmgSbCbN3G1K7HWgRpYGqmdDdqzIajzm/lt2vV5gtW4PUyY1ESAh5F1Cch/h/+HWndtyQZDkKgX0jgXtKttltXJbC4/+LQWPIDmffP8ve12tSpCYcENQdvV8rtGkS4aAH0Mf3jiqa8oNtpr7VgwslCHEhrSXxMz1mprSO+x+R3wqWmo+JCo9QmPnwT9nhf81CtvazMkZ2zmzrGX4EegRNpILLPbR3BwrV214CHpu6lnE9zZlCqU9/pXyJoutDUrGtk8gqD3tl2heAy4EcEOIgnHOYx72Q14HXk227XA61Qvq02dp/+lQKLtiEBByL5ZkT/FYQsgyZsEM4p9YBMXr9/ZzmTDrG1k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.4
Release Details
UpdatedMay 8, 2026, 8:11 a.m.
Changelog

Identical content to 1.3.1 (released earlier today). The version number is bumped to 1.3.4 because an internal 1.3.3 build was published to the App Store on 2026-05-06; instances that picked up that build would not see 1.3.1 as an upgrade. 1.3.4 ensures every existing install gets the editor/table improvements and the privacy cleanup of [1.3.1] below.

No code changes vs. 1.3.1.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBQtsgQvlSPO/vsSYvRbB2PBuBbivwcUewzg126b/lwuFwdLoS/6+o9m1Kahs/ZxLur3f6fBRJEw2fZOh85ofBGQbd6o3KFJtLkUzZZ3/zsfiwbxlUCaNiO3hnuF5UHqpumyiL2bQO2BzaYHCn0G+82UonzYOsvbhMMwVIJeL3oCis3B9Z0+lB6KkCtAuE0mGLybehJ0Sa1KG326gf69OopoE94ikLowwxOPFmFJx6944rmk7axG92CtAV4x68WI8imrKPY59lAt3VI4+YiAXWdjyGKrG08yPi30AjnMwW5raab78hiySW1mIKcpMd8UaDVfKz19oG3MnRz7TpVSzADxuxx5ueuP1sV58e+5UU/Uv2OcghdnFSdyiSCHGQokUqUi63q0QV74517WQgdnmygJRXR+YwYfOn/AhhhKXSeyb/KFIlHoTTdM+gNysJldCBktY49ZEKGhi5AJkGW2jzZ3+hVW1PZylTqV9HRq/ZgFVukYJdPYsWV5UQ8XzN+vYcLuYsPMBWxfKeuecfdzjChZ6sxseqIYyqk2WzN/hBZLbzuQODvroGmb7nPzQsJHolgv7YcCLk0EexuyI2FdYUpI3UKSes9jqAIdLsRylBsgtnVNV6pe53IX3NjWgYubA2VQWgzMM5hFjiM9Q2PyebaXDb7n/LTl73D/qy/0guHw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.1
Release Details
UpdatedMay 8, 2026, 6:34 a.m.
Changelog

Added

  • Text alignment — New alignment dropdown in the text editor toolbar (left, center, right). Alignment persists through save/reload using CSS classes in markdown storage. Supports paragraphs and headings. Keyboard shortcuts: Ctrl+Shift+L/E/R. Custom TipTap extension uses CSS classes instead of inline styles for DOMPurify compatibility (textAlignExtension.js, InlineTextEditor.vue, markdownSerializer.js)
  • Blockquote button — New blockquote toggle button in the text editor toolbar. Uses the existing StarterKit blockquote extension — only the toolbar button and read-only styling were missing (InlineTextEditor.vue, Widget.vue, Footer.vue)
  • Nextcloud Extended Support telemetry — Telemetry payload now includes hasExtendedSupport (boolean), sourced from Nextcloud's public OCP\Util::hasExtendedSupport() API. Helps us understand which share of IntraVox installations runs on Nextcloud Enterprise / Extended Support — relevant for compatibility prioritization and the Nextcloud ISV partnership. Falls under the existing telemetry opt-out (no separate consent), and is listed in the admin "What we collect" overview for transparency. No personal data, just a single yes/no per instance (TelemetryService.php, SupportSettings.vue)
  • Persistent column widths in tables — Column widths an editor sets by dragging the TipTap resize handles now survive save/reload. A post-render hydrator in markdownSerializer.js builds a <colgroup> from data-colwidth (modern) or colwidth (legacy) cell attributes and any pre-existing <col style="width: Xpx">, then converts pixel widths to percentages so the table always fits its container — even when the saved widths sum higher than a narrow page-row column. Tables without explicit widths keep the previous auto-layout behaviour (markdownSerializer.js)
  • Table width presets — New "Width" row in the table toolbar dropdown with presets Auto, 25%, 50%, 75%, 100%. Stored as data-table-width on the <table> (InlineTextEditor.vue)
  • Table alignment — New "Alignment" row in the same dropdown with Left/Center/Right buttons. Stored as data-table-align; rendered as margin-left: auto / margin-right: auto so a 50%-wide table can sit left, centered, or right with surrounding text (InlineTextEditor.vue)
  • Free-form table width drag handle — A custom ProseMirror plugin adds an 8px-wide drag area on the right edge of the active table. Click+drag to set any pixel width between 80px and the widget container's width; the resulting style survives save/reload via the same hydrator. Coexists with the column-resize handles inside the table — different hit zones (tableResizeHandle.js, InlineTextEditor.vue)
  • Horizontal scroll wrapper for wide tables — Tables wider than their page-column scroll horizontally inside a .tableWrapper div instead of pushing the page layout sideways. Read-mode wraps every table via the hydrator; edit-mode reuses TipTap's built-in .tableWrapper element with the same styling, so what the editor sees matches what readers get (markdownSerializer.js, Widget.vue, InlineTextEditor.vue)

Changed

  • Toolbar reordered — Text editor toolbar reorganized into logical groups based on analysis of 10 popular editors: (1) Inline formatting: B, I, U, S (2) Block structure: Heading, Lists, Blockquote (3) Alignment dropdown (4) Insert actions: Link, Table. Compact mode follows the same grouping in the "More" dropdown (InlineTextEditor.vue)
  • Alignment as dropdown — Text alignment uses a single dropdown button (like the heading dropdown) instead of 3 separate buttons. The button icon dynamically reflects the active alignment. Keeps the toolbar compact on all screen sizes (InlineTextEditor.vue)
  • Telemetry includes license key for Enterprise claim verificationTelemetryService::collectData() now adds the configured license key (or empty string for community instances). The license server uses it to verify hasExtendedSupport claims against the bound license_usage row before honoring them; without this binding the boolean would be anonymously spoofable. The key is the same value the app already sends to license validation/usage endpoints, so this introduces no new disclosure (TelemetryService.php)
  • Table cell text wrap policy — Cells use overflow-wrap: anywhere (CSS Text Module Level 3) so long unbreakable tokens (URLs, hashes) wrap mid-word when needed. Edit-mode and read-mode use the same rules so what the editor sees is what readers get. Replaces the deprecated word-break: break-word combo with the modern one-line equivalent (InlineTextEditor.vue, Widget.vue)
  • Page rows allow narrow content.page-row, .row-content, .page-grid got min-width: 0 and max-width: 100% so a wide table inside a multi-column row no longer forces the row beyond its viewport. The grid columns now use repeat(N, minmax(0, 1fr)) instead of repeat(N, 1fr) so a 1fr track can shrink below its content's min-content (PageViewer.vue, PageEditor.vue)

Fixed

  • Aligned text not surviving save/reload — Content with text alignment was escaped to raw HTML after saving and reloading. Root cause: markdownToHtml() had a validation check (html === preservedMarkdown) that incorrectly treated HTML blocks passed through by marked as a parse failure, triggering escapeHtml(). Fixed by skipping this check when content starts with < (markdownSerializer.js)
  • Table widths and alignment getting stripped on savedata-table-width and data-table-align were not in the DOMPurify allowlist, so user-set widths and alignment from the table dropdown silently disappeared after saving. Added to the allowlist together with the <div> tag we now use for the scroll wrapper (markdownSerializer.js)
  • Text overflowing table cells — In fixed-layout tables, long text in a cell could push past the cell border into the next column or beyond the table edge. Multi-cause fix: paragraphs and headings inside cells get min-width: 0; max-width: 100%, cells get white-space: normal (overrides a Nextcloud core rule that set nowrap on <p>), and the entire page-row chain was given proper min-width: 0 so a wide table can no longer push its ancestors sideways (InlineTextEditor.vue, Widget.vue, PageViewer.vue, PageEditor.vue)
  • TipTap auto-generated table widths preventing fit-to-container — TipTap writes <table style="width: 422px"> based on summed colwidths; in narrow page-row columns this pinned the table beyond its container even with table-layout: fixed. The hydrator now strips that auto-style and rebuilds only from user-set data-table-width (markdownSerializer.js)

Removed

  • Organization name & contact email from telemetryorganizationName and contactEmail fields are no longer included in the telemetry payload sent to licenses.voxcloud.nl/api/telemetry/report. These were the only direct identifiers in an otherwise pseudonymous payload, so removing them brings telemetry closer to true anonymity. The fields had no functional purpose for telemetry — the license server doesn't use them — and no direct identifiers remain (TelemetryService.php)
  • "Your organization (optional)" admin settings section — Removed the corresponding UI section, Vue state, and GET/POST /api/settings endpoints from LicenseController. Pre-existing organization_name / contact_email config values remain in oc_appconfig on upgraded instances but are no longer read or transmitted; they can be cleaned up in a future migration (SupportSettings.vue, LicenseController.php, routes.php)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDR0XAuKJCLgbWV58zbVn9unXzIqAifDSrOYOGR04PcRtLR9ZDkgt/FbrI0HctxpnWmXD2zcV5pjYAu4Xc+m5OyWl+o9aMgKao4LZqyVkLiE6KeagdVonIEHbDd5wvNfSG9KXBWjcVu31jH831sBhodRmJ/ovY795C3q5cOFNYoLIGVHi278qa4r/wSqbsvULzu1vPEUpY3hukQn6XjzkRyh+gahUDmcU76xKeNL6f2pEdKkDKqFUN3TgBOJDaZYwJpy3tCwLRZNwFkLLoLy2XihULJxIlc800+zuIFlI3e1EfbhYtdBJXc449sJo7pIBHaHhF1vPU6eFgVmk+J8sPj1RoXiC7CRYNje41NOy0Bvkdx7QeB2O4ElH3huRnsS66oCrzcr+FJ1zRe8USai20NO8zfQifO0W5JR8Y1aWl/aKrzWIKtkZAYRptfMb4T+c0Sc9h1XPgfm5wK5D2eAJfnDgXJ3sUSfg8bf66tFQbvEmrbtG1n5C0X7j3i8jCL/7CqyWHpFbfCTsh4hmm6jnGSHVQvFoFwTcnbiLAamCMbkcRQ5DnaLMIXY/B5r2I2xzy8wEDhl4CJI8imIkjMTsFjrj8/UcTjQ1fL9bO5q8M4wfupSpPE62BIQcyvsKhfD+vfjRKegu3C60e52A9XtErd9sPUGFZNpXvz+DHGk6VHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.0
Release Details
UpdatedApril 21, 2026, 9:26 a.m.
Changelog

Added

  • Feed widget — New widget type for displaying external content on intranet pages. Supports RSS/Atom feeds and admin-configured connections to external systems (Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, and custom REST APIs). Features include: list and grid layouts (2-4 columns), configurable display options (image, date, excerpt, source, author), per-user OAuth2 personalization for LMS content, OIDC auto-connect for zero-click SSO, manual token fallback, 15-minute server-side caching, and public share support (FeedWidget.vue, FeedWidgetEditor.vue, FeedReaderService.php, FeedItem.vue)
  • Feed widget: connection presets — Administrators configure connections in Admin Settings using platform presets that auto-fill endpoint paths, auth methods, and response field mapping. Presets available for Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, and Custom REST API. Each preset supports platform-specific content types (e.g. News/Courses/Deadlines for LMS, Pages/Documents/Lists for SharePoint, Bugs/Recent/Created for Jira)
  • Feed widget: content type selection — Widget editors choose what content to display per connection type. LMS connections offer News/Announcements, My Courses, and Upcoming Deadlines. SharePoint offers Pages/News, Documents, and List items (with library/list selector). Jira offers project filtering and content types (bugs, recent, created). Content type selection happens in the widget editor, not admin settings
  • Feed widget: SharePoint integration — Full Microsoft Graph API integration via OAuth2 client_credentials flow. Automatic token acquisition and caching using tenant ID, client ID, and client secret. Supports SharePoint site ID resolution (hostname:/path: format), page/news listing, document libraries, and list items. Admin configures site URL + Entra ID credentials; editors choose content type and library in the widget
  • Feed widget: image proxy — Secure HMAC-signed image proxy bypasses Nextcloud CSP restrictions for feed images. Supports JPEG, PNG, GIF, WebP, AVIF, SVG (with sanitization via enshrined/svg-sanitize), and ICO. Daily signature rotation with yesterday grace window. All feed images (RSS, LMS, SharePoint, Jira) are proxied automatically (FeedReaderController.php, FeedReaderService.php)
  • Feed widget: OAuth2 account linking — Users can connect their personal LMS account via OAuth2 popup flow (Canvas, Moodle with local_oauth2 plugin, Brightspace). Connected users see personalized content from their own courses. Token refresh is automatic (LmsOAuthService.php, LmsOAuthController.php, LmsTokenService.php, OidcTokenBridge.php)
  • Feed widget: sort and filter — Feed items can be sorted by date or title (ascending/descending) and filtered by keyword. Filter searches in title, excerpt, and author (case-insensitive). Applied server-side after caching for instant response
  • Feed widget: custom request headers — REST API connections support configurable HTTP headers (key-value pairs). Enables Nextcloud OCS API integration (OCS-APIRequest: true) and other systems requiring custom headers
  • Feed widget: design principle — IntraVox focuses on organizational content (news, team updates, external feeds). Personal Nextcloud data (activities, notifications, recent files, Talk, Deck, Mail) belongs on the Nextcloud Dashboard. IntraVox does not duplicate Dashboard functionality. For organizational Nextcloud data from remote instances, use the REST API (custom) source type with OCS API endpoints
  • Calendar widget: external ICS feeds — Editors can add external ICS calendar URLs (e.g. from Moodle, Canvas, Brightspace) directly in the calendar widget. Events from these feeds are visible to all page visitors, including public share viewers. No Nextcloud Calendar subscription required per user. Supports up to 5 ICS feeds per widget with 30-minute caching (ExternalIcsService.php, CalendarWidgetEditor.vue)
  • Calendar widget: LMS event deep links — Clicking an external calendar event opens the event in the source LMS. Supports Canvas (native URL field), Brightspace (URL constructed from UID), and Moodle (URL constructed from UID). Unknown sources link to the feed domain
  • Feed widget: singleflight lock — Prevents thundering herd on cache expiry. When the feed cache expires, only the first request fetches from the external source; concurrent requests wait and read from the freshly populated cache. Uses a distributed lock with unique request ID verification (FeedReaderService.php)
  • Feed widget: circuit breaker — After 3 consecutive failures for a feed source, the circuit breaker opens and returns immediately with "temporarily unavailable". Resets automatically after 5 minutes or on first successful fetch. Prevents cascade failures from unstable external sources
  • Feed widget: background refresh — New FeedRefreshJob background job proactively refreshes configured feed connections every 10 minutes, before cache expiry. Users almost never trigger a cold fetch. Includes its own circuit breaker to skip failing sources
  • Feed widget: rate limitingUserRateThrottle(30/min) on authenticated feed endpoints, AnonRateThrottle(30/min) on public share feed endpoint (FeedReaderController.php)
  • Page metadata database index — New intravox_page_index table stores pre-indexed page metadata (title, uniqueId, path, language, status, modification time). Eliminates O(N) filesystem traversals for page listing, tree, and search operations. Updated automatically on page create/update/delete (PageIndexService.php, Version001300Date20260420000000.php)
  • Nextcloud search: index-first — The unified search provider (Ctrl+K) now queries the page metadata index for fast title-based results (~1ms), with fallback to full-text filesystem search for content matches (PageSearchProvider.php)
  • Distributed page tree cache — Page tree is cached in Redis/APCu (distributed) in addition to the existing in-process static cache. Shared across PHP processes/requests for ~70% reduction in tree response time. Invalidated automatically on page create/update/delete (PageService.php)
  • People widget: scalability guardrails — Hard cap of 5,000 users on the unscoped filter path to prevent OOM/timeout on large Nextcloud instances. Filter results cached in Redis/APCu for 1 hour. Batch status prefetching reduces API calls from N to 1 (UserService.php)
  • Rate limiting on mutating endpointsUserRateThrottle added to page create/delete (10/min), bulk operations (5/min), comments (20/min), reactions (30/min), and analytics tracking (60/min). Covers ApiController, BulkController, CommentController, AnalyticsController
  • GDPR user deletion handlerUserDeletedListener automatically cleans up analytics records, page locks, feed tokens, and LMS OAuth tokens when a Nextcloud user is deleted (UserDeletedListener.php, Application.php)
  • Audit logging — Administrative operations logged with IntraVox Audit: prefix for SIEM integration: bulk delete/move/update (with page IDs and user), license key changes, organization settings, engagement settings (BulkController.php, LicenseController.php, ApiController.php)
  • Health check endpointGET /apps/intravox/api/health returns app status and version for monitoring and orchestration (Kubernetes, uptime monitoring)
  • Scalability documentation — New SCALABILITY.md documenting all performance, caching, resilience, rate limiting, and enterprise features
  • Admin: connection test button — "Test connection" button on each feed connection card verifies credentials and endpoint by fetching a preview from the external API
  • Admin: connection export/import — Export all feed connections as JSON (without tokens/secrets). Import on another instance with duplicate detection and preview dialog
  • Admin: connection active/inactive toggle — Each connection has an NcCheckboxRadioSwitch toggle to temporarily disable it without deleting. Inactive connections show a specific message in widgets ("This connection is currently disabled by an administrator.") and are excluded from the widget editor dropdown. Re-enabling restores all widgets automatically — no reconfiguration needed. Toggle saves immediately
  • Admin: connection status badges — Connection cards show configuration status as text badges: "Configured" (green), "Not configured" (orange), "Token missing" (orange), "Credentials missing" (orange). Replaces the previous green/grey dots for better visibility
  • Admin: connection remove confirmation — Removing a feed connection shows a Nextcloud-style confirmation dialog instead of a browser prompt
  • Admin: Clean Start DELETE confirmation — Destructive "Clean Start" action now requires typing DELETE to confirm
  • Admin: orphaned data banner — Automatically detects orphaned data on admin panel load and shows a warning banner with link to Maintenance tab
  • Admin: advanced options collapse — Endpoint path, response mapping, and custom headers for custom REST API connections are behind an "Advanced options" toggle
  • Admin: column width warning — Shows a warning when the configured number of page columns may be too narrow for the available width, with a recommendation for fewer columns
  • Feed widget: error messages — Specific error messages for inactive connections, 404 (connection not found), 401 (authentication required), 403 (access denied), and 429 (rate limited) instead of generic "Could not load feed"

Changed

  • Feed widget: HTTP timeout reduced — Outbound HTTP timeout reduced from 10s to 5s to prevent PHP worker blocking when external sources are slow (FeedReaderService.php)
  • Bundle splitting — Enabled webpack splitChunks to separate vendor code (~2.9 MB) from application code (~220 KB). Main bundle reduced from 3.7 MB to 220 KB. Vendor chunk is shared between main and admin entry points and cached separately by browsers (webpack.config.js)
  • TipTap lazy-loaded — TipTap editor and all 8 extensions (~240 KB) are loaded dynamically via import() on first editor mount. Pages viewed in read-only mode never download the editor code (InlineTextEditor.vue)
  • Widget components lazy-loaded — All widget components (News, People, Calendar, Feed, Links, InlineTextEditor) loaded via defineAsyncComponent. Pages only download the widget types they actually use (Widget.vue)
  • Widget watchers debounced — Deep watchers on News, People, and Feed widgets debounced with 300ms delay to prevent API call bursts during editor configuration changes (NewsWidget.vue, PeopleWidget.vue, FeedWidget.vue)
  • Widget initial fetch deferred — News and Feed widgets use requestIdleCallback for initial data fetch, improving perceived page load performance
  • Page + lock fetch parallelized — Page content and lock status are now fetched in parallel via Promise.all instead of sequentially, eliminating ~100ms waterfall (App.vue)
  • Engagement settings cached — Engagement settings now use CacheService with 5-minute TTL, consistent with navigation and footer caching (App.vue)
  • News widget: collection limit — Recursive folder scan stops after collecting enough items (default: max(limit * 4, 200)) instead of scanning all folders before applying array_slice (PageService.php)
  • Tree components: progressive rendering — PageTreeItem and PageTreeSelectItem render max 50 children per node initially with a "Show more" button for additional items. Prevents DOM bloat with large page hierarchies (PageTreeItem.vue, PageTreeSelectItem.vue)
  • Navigation/footer HTTP caching — Added Cache-Control: private, max-age=300, must-revalidate and ETag headers to navigation and footer API responses, consistent with the existing feed API pattern (NavigationController.php, FooterController.php)
  • Feed widget: unified connection architecture — Replaced separate source types (Moodle, Canvas, Brightspace, REST API custom) with a single "Connection" concept. Editors choose RSS or Connection; the admin configures connections with presets (Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, Custom, plus LMS types). Presets auto-fill endpoint, auth method, and response mapping. LMS-specific logic (Moodle POST body auth, Canvas context_codes, Brightspace org unit) is preserved internally but hidden from the user. Backwards-compatible with existing connections
  • Calendar widget: IManager refactor — Replaced CalDavBackend with OCP\Calendar\IManager for fetching calendars. This properly handles both regular calendars and ICS subscriptions. Calendar identifiers changed from numeric IDs to string keys (CalendarService.php, CalendarController.php, PageService.php)
  • Calendar widget: hide ICS subscriptions from selector — Nextcloud ICS subscriptions are no longer shown in the calendar selector since external feeds are now managed via the dedicated ICS URL field
  • CSS theming compliance — Replaced non-standard --color-text-light with --color-text-maxcontrast in Feed and News widgets. Replaced hardcoded #fff/white with var(--color-primary-element-text). Replaced hardcoded border-radius values with NC variables. Standardized font-weight to 600 (NC convention). Dark theme backgrounds now use var(--color-primary-element-light) instead of hardcoded rgba values. Affects: FeedItem.vue, NewsItem.vue, CalendarWidget.vue, FeedWidgetEditor.vue

Fixed

  • Calendar widget wrong events shown — When an ICS subscription had the same numeric ID as a regular calendar, the widget showed events from the wrong calendar. Fixed by switching to unique string keys via IManager
  • REST API SSRF hardening — Connection base URL is now re-validated on every fetch request, not just at save time. Prevents SSRF if an admin account is compromised and a malicious URL is injected into stored connection config
  • Version restore not persisting — Restoring a page version appeared to work but reverted after a hard refresh. Root cause: the backend reused a stale file node after IVersionManager::rollback(), and the frontend masked the issue by showing a version preview instead of the actual restored page. Fixed by re-obtaining a fresh file node after rollback and clearing the version preview after restore
  • SSRF hardening: LMS connectors — Added validateUrl() with private IP range blocking to Moodle, Canvas, and Brightspace fetch methods. Previously only the generic REST API connector validated URLs at fetch time
  • SSRF hardening: ICS calendar feeds — Added private/reserved IP range blocking to ExternalIcsService::validateUrl(). Previously only enforced HTTPS without checking for internal network addresses
  • SSRF hardening: SharePoint & Jira — Added validateUrl() to resolveSharePointSiteId() and getJiraProjects() to block requests to private IP ranges
  • SSRF hardening: Confluence API importer — Added URL validation with private IP range blocking to the Confluence REST API importer's base URL
  • XXE hardening: Confluence importer — Added LIBXML_NONET flag to DOMDocument::loadXML() and loadHTML() in the Confluence Storage Format parser to prevent external entity resolution
  • Token handling: Jira project listing — Replaced direct admin token decryption with resolveToken() for consistent token resolution across all connector methods

Security

  • CSP hardened — Removed unsafe-eval from Content Security Policy. The Vue 3 runtime-only build and TipTap editor do not require eval(). This was a historical precaution that is no longer needed (PageController.php)
  • HMAC key hardened — Image proxy signature key now uses hash('sha256', ...) for proper 256-bit key derivation instead of string concatenation (FeedReaderService.php)
  • API response size limit — External API responses larger than 10 MB are rejected before JSON parsing to prevent out-of-memory conditions (FeedReaderService.php)

Accessibility

  • Feed widget aria-live — Loading and content states announced to screen readers via aria-live="polite" and role="status" (FeedWidget.vue)
  • Feed item semantics — Removed conflicting role="article" from feed item <a> tags. Added focus-visible outline for keyboard navigation (FeedItem.vue)
  • Admin loading spinners — All loading spinners in admin settings now have role="status" and aria-label="Loading" for screen reader users (AdminSettings.vue)
  • Connection card keyboard nav — Feed connection expand/collapse headers are keyboard-accessible with tabindex, role="button", aria-expanded, and Enter/Space handlers (AdminSettings.vue)
  • Status dot contrast — Disconnected connection status indicator has a visible border for better contrast on light backgrounds (AdminSettings.vue)

Documentation

  • New SCALABILITY.md — Comprehensive guide to performance, caching, resilience, rate limiting, GDPR, and enterprise features
  • Updated ARCHITECTURE.md with scalability section
  • Updated SECURITY.md with CSP, rate limiting, GDPR, audit logging, and feed widget security sections
  • Updated ADMIN_GUIDE.md with health check and audit log sections
  • Updated ADMIN_SETTINGS.md with connection testing, export/import, enabling/disabling connections, Clean Start confirmation, and advanced options collapse
  • Updated FEED_WIDGET.md with RSS example screenshot, SharePoint setup guide (Entra ID app registration), content type selection, error messages table, and screenshots for all connection types
  • Updated ACCESSIBILITY.md with feed widget and admin panel accessibility improvements
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLc6iFEUpymkn2oOpihHrtxmTjKYFZWKcuvfBrf1Xr3us6SzOBhArJpj7t5GHUekRY6sJiuf47lqIDbjzf9fby51vse5bF+n1/QHXdApMDmsxo6EhtM5e3VRWje9A+ZuT2W+Xspdu1owszLqJfQw3TMBFmtAF2QNLAxTU6X8BOwc2Px6MUJnD+aNrOaE4117bBqSv27JihzvyHoz21ey+kZK+vrXaZoXrLzKkf69mPYKMEiVuyKaueTLhuRcihJPZAuVC+ClgZVTueZGDmNQA39xfL9Puy5JpbQx6+7MSL6FKhoN4bXD3ve3DloPsIC35KF+gpH/T8hY6f3vWQgX5mGh5mQSJLHTTkYulKiDcXRq82cDg/o2tpw7D6Uu3R/wVafqGrndtl8A5/okhCHGJnwh7FdG3vzoMFMLdEM03Zlk4W5hiVio5fd1Wy0LVM6SaGM81S9+TrOV0S35vuONStfe56e17wDC9DVaznDTQJW7E7qj4eihX/r0sVD0qQzYoIQ7PvnJ5XNAobWh28TA0eXwOnTwlOSsFhHxBLyt/DJE2CYoEz8YYBNnBgTGthYVKPp/grlWfFGNrRygNOYYMbMSmVqZQ/8liz1OrMcFwC0DoW/IVtmaB8PIGYs7XO8D8IBYRVpklTlQpgFrEf8PpD/8rfnp04VGlWCb/E9tR9x4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.2.0
Release Details
UpdatedApril 16, 2026, 10:48 a.m.
Changelog

Fixed

  • People widget filter persistence — Filters using the "does not contain" operator were silently converted to "equals" on save because not_contains was missing from the backend operator whitelist. After a page refresh the filter showed different results. The operator is now correctly preserved
  • People widget filter value encoding — Filter values containing special characters (&, <, >, quotes) were HTML-encoded on save via htmlspecialchars(), causing them to no longer match user profile data (e.g., "R&D" became "R&D"). Filter values now use a dedicated sanitizeFilterValue() that strips tags and control characters without HTML-encoding. Existing corrupted values are automatically decoded on read
  • Editor contrast on colored rows — Column labels, placeholder text ("Enter text..."), column borders, and "Add Widget" buttons now adapt to dark row backgrounds (Primary color). Previously these elements were nearly invisible on dark backgrounds

Added

  • Skip-to-content link — Keyboard users can skip past the navigation to reach the main content directly (App.vue, PublicPageView.vue)
  • Semantic landmarks<header>, <main> elements replace generic <div> wrappers for better screen reader navigation
  • ARIA tab patterns — Proper role="tablist/tab/tabpanel" with aria-selected on NewPageModal and MediaPicker tab interfaces
  • ARIA combobox pattern — PageTreeSelect now announces as a combobox with aria-expanded and role="listbox" on the dropdown
  • Carousel accessibility — News carousel has role="region", aria-roledescription, aria-label, aria-live="polite" for slide announcements, and respects prefers-reduced-motion
  • Live regions — Loading states use role="status" with aria-live="polite", error states use role="alert" (App.vue, PublicPageView.vue, CalendarWidget.vue)
  • Focus-visible styles — Global *:focus-visible outline for keyboard navigation visibility
  • Reduced motion support — Global prefers-reduced-motion media query disables all CSS animations and transitions. Carousel autoplay is skipped when the user prefers reduced motion
  • Visually-hidden utility class.visually-hidden CSS class for screen reader-only content
  • Breadcrumb current pagearia-current="page" marks the active page in breadcrumb navigation
  • Accessibility documentation — New ACCESSIBILITY.md documenting WCAG 2.1 AA compliance status, legal framework (Wet Digitale Overheid), and implemented measures

Changed

  • Form labels associated with inputs — All form inputs across 15+ components now have programmatically associated labels via for/id pairs or aria-label attributes (WidgetEditor, NewPageModal, PageTreeSelect, CommentSection, MediaPicker, AdminSettings, PageEditor, NewsWidgetEditor, PeopleWidgetEditor, CalendarWidgetEditor, LinksEditor, NavigationEditor, PublicPageView)
  • Icon buttons accessible — All icon-only buttons in InlineTextEditor toolbar, carousel navigation, MediaPicker, and AdminSettings now have aria-label attributes
  • Draft badge contrast improved — Fallback text color darkened from #856404 to #6d5003 for a 5.5:1 contrast ratio (WCAG AA requires 4.5:1)
  • Dropdown accessibility — Navigation dropdowns have aria-haspopup and aria-expanded attributes
  • WelcomeScreen heading — Changed from <h1> to <h2> to prevent duplicate h1 on the page
  • Password error announced — Public page password error message has role="alert" for screen reader announcement
  • MediaPicker strings translated — All hardcoded English strings wrapped in t() translation function

Fixed

  • Focus anti-pattern removed — Removed event.target.blur() in Navigation.vue that was stripping keyboard focus after clicking the page structure button

Documentation

  • Added ACCESSIBILITY.md with full WCAG 2.1 AA compliance matrix
  • Added accessibility link to README documentation section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWi2Kezb67KRxkFi/zRvjUrCCpNNRc2DBOWtuhOITpNScggVnaSiP+zLGO3s+/fPnKmgGrFoPeSuTSQifpEA37aQrwWx1comrLRq6k9SG+4+VhgAxVjvYdha0fqhah0HDjsgfC1cLhOBExqudxnijKEf+NCGgZqf1tHFnLtUbM1Z+x5o0CjAjv47c8Qrz/LD5NTvDcmU2vkkePA4nNjMheGuxC70rmwceaXaoA2CRf9BZ2XQsI8AgE9yoTEFvdWVdpN/BR+DKoAQya6XBZitrAp1jvH3okVMMap+XDBJrhD8mfBC/9eEn4Q/UW1Xc/m3WnCMVy5MiuY3Jv0b9pl+BghH8elxTjsZZRQJ7riGX1k9e/I3hjl4GZKO96USxGi5tDoWWtq/dKLddmrzy00o0cBMuKaAJ/sFal+OyZg++OWO7Zi0sxeL12T2OaojmJ4u22sZmgaZi+Tl5naidjOE9cz3Tv41C7IIAKpW4j1Xrj7L2D9vA5C7rKH/7vIbY/iLWnIY0df5BDs7NsccnftNNLXGA24PjtN7C21SoLbSHA2hDk81Lq3QohMyCod13UkcCO4/OjKFH523IEmLnzxujA+YXNxnfEvaEW66AQn56pDKgBN0tmLKjMBd8hIAEBzpBP67buSytYIj3XjoRtR9rMHq1W125eljViPQlVVd0vTM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.2
Release Details
UpdatedApril 10, 2026, 10:41 a.m.
Changelog

Fixed

  • Telemetry error feedback: The "Send report now" button now shows the actual server error message (e.g., rate limit, connectivity issue) instead of silently failing
  • MetaVox icon dynamic loaded — MetaVox sidebar tab icon is no longer a hardcoded SVG copy. Now loads dynamically from the MetaVox app via imagePath('metavox', 'app.svg'), so logo changes in MetaVox are automatically reflected in IntraVox. Dark mode handled by Nextcloud's automatic app-dark.svg serving

Changed

  • App Store description rewritten — Expanded from ~150 to ~250 words, structured in 6 sections: page editor, widgets, collaboration, content management, enterprise, and requirements
  • App Store summary — Changed to "SharePoint-style intranet pages for Nextcloud — no code required"
  • Author updated to VoxCloud — Author name, email (info@voxcloud.nl), and homepage (voxcloud.nl) now reflect VoxCloud branding
  • Screenshots expanded from 3 to 7 — Added calendar widget, people widget, news carousel, templates, and engagement screenshots
  • Category social added — Reflects engagement features (reactions, comments, people widget)

Added

  • Documentation links in App Store — Editor Guide, Admin Guide, and API Development Guide now linked from the app listing

Security

  • axios upgraded to 1.15.0+ — Fixes critical SSRF vulnerability via NO_PROXY hostname normalization bypass (GHSA-3p68-rc4w-qgx5)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturedEPa13irIrVkzszfHig0ZkpEhHIKNvbSxRdMHeALc3YGKW3H/pXgEyzlSiOgTRlYG9JwD6bAo8ANVhK9tBaIMr5nzOO0JrgExrnHniBe4LtGgJ2xbE1TeVVKEnlgcmwi8SG60ueKvIJU/x/Vy2yIJJGe/ShTntep5qiwGJBe8QksUTojfPiDaqDXzcgVRyYhbvIuT44/TF5oohBzbLLHvXm5bhcbUP6WyWz2KsTF7sgMtkKmClOiY/vZYVG2QaK87+QbwBwnW5icirect8ZzPzxSHqsg3LJdP4InayQhs21ZSm6rdrmBhT8Z36OJv9Mu2Dzdvl5cbqalUJbLs5ILHh/i4LKcIgt5fd9yvPHrtH7DNKQHeYMdH6x9saOq6zDC/g71N2zb1klXypSNpnkb/Ki9ZniJd0AQq2vxj4i0rguZZSM2HyMgnQnmAUU/HHbZGExGVQ6qqZl2xdVp3PZMZiQKJvIoVFqev4CbHr1Mite0cy2aYcb8iGnAdGYBL8Q2YahPyL3+dgHmi6/ywY3pmo9w+4O+JDggH3O7Mt2rlgbEQAaR0qLafrRU0yTB54Xyk7CNQE4kV1oGzl+wIO0LBBpDnuQAqenvuh7ac4W3kil3fbjVs9lk3JiH9q0Wb9gQ50ZE9T00RM/VhSDacfnmghY1udXhgAThMrNXeOjQ3m0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.1
Release Details
UpdatedApril 8, 2026, 11:53 a.m.
Changelog

Added

  • Support contact settings — New admin settings section for configuring organization name and support contact details. Contact information is included in telemetry for easier support identification
  • App Store screenshots — Added calendar widget screenshots (layout, editor, primary, sidebar) and updated admin demo data and edit mode screenshots

Changed

  • Contact info updated — Author email changed to info@voxcloud.nl and website URL to voxcloud.nl
  • Admin settings refactored — Extracted support/contact settings into dedicated SupportSettings component for cleaner code organization

Security

  • serialize-javascript upgraded to 7.0.5 — Fixes excessive CPU usage vulnerability in array-like object serialization during webpack build process (#42)
  • brace-expansion upgraded to 5.0.5 — Fixes bracket handling vulnerability (#40)

Fixed

  • Demo data imports all languages — Demo data setup now detects the single active language and imports only that language's content, instead of importing all available languages regardless of configuration
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureaKR0xRRjvews2FOdXJ446XMnOvUrRh3oPx3N7dR/TGujbDnjFFXwF8qC7wXo9CrwLD164arXII26lxxH509xmimeAfARht3+m5iFU8X2UdeWfszCJtuf2TilPEp+3ZDcgKOpN3o9dkcas6hV7rYfsqVJTkLAPqvAhOA3lRQOM70SKV8P5Jo3wSKHiXocbdsk094u2jd640LIR3EFfkdCrzxQJ9KetiH3w+h135bz1qwU8/eceKTH+O9aHYtphsbfFqRvZzMqnZ3qEABfWzSdOMgkvSIrpYZDWy20aPi1vagdi9VtLBzuzVNvmzjLKcCu3HNdJ2mrITGFykR1JM+EKG5AmdoIovqjunLgwpoCQCmLYnvhLegYfsIz1MbG0mgfJ1ZeHwW/DI/9usLGtlNOwRqJjaL9WIgT2zk4wPkG0P0N8f+i/S4limsWXHilNlqj7nZJWQftBm+UoecxZ4hewwGbQZZIGdBDIFkbKV3JPsnN8y6OXohEIAWXfgy66SXM5n2KdYVlFAiMyAcIPWkab+ZjB/o+jrpkGuC/9+eJ0fTd8LAwSKzupt4hTCqmmru5t2Or/6YSEZxl3LlghWtC3ivSefxvqLuKy95vPVmT+ylOPohgmzUxPzlOHHcOp/N9YIP3YSWwMZ2cDbvAI4PeZD3UjHpnhm3t9q8lHOrygyk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.0
Release Details
UpdatedMarch 29, 2026, 7:49 a.m.
Changelog

Added

  • Calendar widget — New widget that displays upcoming events from shared Nextcloud calendars. Supports multi-calendar selection (merged view), configurable date range, event limit, and show/hide time and location. Events are shown with colored date badges matching the calendar color. Recurring events (RRULE) are correctly expanded into individual occurrences
  • Responsive calendar layout — Calendar widget automatically adapts to available space: 1 column in side columns, 2 columns in medium containers, 3 columns in wide content areas (via CSS container queries)

Fixed

  • People widget users lost on reload — User IDs containing dots, @ signs, or spaces (common in LDAP/SAML/OIDC environments) were silently stripped during save, causing selected users to disappear after page reload (#41)
  • Deploy script OPcache — Added Apache/PHP-FPM restart to deploy script to clear OPcache after deploying new PHP controllers

Security

  • Rate limiting on public People API — Added AnonRateThrottle to the public share endpoint for the People widget to prevent user enumeration

Documentation

  • Language & demo data — Added guidance that Nextcloud language setting must match the imported demo data language. Added troubleshooting entry for "Admin sees empty Welcome page after demo import" (#37)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureZBIZ5aIC0Jf+cgyuNd3xYfy7lZbE7fbg38Xem2/zEuWkI5PWOSY/WmCebThcm9NHRdFJIL74zHRIUbfE2XaicmcqwgSZozNcUeUG8kpK5elRhLYJXPdPZMAN1LpKiPlrz3951koLc2f0LNpTvOBvsXgk0Fjlsj/NRmYcn6Oy224uzlYrkwpwBn8UDRA6CBC8qJLG+TYF4/VnIfJLEomG01HV9Ar2TGb+dDUobWPWAgfXfkdNtrc7gfLPipGlAs8enaBWbEhLQi/qRVfU2W1azSTYzFgl1rwBMnFG5V9g8ymkZpakbioOnL074u9JUYwBIcXGSq+7w9oKo5LFmzidPmSALp8B12aM+lAElH/vBKlHBYSoDv3A/KoqWfXW5BZvXQXmtFa043vK0kHD5M0PARFfvPN7xkVXUYoQX5o9Ptre/I+UkINXO6FX7X4KepWM57WFVidCOMwwCl9e6b5UQdt6aeYSl1qoAnBNQgAxtYm2QgRJa9FyDEl4+yup+bBwrYU8URBCQJk6GTbAFaA5397wE12N3OLpwoiIx3g7ZBP+ppRmO1eb1SDGN9tJWa5AKgEg7CBnBaV5YNtWRlmoUfsgfCt1b039Dca7fEVcL523m5zgmxqkiCbO70fwlTdhoe00hQpcZomfmEP6wB7FftWIqMR63Ndw+7WmoGIouhM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.1
Release Details
UpdatedMarch 9, 2026, 3:12 p.m.
Changelog

Added

  • IntraVox Editors group — A third permission group (IntraVox Editors) is now automatically created during setup with Read + Write + Create permissions. This provides a three-tier permission model out of the box: Users (read), Editors (read/write/create), Admins (full access)
  • Scenarios documentation — New SCENARIOS.md guide with step-by-step recipes for content approval workflows (using the Nextcloud Approval app and MetaVox) and department-based intranets

Documentation

  • Updated ADMIN_GUIDE, AUTHORIZATION, EDITOR_GUIDE, and README to reflect the new three-group permission model
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQuql4/Qdcw6lDxelq5UHCLVmlFf7+6YjcNPpfIDS+ynsrL+9QbyGsGQyx8fZdisovKtKJODYvfEou6EmcdD8l14mvBc4P6v6PZwzRmgP3qGMG4fYX0lFfniULGs8YGtKVGtgqilJ1gLnHQrO4qIxQqvvNGtTKmr8N3GehbHprT/tTzgPTlhmIHPIjKrw6q5m380WyUBhq9Hw9o16MekCX5obAshT2pwQuQvkmEYuprV4wr3dFOqKC5vM04yd1x6s2y72ZLcCC4YDPRoMP75vClpQaaScIYwVoulnFlLqOZUw/qlywWttwMAalDJkRPmC3E08xlOup4RwZkGSdu9jv5ESDemPoxvtV4alDMkf/qECW8KZkjTEX89MuYfFLK7POiH68qJllpAooquc71PAdN/YmTtKPplKBKqiJwWReAgDK4dZdls1komf17vcn+usYsJhzVT5Jarp8jjT0aQpBFAUDIuEJmeF0nzI/Q0xV1bMeCs/j2yjDdSIJPLHr27uk68Tb+gBQbhYdpPR6sYxLT2DT3xbbvq9z3RPlowcO3/kvN71ojGEx6xPGOsISJbRDpg4v3ixzVaKa9nUurb44Hsp7E1GsF19ARAlEquCuJxkCXONHc4jjW0pPGUxyBAt5V4kvWqRhS9Whl1JjSWOd7X30GvShRSWwWu59BiaTpI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.0
Release Details
UpdatedMarch 8, 2026, 10:37 a.m.
Changelog

IntraVox 1.0 marks the first stable release. After 19 iterative releases, the app offers a complete intranet platform: a full page builder with 10+ widget types, page versioning, templates, public sharing, RSS feeds, engagement (reactions & comments), draft/published workflow, concurrent edit protection, and multi-language support. The JSON page format and REST API are considered stable from this version onward.

Added

  • Page locking — Pessimistic locking prevents concurrent edits. When a user starts editing a page, other users see who is editing and the Edit button is disabled. Locks auto-expire after 15 minutes of inactivity, with a 60-second heartbeat to keep active sessions alive. Locks are released on save, cancel, navigation, and tab close
  • Lock safety net in API — Backend updatePage() rejects saves with HTTP 409 if the page is locked by another user, preventing data loss even if the frontend check is bypassed
  • Force unlock for admins — IntraVox Admins can force-release a page lock held by another user (e.g. after a browser crash). Includes confirmation dialog to warn about potential unsaved changes
  • Draft pages (#32) — Pages can be saved as "Draft" or "Published". Draft pages are only visible to users with write permission and are hidden from read-only users, public shares, search results, RSS feeds, and the page tree. Editors see a clickable status badge in edit mode to toggle between Draft and Published, and a "Draft" indicator in view mode. Backward compatible: existing pages without a status field default to Published
  • Duplicate row (#32) — Editors can duplicate a complete row (including all columns and widgets) with a single click. The duplicate button appears in the row controls next to the delete button
  • Sticky edit toolbar (#32) — The header toolbar with Save/Cancel buttons stays fixed at the top of the viewport when scrolling, making it accessible on long pages

Changed

  • Page lock translations — Lock-related UI strings translated to English, Dutch, German, and French
  • Draft/duplicate translations — Draft, Published, and Duplicate row strings translated to English, Dutch, German, and French
  • New pages default to Draft — Newly created pages (both blank and from template) start as Draft and automatically open in edit mode so editors can begin working immediately

Fixed

  • Links widget tile overflow — Tiles in narrow containers (sidebar, small columns) no longer shrink to unreadable vertical text. Tiles auto-wrap to the next row when there isn't enough horizontal space, while respecting the configured column count when space allows

Documentation

  • Editor guide — Added sections for sticky toolbar, page locking, draft/published status with visibility table, duplicate rows, and updated creating new pages workflow
  • Admin guide — Added page locking and draft pages sections, updated security considerations
  • README — Added page editor features (duplicate rows, sticky toolbar, page locking, draft/published), new feature sections with screenshots, updated security section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureiNaCstuvlWhKDNWHxOI3UH2urSyZ8OZCmlMAvQHWW8FDbfo3gBmHCD7ofk/6G78se/+9K8bLaSPMd0f3n3enR62K0ZG0jj5TP4eVvIsVYpVlLdzZlV64fJRcFSUotMFaluWlflLPKhuJbPJTCLivaYwzxX8QhfG7f9SUgZcsb/YZrCU0exRzekrFevLtHNsVE5aj7UWGg3lQh/zYZ28tlpsoWUPCJ2dT4qQ56kFO6IYvc4Wmf2diEzLLye1XaVpLaBbldRfDt2b4siu3uUMPePJHij6EDYL1dQAPuYAa12slvrh9TTRlffbtU1ny3b+1t9yLAVBiE6NEFccX7S/P5pmEPNmoeCECIv8lTyw8GJUeRNT+VdmlOZporvVXn4CWhW4aaQW+qVMLUrKrQ4Ond/ZYmVyVR4TjKiGZr04hr/xIdj0FDPffqe3SiLS5DJ4g3P+q3CCI7vktKlIdOrgpyHFavOfTq9IT2MT94UfJFob8L34g+yDsfdyQdYC2hQTXZsQUJ9TS72pzUC4c52Y4gomtLyUh4E7xOv8hAiGiKvaCDlcQJD7jE95LKw+EEwMvXrDMfhgn8hHMg9JxzSapRggu59B5Butz83jVNRnTWht9gaGu3nlpvMnNoE0YdFyU2c1yj0w5DoB7VmKd+4+1S32aO97qba7DCBpqrdQYc8o=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.18
Release Details
UpdatedMarch 7, 2026, 11:51 a.m.
Changelog

Added

  • Spacer widget rendering - Spacer widget now renders correctly in view mode with configurable height (10-200px). Previously fell through to "Unknown Widget Type" error display
  • Links widget tiles layout - Links widget now supports a tiles layout alongside the existing list layout. Tiles display a larger icon (36px) with a separate title and subtitle on two lines, creating a card-style presentation. Editors can switch between layouts and set title/subtitle per link in tile mode
  • 30+ extra link icons - Added icons for common intranet use cases: folders, chat, dashboard, contacts, forms, code, support, security, organization, news, and more
  • 5 unique demo showcases with rich, diverse layouts demonstrating all widget types:
  • de-linden (Universiteit) — 4 photos, 1/2/3/4-column rows, video, people grid, SURF services, right sidebar
  • van-der-berg (Advocatenkantoor) — 3 photos, header row, news grid, file widgets, no sidebars
  • gemeente-duin (Gemeente) — 3 photos, 1/2/3/5-column rows, left sidebar, news list
  • de-bron (Zorggroep) — 3 photos, 4-column department overview, people cards, video, file widgets, right sidebar
  • horizon-labs (Tech startup) — 2 photos, news carousel, culture row, right sidebar

Documentation

  • Showcases guide (SHOWCASES.md) — Complete documentation of all 5 showcases: widget coverage matrix, technical structure, background color guidelines, image handling, and people widget portability
  • Editor guide updated — Added documentation for file, spacer, news, and people widgets; updated column support from 1-3 to 1-5; documented collapsible rows, header rows, and side columns
  • Export/import updated — Widget types list expanded from 6 to 10 (added links, file, news, people)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCnOojEkcaYY3IrqfW3cj9gDhgOnlVkTd+sZpTFow4jh1pH+IrZ1NgXRjGgIKZiQtdvlh3AqgHdEE7kWidNvVTps4SL79TTLcQlO+aT223Sf9OOMC+GQsGkxUVKVY1d456mupVrZyslUCopbxr4Rf2aYxfsm3GFdMxPFGByXWE4VkJztuo8UI4krp2rfVRcBbv2m8RWd2w+1mAlkOiRK7176eS+d4jHn0h6Kslde5E/E4DfGML8uUyyu5yACJ/MMkUcJ+wxLvu2esOM5oPkbMrAHpWCa5TRzqVtbpoplcmDq4pYVw84AXc/+V91HduZOVLHgzWXhkV6O0qXjsWgsDfAPiZ1t9EWFuUMuV0EY2WbIxdo5eBSQsDaG4R60JKVlUvbx07OXecWG80VRslsngbXbTtvWV/AwHGWN60MufTQbEU8+cw3tIBD5RAlXwcnIVDHawBvasxQ7wlWU5/B8BZZkEDGdQMBlXTQE45+FVEbwXOaaQPD8s7cde2zCGk7Ze4MfIqZDyD5cBuszuVf5ljCpm8BQvt4oBGRPX9C0K8TB+l3vp6XzuMOvxixdIES9E20e9LYn1Yve0tTf3PzBQgUvPM4eYjXHD3U24w/0PNPNrBtLzg0uePqmm01dHBkVTqQC4CdmLD/cRG7GIH8bVBey+9XsftagMXH2LGuz8NS8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.16
Release Details
UpdatedFeb. 25, 2026, 1:50 p.m.
Changelog

Added

  • RSS feed - Personal RSS feed for each user with token-based authentication, feed media endpoint, conditional requests (ETag/Last-Modified), and brute force protection
  • RSS feed settings UI - Generate, regenerate, and revoke feed tokens with configurable scope (my language / all languages) and item limit
  • RSS feed sharing policy - Feed respects Nextcloud's "Allow users to share via link" admin setting; shows clear error when disabled
  • RSS feed cross-language links - Feed items link via #page-{uniqueId} format, automatically resolving pages across language folders

Changed

  • Dummy text generator - Removed =dad() alias, only =dadjokes() and =lorem() are now supported
  • =lorem() rich formatting - Now generates richly formatted content showcasing all text widget capabilities: headings, blockquotes, bullet lists, tables, ordered lists, and mixed inline marks (bold, italic, code, underline, strikethrough)
  • Dummy text multilingual labels - =lorem() section headings, table columns, and status labels are now localized for EN, NL, DE, and FR
  • Documentation - Added RSS feed admin setup guide with GroupFolder permission requirements (Read + Share), ACL examples, and troubleshooting

Fixed

  • People widget "Invalid Date" - Birthdate now correctly displayed regardless of Nextcloud locale settings. Added backend normalization of locale-specific date formats (DD-MM-YYYY, DD/MM/YYYY, DD.MM.YYYY) to ISO 8601 before sending to frontend, with additional frontend fallback for edge cases
  • RSS feed empty for ACL users - Documented that GroupFolders requires both Read and Share permissions for public feed endpoints; updated all permission tables and recommendations
  • Webpack build failure - Added string_decoder and buffer to webpack resolve.fallback to fix build error caused by @nextcloud/dialogs 7.3.0 pulling in Node.js core modules via sax/is-svg
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLkqXT+TE7U884io7bEDmL/gZLvaShUTg97nU7qIjNMBXEkd4nqo9nooA8+Y8qLUQEIjP1wFkw2p/TMduDHbWgZcPe+SIDuvfyQhqSlO5aeD8Q+pW+KmGAy0XbbQlVX6neiqaNGhD8TpCdnIStIHuPkjRngBSOuXf4JjeV3DNM2QKlck2at1svnElJOWujwLerTqWVGWQEaXSBvn0YGAHiLorgKXVitgZRMOxviUeSTxdWtwNsJ3vVIZ+mr+4UllElQh1jLgnePi2xa3DXs3b+r9CqebhIIQ2Brt8r0U2l3W5LIsjZJtf+/PHf9ytfAag51+XHLb/xMEZx9NDxakeGZlDPdQ652np7z7jgUxwE/wASSpVJ4LePTzwoBrdg4EDocI114Gtz0vqJGoTOJBHxZEovydDEXjOZSJcnLvzpfs1nkQBQYUvQGzSVti+0W64vSCh/I53o/U7GRYmCL03pYbNYZ9S2nk32usjfFizVbpGvKFrA5crLqxBns5Yb6bYY5QNtZtqHJiobkijwP19esHX6eCNLIKvI6aozaMtpawOQ/IDCDdJFI7N1+QFcoMgUsbbpfBXhImJ1I3LjWOjbzl+ZQ4d6CrHC1Gmd/KohKuvx5ER7RmgvLIhpgEEAKvdpFxgBc2gnQeVwTLUOBlzjJhS+I+7ggkrmX7+5HarwP0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.15
Release Details
UpdatedFeb. 19, 2026, 6:35 a.m.
Changelog

Fixed

  • MetaVox sidebar on NC33 - MetaVox metadata tab now works in IntraVox on Nextcloud 33, where MetaVox registers via the new scoped globals API instead of the legacy OCA.Files.Sidebar API
  • MetaVox mock Node object now passes correct mountType and mountPoint attributes (camelCase) so groupfolder detection works properly
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signatured13CndlYRWziam4mAOeDoHdjExboNyPiyFqfTRdrqRtcJkWVhRE0vN7wCEpWqUZaAni+r5JOpmwhpD7ePTFB8j77sIMq2K2ahdeGOVhnRrhQ3Qk055iXrnxzm3lvwaaerShVPa9D5fga3auYwpcuJxW4NDj36QvCwybkhwzJx381shlVjGyuZKQFJJWn3d3ZAzC2u1El8OlLIeBEDeszJizpa3EBEGdftZ7sfqkem+UMU9jWOGrXMwkYsauDhp+0mW6TNb7lDV84gZUKoE9lAYYLTPzFU5VWDA2mtvV6h09kwtZrXfkMxoh+S/qAcFkP9gwXFHKZKCDs3Z/HGTqeDxrbW6EM5sboYLOS7+VQapwes/UsGRO3XO9jzo5cfe4+c6fy32mjgwyhskSBm5UYdpYANsRgvOj0D9GQFNLYSuktoHaV0lq7BAtroDDk7B09k/422Eia0taM9PuoTmbMZ97yhgYZpEyJMLVx4nTMu30zXXkw0fkF3KfF0vZMnsOaAgYfQWXzChqpOlvemmz7bx/Ew7Murqz5ytaXfZvQ09WtWEV4l1b4AdCaf1ow/+w+V5BtXM/tCvaUmjQtdK+mf70ptdCr/+crxjhytihIm+NFMZSB/FMNlOKGcM3J0wz/kcBJ6tCLAcCIjzaf9p+42yUo8bgi+WzJTNp0r6EZSLA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.14
Release Details
UpdatedFeb. 18, 2026, 2:07 p.m.
Changelog

Added

  • Nextcloud 33 support - App now supports Nextcloud 32 and 33 (PHP 8.2+ required)
  • Page nesting depth increased from 3 to 5 levels for deeper page hierarchies
  • Dummy text generator (easter egg) - Type =dad(), =dadjokes(3,5), or =lorem(2,4) in a text widget and press Enter to generate dummy content (inspired by MS Word's =rand())
  • Birthdate field support in People widget - display, filter (is_today, within_next_days)
  • Bluesky social link support in People widget
  • Date filter operators for People widget: is today, within next X days

Fixed

  • People widget display options now correctly control rendered fields in grid layout
  • Removed gridShowFields override that forced fields off
  • Removed hardcoded layout !== 'grid' template restrictions
  • Removed CSS rule that hid headline in grid layout
  • showFields is now the single source of truth across all layouts
  • All display option checkboxes now always visible in editor (no longer hidden per layout)
  • showFields whitelist expanded in backend (PageService.php) to support all 15 field types
  • Legacy title field synced with role for backwards compatibility
  • Heading widget bottom spacing increased
  • Comment cascade delete now properly deletes replies and updates count
  • Security: markdown-it updated to 14.1.1 (ReDoS fix in linkify inline rule)
  • Security: ajv updated to 8.18.0 (CVE-2025-69873 ReDoS fix)

Changed

  • Twitter links now point to x.com instead of twitter.com
  • Dependency updates: axios 1.13.5, qs 6.14.2, webpack 5.105.0, ajv 8.18.0
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureKx4wBbCHSaA+wD5HWQ0/arQjdIOdtmxLwRYyh1GhcBKDiUVrfNUoFlOreUrs/FPv6heMXFD8XdJcVn6XXxPZzSOAYVCnKaIGGYea4RfsTlCbrShkasX2TxQ/1Kn1vH2QM+qe0aNdZstYv1QxhFgQyb82tWreFTuhisKgndvWqE5LouHSIDzamgr+iKmEoxf/LvCbPt4UvWc8nQdCc+XdnDa7WzMrjAB1xu5tHXE3coFmEqAWUwdMpp+vR9YanFLjC8CKfJEl+S4qL0DhDviXXUzjlOmIEttrXwRI1nv5rLg+Ucy1fBdZPUmMLXqgh7eUTWCSAlTVsTPYMvdhNQAZMWpioKf7X7pZcbp9JvcmbTZ6+VJVIT8tGGJROwpx/Z8v1fN3e5Gcv+pSq0yHpKM43v2S8LSa+Z5HB7BIV5GeUCmSIGfrWYEJvXYhpHtyHJrdVYfH2YuYbqkAH5bKuURwKQdJ0Y6A9v/gpEdwso44dNpPh0CY2uaGk/FwrJs1IYYmCI59OqF6l1/ffo9l/jR+PA5Jh3nns9lUR+hhfTJ25hF3+xhYdQV818Acbnl24c59rugq7+hX++cVn/b8VXen5WIUdVK4nl8eHNSYYVJoRLoz0PqhEVitwSF9k6zU+6/kSWIe2UiEwiOALXTSS89q+TVRT1J1oX1L//SPTg0b988=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0

Nextcloud 32

IntraVox 1.6.0
Release Details
UpdatedJune 13, 2026, 11:59 a.m.
Changelog

Major release with three themes: Nextcloud 34 compatibility, community translations via Transifex, and admin-curated language activation. Plus PhotoStory lightbox fullscreen + "Open in Files" originally drafted for 1.5.6 are folded into this release. No data loss on upgrade — existing installs keep their four configured languages enabled by default.

Upgrade safety contract

This release respects seven rules so existing installs cannot break:

  1. No language folder is ever deleted automatically — not on toggle-off, not on upgrade, not by cleanup.
  2. Default for installs upgrading from 1.5.x is ["nl","en","de","fr"] — exactly the previous hardcoded set.
  3. The Version10600 migration only seeds the config key; it never creates or removes content folders.
  4. English cannot be disabled — it is the guaranteed fallback for every code path.
  5. License page-counts stay per-language and are not reset when a language is toggled.
  6. Cache invalidation runs automatically when the admin changes the enabled set.
  7. occ upgrade from 1.5.x → 1.6.0 produces zero user-visible changes (until the admin acts).

Added

  • Nextcloud 34 compatibility declaredinfo.xml now ships <nextcloud min-version="32" max-version="34"/>. Audit results: zero removed-in-NC34 OCP PHP APIs referenced in lib/; all five OC.* JS globals IntraVox uses (OC.dialogs.filepicker, OC.MimeType.getIconUrl, OC.L10N.translate, OC.requestToken, OC.webroot) remain functional in NC34 stable (deprecated, scheduled for migration in 1.7); bundled @nextcloud/vue (9.8.1) and Vue (3.5.22) match NC34's ship versions; PHP >=8.2 matches NC34's >=8.2 <8.6 requirement.
  • Transifex-ready translation pipeline — IntraVox is now packaged for community translations via Nextcloud's Transifex pool (o:nextcloud:p:nextcloud:r:intravox). New .tx/config + .l10nignore + l10n/.gitkeep + committed POT template enable the Nextcloud l10n sync-bot to open pull requests with new translations as they land. Resource provisioning requested via docker-ci#951. The four existing languages (NL/EN/DE/FR) continue to ship in l10n/*.json until the resource is online.
  • Admin-curated language list — new "Available languages" section at the top of the Demo Data tab in admin settings. Each language IntraVox ships a translation for appears as a checkbox; the admin ticks which ones should be active in the intranet. Disabled languages disappear from IntraVox menus, navigation, and the demo-data table, but all their content stays on disk and reappears the moment the language is re-enabled. English is always enabled and cannot be unticked.
  • Empty homepage on language activation — when an admin enables a new language (one without bundled full-intranet demo data), IntraVox creates an empty homepage in the content folder so the language is immediately usable. Idempotent: never overwrites existing content.
  • New LanguageService, LanguageController, LanguageHomepageService under OCA\IntraVox\Service\* and OCA\IntraVox\Controller\* — the single source of truth for "what languages are shipped" (auto-discovered from l10n/*.json) versus "what languages are active" (admin-controlled, persisted in oc_appconfig.intravox.enabled_languages).
  • PhotoStory lightbox: "Open in Files" button in the lightbox topbar, plus a clickable filename in the details panel. Both open the photo's parent folder in the Files app in a new tab. A new server-side endpoint /api/photo-story/open-in-files?file_id=N resolves the user-relative parent path (including federated/GroupFolder mountpoints) and 302-redirects to the Files view — the API's path field is storage-internal, so building the URL client-side would 404 on those mounts.
  • PhotoStory lightbox: swipe-down-to-close on mobile — vertical swipe over 100px closes the lightbox, alongside the existing horizontal swipe for prev/next.

Changed

  • All hardcoded SUPPORTED_LANGUAGES constants replaced — 12 services that each defined their own copy of ['nl','en','de','fr'] (PageService, DemoDataService, LicenseService, NavigationService, SetupService, FooterService, SystemFileService, FeedService, OrphanedDataService, ExportService, PagePathHelper, plus 2 OCC commands) now read from the central LanguageService. License page-counts only enumerate enabled languages; RSS feeds only include enabled languages; the orphaned-data scan recognises any language that's ever been shipped or enabled so it can never accidentally flag legitimate content as orphaned.
  • Navigation fallback unified on EnglishNavigationService::getCurrentLanguage() used to fall back to 'nl' for unknown user-locales. It now falls back to the universal English default, matching the rest of the codebase and the Transifex source-of-truth.
  • SetupService upgrade migrations now language-awaremigrateResourcesFolders(), migrateTemplatesFolders(), and migrateVersioningFolders() now iterate over admin-enabled languages and skip language folders that don't already exist on disk. The result: occ upgrade from 1.5.x → 1.6.0 touches exactly the four folders the install already had, never creates phantom folders for new Transifex-discovered languages.
  • Demo Data tab filters by enabled languages — only ticked languages appear in the install-status table. The "Full intranet" content option remains bundled for NL+EN only; other enabled languages show "Homepage only" and use the empty-homepage flow.
  • POT generation uses Nextcloud's official translationtool.pharscripts/generate-pot.js is now a thin Node wrapper around the same binary the sync-bot runs (create-pot-files task). Zero drift between local extraction and what Transifex sees. Replaces a custom en.json-based extractor that produced inflated POTs containing ~820 stale msgids the bot would have stripped anyway.
  • Plural-form overrides for JA/KO/ZH/TH/VI/ID (1 form), FR/PT (n > 1), PL/RU/UK/CS/SK (3 Slavic forms), SL (4 forms), AR (6 forms) — ported from IntroVox's regenerate_js_translations.py so non-Germanic languages render correctly when their pluralForm field is absent. Without these overrides Asian and Slavic translations rendered with the wrong plural rule.

Fixed

  • PhotoStory lightbox: Nextcloud header overlapped the topbar — the lightbox sat at z-index: 100000 but the NC header (z-index 2000) stayed visible because parent containers create stacking contexts (transforms/filters) that trap position: fixed children. Wrapping the template in <Teleport to="body"> escapes the trapped context; the lightbox now genuinely covers the full viewport.
  • PhotoStory lightbox: date/location pill unreadable against light photos — the translucent pill background disappeared against bright photos (white walls, snow, paper). Darker background, stronger backdrop-blur with saturation, subtle border, heavier drop-shadow, plus a text-shadow fallback for browsers without backdrop-filter.
  • PhotoStory lightbox: body scroll-lock on open — the page underneath could be scrolled with the trackpad while the lightbox was open. body.style.overflow = 'hidden' is now applied on open and restored on close.
  • PhotoStory lightbox: iOS notch / Android status bar in fullscreen — topbar now uses env(safe-area-inset-*) padding so the close button doesn't hide behind the notch.

Removed

  • Stray l10n/*.po files — replaced by the canonical Transifex output path translationfiles/<lang>/intravox.po. The PO files in l10n/ were never used by the Nextcloud runtime (which reads .js + .json) and only created dual-source confusion. Bundled translations remain in l10n/{nl,en,de,fr}.json until Transifex onboarding completes.
  • PageService::SUPPORTED_LANGUAGES constant — and 11 sibling constants across the service layer. All logic now routes through LanguageService.

Internal

  • New migration Version001600Date20260609000000 — pure config-init, seeds intravox.enabled_languages with the legacy default on first upgrade. Idempotent.
  • PagePathHelper stays a pure helper — its language-code set is static-class state synchronised once per request from Application::boot(). Avoids piping LanguageService through every caller of a previously side-effect-free helper.
  • AdminSettings initial state expanded — admin UI receives availableLanguages, enabledLanguageCodes, and defaultLanguage server-side, no separate fetch needed on tab open.
  • RELEASE_CHECKLIST.md rewritten with the full Transifex pipeline diagram and two adopted IntroVox v1.7.1 gotchas (GitHub-bot divergence, near-empty-language conflict resolution) so the next release doesn't repeat IntroVox's mistakes.
  • scripts/generate-pot.js rewritten as wrapper around translationtool.phar (downloaded + cached under scripts/.cache/ for 7 days).

Notes

  • The first Transifex sync PR will land only after a Nextcloud team member provisions o:nextcloud:p:nextcloud:r:intravox on the Transifex server. A GitHub issue on nextcloud/docker-ci requests this. Until then, translation files remain manually maintained for NL/EN/DE/FR.
  • Disabled-language pages don't count toward the free-tier 50-pages-per-language limit. This is the intended behaviour: organisations get back unused-language capacity once they curate the list. Re-enabling a language re-counts.
  • The bundled LANGUAGE_META map in DemoDataService still hardcodes display names and the "has full intranet demo" flag for NL/EN/DE/FR. New Transifex-shipped languages will appear in the admin UI with their base code as the name (e.g. "es") until they're added to the meta map. Cosmetic-only; activation and content management work either way.
  • Cosmetic legacy still in code: five OC.* JavaScript globals (deprecated since NC 26-30) — migration to @nextcloud/* equivalents is planned for 1.7. Works on NC32-34 today, may break on NC35 if Nextcloud removes them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTf7ZtlGWgI9TvkiQXT6xXf2fHFVS7KIq4LEB/evxDo4c/+mV4vL14flkwjF+dH6wtwnwbgjdFXGW3YPGcpWb5EU/ulDXwplwsPL3M+JxJGOgUtVR3DpMufuel27aggb9QKJeV1MGmlqyZivWUn9PgHtHciWghT1F2Xab3ui7YSFtC0UYlZm94f1J54payg2/5eQWZBr2odtZ0yIUc8IlIlYaYApDWcMr0NX52EX9DRFE33G0SqpB9L06WDu2BRxbesistv1KNp0IN6CDajkrs9dNPe0O6IIPW+9Ryo4oO2xjAzKKfwu+84egH611IkMhheumimFL7zeQZ3GE2VDQC26A/fE0S8Xo+uoHF63NliWIZvtvKPCDecHsVozYGoLm9Tdu3R+V1vNRgy8OeNg6VF1qNAup+YN6WFOxw+ftpKe526KCNHETQOdwp7JqEU4I0miYRJdo8GT6nEOC/MD4eBNsMLUxubt4iH1emd/PzvGPmUppF+iCudLzUCPYHG2xMyTDQprnW0hoBlb/9BCD3csE6lQwqwFsbzX+ITzd5PoMWbHX7Cy7AKQ6Izc3F2ZfAUrCVcoqFwAEiH3c/7RGRCXPxvQ2H50m9vKk8pn7gW8Lo5zu4E+66QaHUjUueLzeQd0AmHfCDdgbicqev0xrWwhk6wQsCLilRmLrpVdy7sw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.5
Release Details
UpdatedMay 30, 2026, 8:59 p.m.
Changelog

Patch release that fixes #57: clicking-save on a Link widget item whose URL is mailto:, tel:, or sms: would silently empty the URL on save. After page refresh the link rendered as #. No DB migration, no API breaking changes.

Fixed

  • Link widget: mailto:, tel:, and sms: URLs were stripped on save (#57) — Service\Sanitize\UrlSanitizer::sanitize() only allowed http(s)://, root-relative paths, and # anchors. Any other scheme — including the universally-accepted communication shortcuts mailto/tel/sms — was rewritten to an empty string at save time. The widget then rendered href="#" after a page refresh, even though the in-memory edit showed the correct URL until then. The Navigation editor used a different sanitization path (FILTER_SANITIZE_URL without the scheme allowlist) which is why mailto links worked there but not in Link widgets. Allowlist extended to include mailto:, tel:, sms: — three schemes with no JavaScript execution path, part of the default allowlist of DOMPurify and HTMLPurifier. javascript:, data:, file:, xmpp:, matrix:, and bare domains remain blocked. New unit tests cover both the accept and the continued-reject cases.

Notes

  • Existing Link widgets that lost their mailto/tel/sms URL still need to be re-edited and saved once — the empty value is persisted on disk. There is no automatic migration; once saved with 1.5.5 the URLs stick.
  • xmpp: and matrix: remain blocked. They are safe in principle (no JS execution) but unlikely to be intentional in most intranets; add per-need with an explicit code review if you want them. Open an issue if your installation needs them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCh/CmZ8aQnDr2XuBCui2CiOFzzX9RnHEHBISRDwUZISNfh8j+W8l9zbtlV5dsZ2tjgpT9EfMQCcK0O7Rms0xrEl7tGFWeGB4+3Nr6RlfhR59CFDtiXB1eg/mHhFR5uJBOB8CMhhhCTnN/dkD1np0PCRFJjDbn3lmij92xMOLMwFsaPAvhvRFA1wHn0cy+hUl5ZQyFDHivA7OLdadsh+eMth/Z0WaZJXvHuoWqbUFpGOMGzRmeeIYubZj5NsVslZg6gL93XSul9y5Jllh6IsMCcEwMLdhA3N+G9rLF9QzKUjev3aV1OzH+vVyY6LAhRYTN7k3bAZLOEt7HhuwA5f2bgEPbbjzNgW867foQA8HpAHeczfKSjbWiCOPCFhJ7q0OCIsAf9RJzCXHLUsBbSIDuxQyH35rd0sRL1qmg7hSikMBCs4G2d4/ajzZo34WA5k+R4WFmqhsJiMAm0By5ENBs9dVkAS+E6hxJruM9W/BevyftUjV/guD8YfLy1yByTuUICpA13pnJjo0rxFZmv6Iyo2uwDFZUVzag4RfLok80mXSY6icuKLWsH6mdX+7WaoT1n0v5NqFT38v7dVGG/DWZpF/edJSW5koAJMcr0gHTJ6h0wJzXFf+vx+1XOkJ/1184HStnxv9W9CabTkxRybcwHPwH7AtdH/GytDDG4qVi0k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.4
Release Details
UpdatedMay 30, 2026, 1:53 p.m.
Changelog

Patch release that closes an information disclosure issue introduced by 1.5.3.1, fixes a Leaflet/sticky-topbar layering bug, and brings the bundled @nextcloud/vue in line with what Nextcloud 33 itself ships so IntraVox widgets visually match NC's own apps again. No DB migration, no API breaking changes.

Security

  • FileStory / PhotoStory: source folder path leaked to users without access — 1.5.3.1 added a "You do not have access to this folder" empty-state that showed the configured folder path (e.g. Shalution/Administratie/2026) as context. For a user who is deliberately excluded from that folder, this disclosed the existence and naming of paths they shouldn't be aware of — path names can carry sensitive context (client names, project codes, person names, dated boundaries). The empty-state now renders a minimal lock icon + "You do not have access to this widget" with no folder name and no scan hint. The folder path remains visible only for users who do have access but happen to see an empty result (legitimate context).

Fixed

  • PhotoStory: Leaflet map overlapped the sticky IntraVox topbar on scrollPhotoStoryMap.vue and PhotoStoryDayMap.vue had position: relative with no z-index, so Leaflet's internal panes (default z-index 200–700) rendered over .intravox-topbar (z-index 100) when the page scrolled past the map. Both map containers now establish their own stacking context with position: relative; z-index: 0; isolation: isolate;, capping the Leaflet panes below the topbar without touching Leaflet's own z-index conventions.
  • PageDetailsSidebar tabs visually diverged from NC Files — IntraVox bundled @nextcloud/vue 9.5, while NC 33 ships 9.6+ with a refreshed sidebar-tab look. The result was a different (often "double-underline" feeling) active-tab rendering versus what users see in NC's own Files sidebar. Bumped the bundled @nextcloud/vue to ^9.6.0 (resolved to 9.8.1) so PageDetailsSidebar now renders identically to NC's own sidebar tabs.

Changed

  • Bundled @nextcloud/vue upgraded from 9.5.0 → 9.8.1 (within ^9.6.0 range, matching the version NC 33 itself bundles). No public IntraVox API changes; some Nc* components may have minor visual refinements that come along with the upgrade.

Removed

  • Obsolete .app-sidebar-tabs__nav border-bottom override — the 1.5.1-era CSS workaround in css/main.css was meant to fix a double-underline on NcAppSidebarTabs in NC 32+. With the @nextcloud/vue 9.6+ refresh that override became counter-productive (it removed the hairline that NC's new active-tab rendering visually anchors against, producing the misaligned look reported on 1.5.4-rc). The override has been removed; the look is now exactly what NC Files renders.

Internal

  • RELEASE_CHECKLIST: new section 1b "Dependency parity with Nextcloud core" — codifies the lesson from this release. Before tagging, check node_modules/@nextcloud/vue/package.json against the version NC ships for the target NC min-version (table maintained in the checklist). Visual canary: PageDetailsSidebar tabs vs. NC Files sidebar.

Notes

  • The defensive backend guard PhotoStoryService::assertNotResolvedToUserRoot() added in 1.5.3.1 stays in place. It already returns reason: 'folder_not_accessible' on the 404 response which the new empty-state branches on.
  • Known follow-up: News widget's empty-state still shows Source: {path} for unauthorised users. Same pattern, lower severity (source is usually a page-id, not a filesystem path); tracked separately.
  • Future direction: SharePoint-style audience targeting per widget will eventually let admins hide widgets entirely from users who shouldn't see them. The lock-state introduced here is the fallback for the edge-case where audience-target users lose folder permissions after configuration.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturebdeRHVR20/nH1R+zH2h19G2oU3imUS1G7ErSfoE76L06c1ZdJWAxX3IRoU0uXXw6g1riRPttaiwpkXuype8kPK/9mDqdXZT0WKUtYqSV+dkBjdpe1ODKCrXZhR4WZsDfGpuvzA68HeCYLTk5Zb9LgSwZIcwBfLDaAKK+DzgBuosLV/WepscTkKBAtjb0jOGyfYRQQRXScO4ywNS4Ke9kzTkvqpqlSgStQ8yMVer6cwb7/ToxjGhMSeUy7w0IKS69K2usogY79m28XVmLpaUp/5ky0BxA1+ggtv8Z9tdLCxy+G3S59ndDIXqgCXT6G1eShRFP7PuoQg3rJZK2rhM6hn2oOFX3ZUHDVE9hxpA2Iv67B3u1alq5ZYdmbtppwCFyFmUuOl5juZLHAZc5MG4T0USxIdgorxh2A2rBmuGAdrQk3vJlby8G+apL/hhFaZoUeBi1i7wFS1f62ucSJUKO6IAfAYJUxBDkIVFNboaZeRI30hPAa2yJGbYgAq2vuDuj1eGpewDQ65SNvaitI0LBjj0IQiPYs3DdnLVXDOqpva+VhaiQnA8Iq8TFK55tMyQiCn6QFNWCfTApT6L3W7X1j1GsiMutzjSS3GLLt27SeB/8948hXeR1JqcCLmiqaYt9C5KsbFH/UiMq6AGTungHCm4mxz1jSaGEAXBpsPlAqb4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.3
Release Details
UpdatedMay 30, 2026, 11:35 a.m.
Changelog

Patch release that fixes a "file no longer exists" toast when clicking documents in FileStory, and makes click-to-open behaviour consistent across all mount types. No DB migration, no API breaking changes.

Fixed

  • FileStory: "file no longer exists" toast on click for legacy shared-storage GroupFoldersFileStoryWidget.openFile() preferred OCA.Viewer.open({path}) for inline preview, deriving the path from file.path by stripping a leading files/. That works for personal storage and per-folder jail GroupFolders, but in legacy shared-storage GroupFolders the cache row stores __groupfolders/<id>/... and the user-visible mount-point name (e.g. Shalution) isn't carried on the row. The Viewer received /__groupfolders/4/Administratie/2026/Boekhouding.xlsx, couldn't resolve it against the user's tree, and NC raised the "file no longer exists" toast. Federated shares hit a similar dead-end via a different code path.
  • FileStory click behaviour now consistent across mount types — documents always open in a new tab via NC's /f/<id> handler, which resolves the right mount server-side for personal storage, both GroupFolders mount strategies, internal shares and federated shares. Removed the path-derivation entirely (resolveDisplayPath() deleted).

Notes

  • Behaviour change: clicking a document in FileStory no longer opens the inline NC Viewer overlay — every click now opens a new tab at the file's NC Files location. This trades inline-preview ergonomics for "actually works on every mount type" reliability.
  • PhotoStory is unaffected; its widget uses an internal Lightbox component and never touched OCA.Viewer.open().
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureAJvUlLcI5LNjLuz5DDx6QDyCAMh6j7PTBvzanLh5i26TsW2mHudGF/mCkxku08w9eJvE8ZY0VKFEzkLbbBc0v16RHQ1YO0slEGvbTv6QdrECl8JdmGwU0oDHpWAKlrGOeKRO0b9oDSu7D+Z1mVGlhxxMexJAnpugWDkevjeI1aznx0Di8FNa5KMxT9apIvceQfuHPbBOBPnE2BgjJMQTBWwR0sel8DYmdcd4y5FVKwY/3TlcTqzNLKwujDpqPt4Ihu4GVjS/dltaJqhSVlKJCiyh/w+kmB/RujnoEwLVru+GNhfgggvtr+YbQrwxoCqsoP1xiHeNoIA60/VCINwB0NkZHxXkrjGuTG7lInhzhEgwbl5sDg1JpG3BfQv1Z4R9VIHDXhCxyJT6oH7WbrssaUI0RlZQ2amYMu7a+FBe4+wHau4vD/KkvfOj62YZ6jPksvS140seB7IMYw9gxsw45bjjFS0COXGeIado8437PU17MBvwVGshcQHwdkwSyGTl3HWvXeQ5i4Gt9TiYTjjfmU4KFk83X8PcwB4qYho0yHLsMTZpdEApYTmLMkCrIKkJSk/mKnUQdiLkNnCjCTvZI1YvajTqzZxlNFy7IudFrvP6lyGosRum7OSdCACTQGSauuRMw7bB+J5x6aME6islckUuqmc9vxce92r6/brSurs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.2
Release Details
UpdatedMay 28, 2026, 5:52 p.m.
Changelog

Patch release with two production-blocking PhotoStory fixes (groupfolder albums and federated-file thumbnails), three UX improvements requested from real use, and one admin-tool clarification. No DB migration, no API breaking changes.

Fixed

  • PhotoStory shows "No photos found" for every groupfolder albumPhotoStoryService::extractStorageAndPath() returned the jailed Node path (e.g. Albums/Doris Synchroonzwemmen) while oc_filecache.path stores the unjailed form (__groupfolders/7/Albums/Doris Synchroonzwemmen or files/Albums/Doris Synchroonzwemmen, depending on which mount strategy the groupfolder uses). The SQL path LIKE predicate matched zero rows, the widget rendered its empty state, and the hint text misleadingly pointed admins at occ files:scan — even though the files were already indexed. The path is now reconstructed by walking the cache wrapper chain for the first CacheJail::getGetUnjailedRoot(), which covers both groupfolder mount layouts as well as any other jailed mount (federated, encryption-wrapped). Root-mode / enumeration also benefits — separate groupfolder mounts no longer collapse into the personal-storage scope.
  • PhotoStory/FileStory tile previews missing for federated files — NC's /core/preview returns 404 for any file on a Files_Sharing\External\Storage mount: the preview providers (Image, Office, PDF) need a local file path or a Collabora/LibreOffice render, and federated files only exist on the remote NC's disk. Result: PDFs, docx, xlsx and even jpg tiles from an OCM share rendered as a generic mime-icon instead of a thumbnail. New shared PreviewController at GET /api/preview?file_id=N&x=400&y=400 closes the gap: local files 302-redirect to /core/preview (no overhead, NC's own preview cache stays hot); federated files are handled by the new FederatedPreviewService which calls the owner instance's /index.php/apps/files_sharing/publicpreview/{token} endpoint and caches the result in appdata/intravox/federated-preview/ keyed by {fileId}-{etag}-{x}-{y}. Cold response ~250–400 ms (~5–15 KB transfer per file, not the file body), warm ~180 ms.

    Three protection layers stack to keep this scalable and friendly to the remote: a per-user rate throttle (UserRateThrottle(600/min)) bounds individual misuse; in-flight deduplication via NC's distributed cache ensures that 50 users opening the same uncached tile at once produce a single outbound HTTPS call (49 wait for the cache to materialise, then read); a per-remote concurrency semaphore (default 8 simultaneous outbound calls per remote host) prevents an IntraVox-server from saturating one owner instance and tripping its IP-throttle. When the cap is hit the request degrades gracefully to the mime-icon fallback. A companion POST /api/preview/warmup endpoint pre-warms up to 16 federated tiles per call; PhotoStoryWidget and FileStoryWidget call it fire-and-forget after every paged fetch so most tiles are already warm by the time the user scrolls into view. Bandwidth scales with viewed files, not with corpus size — fine on 1M-file federated mounts.

Added

  • PhotoStory: hide RAW sidecars when a JPG/HEIC variant exists — DSLRs and mirrorless cameras in "RAW + JPG" mode write two files per shot (IMG_5432.CR2 + IMG_5432.JPG) that show up as visual duplicates in any folder view. New hideRawDuplicates widget option (default on) groups files by (parent_dir, basename-without-extension) and prefers the browser-displayable variant over the RAW. Covers Canon (CR2/CR3), Nikon (NEF/NRW), Sony (ARW), Adobe (DNG), Fujifilm (RAF), Olympus (ORF), Panasonic (RW2), Pentax (PEF), Samsung (SRW) and Sigma (X3F). Implemented as over-fetch + dedup + slice so paginated infinite scroll stays correct; total continues to count physical files (honest source-of-truth for storage cost).
  • Sticky page navigation — header (title + Save/Edit) and navigation bar are now wrapped in a position: sticky; top: 0 topbar so they stay reachable on long pages. Previously a 300-photo Photo Story timeline forced you to scroll all the way back up to reach another page. Dropdowns/megamenus continue to position via getBoundingClientRect(), so their placement is unaffected.
  • Orphaned GroupFolder admin: show what's actually in the folder — the "Content" column used to render the literal "Unknown data" for non-IntraVox orphans, leaving admins to delete blind. OrphanedDataService::analyzeOrphanedFolder() now returns a sampleContents field with the first 8 top-level entries (name, type, size) sorted alphabetically, and the admin UI renders them as a small listing under the badge. The empty-state label also changes from "Unknown data" to "Non-IntraVox data" for accuracy (#56).

Notes

  • The PhotoStory groupfolder fix activates on every groupfolder-hosted album with zero config — existing widgets pointing at a groupfolder path will start returning their photos immediately after upgrade.
  • The federated preview proxy degrades gracefully: if the owner instance can't produce a thumbnail (no Collabora/LibreOffice on their side, or the file format is unsupported there), the endpoint serves a 302 redirect to the matching mime-icon SVG. No broken-image placeholders.
  • hideRawDuplicates defaults to enabled also for existing widgets (the param is absent → backend reads its default). Users with RAW-only albums can untick the new editor checkbox.
  • No DB migration; widget configs are read back through the new optional field transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturemyEi+pL/zo6IBucOaSFT5mI0lcpEe1D/O6I6fF/yEeHWYWnAeylyogGH5pDKz1TFn0b5mhCXPr2bwZDXRq4gkW8dpXkLVDPC9ox3kX/7jwULrvSzXbn7okB18UC0eGDvG3O0VXrVPl0XMveQCjlZ3GYvSi3p2mukoN6vKYXJazEwnioFhh18W39wUZ+/rxQz5MnQKfaWnOBisrv1Js1z4TAOITDII1gSnMcJFFWKepzSaUQbXNjsAjieaV0qshjTM9JAPZiAOGIQEJH6mGM60LgvV9czXdd5g5StTDinr2zK7O/kHe0qia5Z2GjmN50KrLAsmff7nFS4P2qDTov4H8p7Kw+qEClC+Wm0F6p/E3yZ7XWc3KkwU8vk96gXuYJ8yF4zCswLx4YAwSS1QvuACxQBnC+fF42jh/wXJpPylbMrJqeKKY3Ql24TTzUkSX+ZMweoQ4qkb3BQRQPQY/9pyiQrxc/OvpMdicJkl2IGIIYPG/5pLhTEZEZCXtlVRMpcO9LKzLzU1e+Otddyz3DsyXBwcTawwWknmZPhhD7fvSYpQb6dp0pgjWjBnoI7+YCcMI4sKONQUYrTzwA6eCjYRCiAcW30bTsUG27xHGvHT2cTg/JnNfaeYPIEVvWE+qCXKPON39QL/SMPfSJPrCMOptTuW35mpF4A/w4AF+BCq8k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.1
Release Details
UpdatedMay 28, 2026, 10:58 a.m.
Changelog

Patch release that fixes legibility on themed page rows and tightens a handful of widget rough-edges that surfaced in production after 1.5.0. No new features, no API changes.

Fixed

  • PhotoStory/FileStory contrast on dark row backgrounds — filenames, day-headers and meta lines used --color-main-text (dark) regardless of the row's background colour. On Primary (--color-primary-element) rows that produced unreadable dark-on-dark text. Both widgets now accept rowBackgroundColor from the parent Widget.vue (closing a gap with the existing widgets that already consume it) and switch internal text + tile surfaces to a WCAG-paired colour set via two CSS variables (--fs-text/--ps-text + their muted siblings). Tile bodies become a tinted-glass card on dark rows instead of cutting a hard white rectangle through the coloured backdrop.
  • FileStory tile filenames invisible on dark rows — regression from the same root cause: tile bodies kept their --color-main-background (white) while inheriting the now-white filename colour. Tile surfaces, hover state, preview-fallback bg and mime-icon placeholder all lift to translucent white on fs--on-dark.
  • Folder-path "/" silently collapses to empty after savePageService::sanitizePath strips leading/trailing slashes, so a configured PhotoStory/FileStory folderPath = "/" (root) was persisted as "" and rendered as "no folder selected" after reload. New sanitizeFolderPath() wrapper preserves / (and \) as a meaningful "whole drive" marker before delegating to the generic sanitizer.
  • 502/503 during page save — entering edit mode after a FileStory widget existed triggered four expensive folder=/ queries within ~250 ms (the legacy debounce). Apache workers saturated on large libraries. FetchKey watcher debounce raised from 250 ms to 700 ms in both widgets.
  • NcAppSidebarTabs double underline (NC 32 regression)@nextcloud/vue 8.x renders both a 1 px hairline on the tab-strip wrapper and a 4 px coloured indicator on the active tab, producing a stacked double underline in the PageDetailsSidebar. Global override in css/main.css removes the redundant hairline; scoped Vue CSS couldn't reach the data-v--tagged third-party selector.
  • Photo previews missing for common web formatsPhotoStoryService::MEDIA_MIMES was narrower than what users actually drop into their photo folders. Now also includes webp, gif, svg+xml, bmp and video/webm.
  • Empty folder picker returning "" instead of / — NC's OC.dialogs.filepicker returns an empty string when the user picks the root; both editors now normalise that to "/" so the configured value matches the sanitizer's accepted shape.

Notes

  • Default-themed rows (transparent / --color-background-hover / --color-primary-element-light) are visually unchanged; the new contrast logic only activates on saturated row colours.
  • No DB migration. Existing PhotoStory/FileStory widget configs are read back through the new sanitizer transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJUDu14MZav9zDCdwASLwOt9QfZFE4mkGdJjWn05l54CySpeTxrouul/CjST66UGcUmHOIM4gNXCBgrEkSACF0vpv1XWOWu6/PWHUmTsoZWretFLxxA/OXlcO6h3/Q0gHqS9TnIAxFCk1fnHbHHD3hGgYAnISLj6gL6s4axrs+h0/JpIon1ZMloUFxt3759D8Oc+LAgV5kNtYIndBkwb1BM89kb3Ri8NfCzZo3+5wo688lAty1cWjjqkOhzoxw6ERPWxRlek4XXB+4V/9a3wY0/gPWXdHb7YlSOgQpS2KB2m+F/YW64NUfCGOdTE8m/jAvw4Mz/ZDWVhtEk8vFgI3P3Sn1n4WxjArYYE5bChuDHa3A+G2sHZAWQ+/FRUHqExcaoK+mRXQGavoih9WkwVS2Bk9bJ6lKAVFwZgkvgD8YuKwiT9xe3tIhaFceYx1OZq90s6xqijZ6Upm6uoNZO8zwY28LwMJpxlOxqy0lyXVbhKQMb5cU9M80S2kmXbWCHJ1Tech4ZMpTdfZTP/MyoDtdqN9AczNCaMoxMRbW42x2FgNMDwBxszBV4q2mWa0LODiqo3X3AubXvJScBL62d3cWbHhGiEoiB4OJP99YlahBMOw8HoOebDrDYYCUnznz3Hh4GZoNFgWk+wtzrbR3Lu/TBimWHEkkYYQZAHr5mIWjsc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.0
Release Details
UpdatedMay 27, 2026, 8:57 p.m.
Changelog

Major release. Introduces two new widgets — Photo Story for photo galleries with EXIF, location maps and an Apple-style lightbox; File Story for document libraries with multi-mode layouts, MetaVox-aware filtering and federated-share awareness. Adds a fresh wave of perf, security, accessibility and l10n polish across the photo + file widget surface.

Added — Photo Story Widget

  • Four layout modes: Timeline (Magazine, Apple or Travelogue style), Highlights (auto-curated top photos), Grid (masonry), and On-this-day (year-over-year retrospective).
  • Lightbox with keyboard navigation (Arrow/Home/End/Esc/Space), slideshow mode with adjustable speed, focus-trap and focus-restore for screen readers, semi-transparent date/location pill that toggles a mini-map for geo-tagged photos.
  • OpenStreetMap integration via Leaflet: optional overview map per widget, per-day mini-maps in Timeline mode, and a cross-folder cluster endpoint for browsable map-driven storytelling. Admin-config aware (NC admin can disable all map features instance-wide).
  • EXIF metadata rendered into a details flyout (people, subjects, camera, location). Reads from NC core oc_files_metadata when populated; falls back to the bundled lsolesen/pel reader as a last resort with a per-request eager-EXIF cap.
  • MetaVox-driven filtering, grouping and sorting when the MetaVox app is installed. Supports cross-folder discovery mode (empty folder + ≥1 filter) for "all my photos tagged X across the instance".
  • Geocoding cache with periodic warmup job for fast country/location lookup on GPS-bearing photos.

Added — File Story Widget

  • Four layout modes: Timeline (per-day / per-month / per-year granularity), List (flat sortable), Tiles (visual grid with first-page previews and three configurable sizes: Small/Medium/Large), and Grouped (by file-type or MetaVox field).
  • Federated-share awareness — incoming OCM shares are detected per-file via a single indexed SQL join (oc_storages × oc_share_external). Federated rows render with a subtle cloud-badge and silently skip MetaVox-fetch since the remote NC has its own metadata database we cannot reach cross-instance. Mixed sources (local + federated under one root) keep full controls; pure-federated sources hide the MetaVox UI with an explanatory banner.
  • Configurable visible columns: Date, File size, Folder path. Date column can render either filesystem mtime or EXIF/MetaVox taken_at. Filename + file-type icon are always present.
  • MetaVox filter-builder, sort, group-by identical to Photo Story but adapted to document use-cases (e.g. group-by archief_categorie for compliance views).
  • Open-in-Files-viewer click target on every row/tile with role="button", Enter+Space keyboard activation and aria-label per item.

Added — Page editor & widget plumbing

  • Widget registration for Photo Story and File Story in the picker, with iconography and descriptive copy.
  • Editors for both widgets with folder picker (NC FilePicker dialog), live capability detection (MetaVox available?, source-federated?), sortable filter builder with type-aware operators (equals, contains, in, year_equals), and persisted widget config validated by PageService::sanitizeWidget.
  • REST API under /api/photo-story/* and /api/file-story/* covering paged listing, capabilities, MetaVox field discovery, location clusters, EXIF detail and range-aware video streaming (Photo Story only).

Performance

  • Paged enumeration via oc_filecache for all primary widget modes — no more full-tree getDirectoryListing() on large libraries. Hard caps (5000 cross-folder, 20k filtered, 200k count) prevent OOM on massive folders.
  • Federated detection is one preloaded SQL query per request, O(1) lookups per file. The previous IMountManager::findIn('/') per-file approach (cause of the 2026-05-27 saturation incident on nc-dev) is gone.
  • clusters, highlights and on-this-day endpoints now go through listPhotosPaged with sane caps instead of the unpaged legacy path that risked the same blast radius as the federated-detect outage.
  • filterFileIdsByScope collapsed from chunks × scopes SQL roundtrips to one ORed WHERE per chunk — at filtered-MetaVox-page scale this drops ~400 queries per page to ~40.
  • extractGroupfolderId memoised per node within a request.
  • Frontend AbortController on every fetch + fetchMore: rapid config changes no longer race stale responses overwriting fresh data, and pending requests cancel on widget unmount.

Security

  • Per-file ACL guard on the slice in MetaVox cross-folder hydration (buildPagedResponseViaMetaVox) using $userFolder->getById(). Bounded to ≤page-size lookups, so sub-folder ACLs inside groupfolders are honored.
  • Filter payload caps: 16 KB JSON pre-decode rejection on both controllers, value-length cap of 200 chars per filter, max 32 filters and 64 array values per filter — prevents pathological-input DoS.
  • Generic 500 messages on both controllers (no $e->getMessage() reaching client); folder-not-found mapped to clean 404 with empty-state payload instead of generic 500.

Accessibility (WCAG 2.1 AA)

  • Tiles, rows and hero elements: role="button", tabindex="0", Enter + Space activation, meaningful aria-label derived from caption/location.
  • Lightbox: focus-trap (Tab cycles within modal, no escape to background), focus-restore on close, counter announced via aria-live="polite", icon-only buttons get descriptive aria-label + aria-pressed where appropriate.
  • Editors: orphan <label> without for= converted to <div class="editor-label"> to avoid mis-association; form controls properly labelled.
  • Reduced motion: @media (prefers-reduced-motion: reduce) honored for Ken-Burns animation, pulse skeletons, and pill transitions.
  • Status regions: role="status" / role="alert" on loading, empty and error states; map-cluster list items keyboard-reachable; federated cloud-badge gets role="img" + aria-label.
  • Alt-text: meaningful (caption / location / numbered fallback) instead of filename for photos; decorative alt="" for tile previews where the parent already labels the action.

Internationalisation

  • Backend month/category labels now route through IL10N::t() (PhotoStoryService::localizedMonth, FileStoryController::extractGroupKey). No more hardcoded Dutch in API payloads.
  • Frontend date formatters use getCanonicalLocale() from @nextcloud/l10n everywhere — toLocaleDateString / toLocaleString / Intl.DateTimeFormat calls in PhotoStoryWidget, FileStoryWidget and PhotoLightbox no longer pin nl-NL.

UX polish

  • Retry button in the error-state of both widgets. Users recover from transient API failures without reloading the page.
  • Context-aware empty messages: distinguishes "no folder selected" / "no documents match current filters" / "folder is empty".
  • Transparent date headers in FileStoryWidget Timeline mode — replaces the opaque white sticky bar that clashed with themed/coloured rows. Count-badge uses color-mix(in srgb, var(--color-primary-element) 14%, transparent) for a subtle tinted chip that adapts to the active theme.

Developer-side hardening

  • scripts/check-import-consistency.js runs in prebuild: detects mixed sync/async imports of the same .vue component (the root cause of a runtime TypeError we hit on 2026-05-27) and fails the build before it ships.
  • scripts/auto-bump-dev.js auto-bumps the patch level on dev deploys so NC's md5(appVersion) cache-buster always changes — browsers never serve a stale bundle after a deploy.
  • Translation files (en/nl/de/fr) synced for all 122 new UI strings added by Photo Story + File Story.

Notes

  • No DB migrations required for the widget functionality itself; existing pages keep working.
  • PhotoStory federated-share awareness is on the roadmap but not yet implemented (single-storage photo libraries are the typical case). FileStory has the full federated-aware code path.
  • MetaVox cross-instance sync remains out of scope: NC core exposes no federation tokens or remote-file-id mapping. Roadmap item.

New Vue components: src/components/PhotoStoryWidget.vue, src/components/PhotoStoryWidgetEditor.vue, src/components/PhotoLightbox.vue, src/components/PhotoStoryMap.vue, src/components/PhotoStoryDayMap.vue, src/components/PhotoStoryFilterBuilder.vue, src/components/FileStoryWidget.vue, src/components/FileStoryWidgetEditor.vue.

Composer: lsolesen/pel added for the optional in-process EXIF reader.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureFLZvFbovK9mQvZvpGHVOIIcY1Wkokfi3grl/FTH48JoSlk35yZ49frh91/2T0Bda+dcFMO1aCpsNd694iEd26hCMp66F+QA8nqYMB0+WCiEUwlDSVT1x7S9MdLch+7LGPrm2A6h1MWsTQGV9pOIOjWtP4rPGv1+Mw+LFEva+CmFep5Kh/w/RaEqvn9LwcDzxx5JEzzme+nYZurAgV6146olp+xl0rCtxM/IPvL5JlZ7NchtiEc0udMvLroBfdOHKRU0aIJY7ZzVdjJJB46a911krwyn9jfcJmqGVrHZtNlp6uwpFKKlXo1fZDdnMsu/YxnVH5XTJOEflsQTB8GWntZa//R5zRRGXX0jj4o/dWNxvRMPD9jvCTO7Wq5oEvyorRcHVCJ70QatCHKNhOqXtq/vvywVZODt3BZk9gtQ5ssv9FFe7JB7zZWS69ZhHcTS9HqzV0UJ3SpSZfjXN0gsCdTlSi6hknGP9X4wvShSjV+DeHeBJoM4EZHVLSZiRjBWBYpqg0ffwj5X5U8VrXIFtIUHwUMXUJzl7Ta3Uwo4liP77h5AA2xInz+IxLAcpAP/ncaLtlrqCvm0PN1QRz3zq9IBaxE0VI7UDIn6S6ojzXQDWHTPaTPfS/e9v7WqPUB4t/o+6PyEulzq8TXq2jpmXcMsEDHQaRAJl5XT4W3h7TMM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.1
Release Details
UpdatedMay 20, 2026, 6:01 a.m.
Changelog

Patch release that resolves all open frontend security advisories flagged by GitHub Dependabot shortly after the v1.4.0 push. No functional or API changes — npm audit fix lifted eight vulnerable transitive packages to patched versions within their declared semver ranges, no package.json edits required. Build, PHPUnit (258/413) and dev-server smoke tests all green.

Fixed

  • axios → 1.16.1 — resolves 11 advisories (prototype pollution gadgets, CRLF injection, header injection, NO_PROXY/SSRF bypasses, DoS via deep toFormData recursion, streamed upload/response body-size bypasses, null-byte injection in URLSearchParams, XSRF token cross-origin leak)
  • dompurify → 3.4.5 — resolves four XSS bypasses (SAFE_FOR_TEMPLATES/RETURN_DOM, ADD_TAGS/FORBID_TAGS short-circuit and function-form, prototype-pollution via CUSTOM_ELEMENT_HANDLING)
  • fast-uri → 3.1.2 — path-traversal via percent-encoded dot segments + host-confusion via percent-encoded authority delimiters
  • fast-xml-builder / fast-xml-parser — XML comment/CDATA injection and attribute-value quote-bypass
  • brace-expansion → 5.0.6 — DoS via numeric range that defeated documented max protection
  • follow-redirects → 1.16.1 — custom auth-header leak on cross-domain redirects
  • postcss → 8.5.15 — XSS via unescaped </style> in CSS stringify output

After the bump npm audit reports zero vulnerabilities.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDc0e6XrFG/+dkBa2rqaitf3dwAEkyMJA/wqM2F2ZDIp+L9644GrNvZpexYR5xe/IEL4TR6gu1JHpUs2nqxnQ/Wgm8miJwi8+/9Jgg1bjc93k11siFiM8ca+ljWMlJ9Ai1UofzB8tdX2UqOPc1jzPMJwttj1+vYNBIrmD8Ypdubmnw6U3VDP/vSVwwR7I9O08D0DT/f6YGPRa4reXbqHRRllXRUgKXCXL0EWITQ1uwV/XoipV2U35G/BjFwOsQV370teRvY9aMarNl1j86d9N2O+cFMRokMVD/feZNeDXJ1jKh6UxOGPSuJZiQFEVdwMmyyH1MXYy3xh52ZI01G+je1GvGPwzpouTvZzDMYYdsNFepGZtNl1nDBH8THuNnEnMCyBxCPabrlNfBPH9GFdDSPjFptQjZ+ec3/UJHCIqAQHV2no41W5KEBCJTHGf/ex4tU3LIUGGZeTPGmdYCHvH4VNqqqHffL88FqFCKHNO6kWrqnHaFGNwfxsM5uNeYKlZttEzinZzg0Y+ka+e6p0Ko6YNlzG98rpngbyWFM/CVEliEoVYnOsPGHhoV2/GLxMc9JjjRJEBSrRCU7WXCqVQNr8hOLy/qlfvkCnKv2E9YHv4lTKKMayDmJWE0iFCF8DfoA2eHyfLt/6bWSsMzEGERpu4Z/N6EDeoEAws+tfk3No=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.0
Release Details
UpdatedMay 19, 2026, 8:39 p.m.
Changelog

This release lays down the foundation IntraVox needs to scale cleanly to Nextcloud Enterprise customers with thousands of users on multi-node deployments. Two themes: PageService gets split into focused, testable services, and the caching layer gains group-aware keys + a content-addressable distributed cache + a frontend prefetch pipeline.

User-visible: pages and navigation are noticeably faster on warm caches, especially for groups of users that share the same permission profile. Cold-cache latency is bounded by a new background warmup job. No breaking changes; every public API is unchanged.

Added

  • Subtree support on GET /api/pages/tree — Optional rootPageId query parameter narrows the response to the subtree rooted at the page with that uniqueId. Resolves #45 from JustinDoek (teamhub app builder) who previously had to combine listPages + getBreadcrumb to list pages under one anchor. Backward compatible — without the parameter the full tree is returned as before. The same parameter is available on the <PageTreeSelect> Vue component (rootPageId prop) for in-app subtree pickers (lib/Service/Path/PagePathHelper.php::findSubtree, lib/Service/PageService.php, lib/Controller/ApiController.php, src/components/PageTreeSelect.vue)
  • ETag / 304 conditional responses on GET /api/pages/{id} — Browser revalidation now returns a 304 with zero body when the cached page is still current. Per-user group hash is included in the ETag so a permission change automatically invalidates the cached entry without leaking content across users (lib/Http/EtagBuilder.php, lib/Controller/HasConditionalResponse.php, lib/Controller/ApiController.php)
  • Group-hash cache key for page tree + permission map — Tree and navigation caches are now keyed by a hash of the user's group memberships instead of their user-id. At enterprise scale (1000+ users in ~10 groups) this turns thousands of cache entries into dozens — same correctness, two orders of magnitude less memory. Permission path-maps are cached per-language (one entry per supported language, shared across all users) (lib/Service/GroupContextService.php, lib/Service/PageService.php, lib/Service/PermissionService.php)
  • Event-based cache invalidation on group changes — Adding or removing a user from a group flushes the affected distributed caches via UserAddedEvent / UserRemovedEvent listeners. Group permission updates propagate within one request cycle instead of waiting for TTL expiry (lib/Listener/GroupMembershipChangedListener.php)
  • Page-content distributed cache with mtime-indexed keys — Sanitized page output is cached under content_{uniqueId}_{mtime}; a write bumps mtime, the next reader misses cache and rebuilds. The expensive sanitize-pipeline (~500 lines of widget processing) only runs on cache miss (lib/Service/PageService.php)
  • News widget result cache with version countergetNewsPages() results are cached per {lang}_{groupHash}_v{counter}_{paramHash}. Mutations clear the cache; subsequent reads rebuild from a fresh counter state (lib/Service/PageService.php)
  • Frontend prefetch servicesrc/services/PrefetchService.js speculatively loads pages on hover (desktop, 100ms delay) and IntersectionObserver entry (mobile, 200px rootMargin). Respects navigator.connection.saveData so users on metered connections aren't surprised by extra requests; max 3 concurrent in-flight requests. Writes through the existing CacheService so real navigations pick up the prefetched data instantly
  • LRU eviction on localStorage quotaCacheService.set() now catches QuotaExceededError, drops the persistent entry with the earliest expiry, and retries once. Prevents silent cache-write failures on heavy intranets
  • Background cache-warmup job — Runs every 15 minutes (TIME_INSENSITIVE) and pre-warms the path-map + tree + navigation caches for each supported language. Prevents the cold-cache thundering herd after a deploy or after a page mutation (lib/BackgroundJob/CacheWarmupJob.php)
  • RequestTimer infrastructure — Light static utility for measuring p50/p95 latency of expensive operations. Used internally for ad-hoc profiling; not yet wired into TelemetryService (lib/Performance/RequestTimer.php)

Changed

  • PageService.php is 615 lines smaller — From 6135 to ~5520 lines. Ten pure helpers extracted into focused, individually-testable services. PageService remains the orchestrator for filesystem + cache + permissions, but the sanitize, format, search, path and template logic now live in dedicated modules:
  • lib/Service/Sanitize/HtmlSanitizer.php (strip_tags + style-property whitelist + entity decode)
  • lib/Service/Sanitize/UrlSanitizer.php (schema-whitelist for link URLs)
  • lib/Service/Sanitize/ColorSanitizer.php (NC theme-vars + hex + rgb/rgba)
  • lib/Service/Sanitize/MediaSanitizer.php (filename + SVG + image-header validation)
  • lib/Service/Version/PageVersionFormatter.php (NC-style "X sec/min/hour/day ago" + metadata accessors)
  • lib/Service/Template/TemplateMetadataExtractor.php (preview summary: column count, widget mix, complexity bucket)
  • lib/Service/News/NewsContentExtractor.php (excerpt, first-image, markdown strip)
  • lib/Service/Search/PageSearchHelper.php (snippet extraction, per-widget-type scoring)
  • lib/Service/Path/PagePathHelper.php (depth, page-type, department slug, current-page marking)
  • lib/Service/Util/PageIdUtils.php (sanitizeId, RFC 4122 v4 UUID, php.ini size parsing, formatBytes)
  • Test suite grew from 78 (with 36 errors) to 252 / 401 assertions, all green — Existing Controller tests were updated to match the current constructor signatures; a fresh unit-test layer covers every extracted service

Fixed

  • Cache-invalidation gaps closed across page/nav/media/import flows — Discovered during dev verification of the new caching layer: several mutation paths wrote to disk without flushing the distributed caches introduced by PR-3 / PR-12 / PR-13, so changes were invisible for up to 5 minutes after a save. Now resolved:
  • PageService::createPage flushes after writing — without this, the new page sat behind the 5-minute tree-cache TTL (visible on "Create from template" — page appeared in the breadcrumb but the editor mounted blank until reload).
  • PageService::createPageFromTemplate re-fetches through getPage() so the response includes enrichWithPathData + the sanitize pipeline. Previously the API returned half-populated page data and the editor rendered blank until a manual save round-tripped through the real read path.
  • App.vue::handleCreatePageFromTemplate uses the enriched backend response directly instead of doing a second selectPage() round-trip that occasionally 404'd against a freshly-created folder and bounced the user back to the home page. URL hash, local pages array and frontend CacheService are all warmed in one synchronous block before the editor mounts.
  • ImportService::importFromZip flushes all PageService caches after a bulk import — without this, 50+ imported pages were invisible in tree, navigation and news widgets for the next 5 minutes.
  • NavigationService::saveNavigation flushes intravox-pages + intravox-permissions after writing — previously a menu edit landed on disk but the path-map cache (PR-3) served the old menu for 5 minutes.
  • PageService::uploadMedia + uploadMediaWithOriginalName flush the per-page content cache so the next page-render reflects the just-uploaded asset (important for image overwrites where users otherwise got the cached old version back).
  • Public PageService::invalidateAllCaches() introduced as the cross-service hook for the import path (kept internal clearCache() private; only the audit-driven external use case opens it up).
  • Actionable error messages on failed ZIP imports — Resolves #52 from @apesorguk, who saw only "Import failed. Please check the ZIP file format and try again" when uploading a cloudron Nextcloud backup. The five validation errors in ImportService (invalid ZIP, missing export.json, invalid JSON, unsupported version, incomplete export) now bubble through a typed InvalidImportException and reach the user with copy that tells them what went wrong and how to fix it ("Make sure you uploaded an IntraVox export, not a Nextcloud Files backup..."). HTTP status is now 400 for these instead of 500. Generic failures still hide behind an errorId so server paths don't leak. A NcNoteCard above the import form spells out the supported format up front. Error messages translated to NL/DE/FR via a stable errorCode (INVALID_ZIP, MISSING_EXPORT_JSON, INVALID_JSON, UNSUPPORTED_VERSION, INCOMPLETE_EXPORT) the frontend maps to localized strings (lib/Exception/InvalidImportException.php, lib/Service/ImportService.php, lib/Controller/ApiController.php, lib/Controller/ImportController.php, src/components/AdminSettings.vue)
  • Broken Controller test suiteApiControllerTest, BulkControllerTest, AnalyticsControllerTest now compile against the current Controller constructor signatures. The OCP stub gained ISession, ICache, ICacheFactory, IGroup, group-membership events and Files_Versions\IVersion to keep unit tests runnable without a full Nextcloud install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturer9Dvf1Sv0MUqG5zMrZC7vrTGxJ/b/FMFLIQaX9apeRGFYpfb4hH4Zsbt+aKCbyoRj3zOGtdytKpqUDEXZ9jFexiNrkKjfWOvW8XSH1dlFHc6Vo/z+h7Ms+02xgNdSxajfN0yJK0WnDDfhEUn1j9VaByfKuF9VaMVwHL0u4A+k2LwCW0izMkZVjLtiJk/1VyA7pc4Olz+6eWyF0QaKkTXyMmbibugQNrRjRCAylR8up/tSlgi4aTobGMZKkoeZg+HK5KfQXiZHoC4B3GiP3Vf/CfzU0WYyhq7sOZ4LM7PUtgZwcJyUMk5i12oS56Nf+4Umubrn6OaupdmOmgSbCbN3G1K7HWgRpYGqmdDdqzIajzm/lt2vV5gtW4PUyY1ESAh5F1Cch/h/+HWndtyQZDkKgX0jgXtKttltXJbC4/+LQWPIDmffP8ve12tSpCYcENQdvV8rtGkS4aAH0Mf3jiqa8oNtpr7VgwslCHEhrSXxMz1mprSO+x+R3wqWmo+JCo9QmPnwT9nhf81CtvazMkZ2zmzrGX4EegRNpILLPbR3BwrV214CHpu6lnE9zZlCqU9/pXyJoutDUrGtk8gqD3tl2heAy4EcEOIgnHOYx72Q14HXk227XA61Qvq02dp/+lQKLtiEBByL5ZkT/FYQsgyZsEM4p9YBMXr9/ZzmTDrG1k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.4
Release Details
UpdatedMay 8, 2026, 8:11 a.m.
Changelog

Identical content to 1.3.1 (released earlier today). The version number is bumped to 1.3.4 because an internal 1.3.3 build was published to the App Store on 2026-05-06; instances that picked up that build would not see 1.3.1 as an upgrade. 1.3.4 ensures every existing install gets the editor/table improvements and the privacy cleanup of [1.3.1] below.

No code changes vs. 1.3.1.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBQtsgQvlSPO/vsSYvRbB2PBuBbivwcUewzg126b/lwuFwdLoS/6+o9m1Kahs/ZxLur3f6fBRJEw2fZOh85ofBGQbd6o3KFJtLkUzZZ3/zsfiwbxlUCaNiO3hnuF5UHqpumyiL2bQO2BzaYHCn0G+82UonzYOsvbhMMwVIJeL3oCis3B9Z0+lB6KkCtAuE0mGLybehJ0Sa1KG326gf69OopoE94ikLowwxOPFmFJx6944rmk7axG92CtAV4x68WI8imrKPY59lAt3VI4+YiAXWdjyGKrG08yPi30AjnMwW5raab78hiySW1mIKcpMd8UaDVfKz19oG3MnRz7TpVSzADxuxx5ueuP1sV58e+5UU/Uv2OcghdnFSdyiSCHGQokUqUi63q0QV74517WQgdnmygJRXR+YwYfOn/AhhhKXSeyb/KFIlHoTTdM+gNysJldCBktY49ZEKGhi5AJkGW2jzZ3+hVW1PZylTqV9HRq/ZgFVukYJdPYsWV5UQ8XzN+vYcLuYsPMBWxfKeuecfdzjChZ6sxseqIYyqk2WzN/hBZLbzuQODvroGmb7nPzQsJHolgv7YcCLk0EexuyI2FdYUpI3UKSes9jqAIdLsRylBsgtnVNV6pe53IX3NjWgYubA2VQWgzMM5hFjiM9Q2PyebaXDb7n/LTl73D/qy/0guHw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.1
Release Details
UpdatedMay 8, 2026, 6:34 a.m.
Changelog

Added

  • Text alignment — New alignment dropdown in the text editor toolbar (left, center, right). Alignment persists through save/reload using CSS classes in markdown storage. Supports paragraphs and headings. Keyboard shortcuts: Ctrl+Shift+L/E/R. Custom TipTap extension uses CSS classes instead of inline styles for DOMPurify compatibility (textAlignExtension.js, InlineTextEditor.vue, markdownSerializer.js)
  • Blockquote button — New blockquote toggle button in the text editor toolbar. Uses the existing StarterKit blockquote extension — only the toolbar button and read-only styling were missing (InlineTextEditor.vue, Widget.vue, Footer.vue)
  • Nextcloud Extended Support telemetry — Telemetry payload now includes hasExtendedSupport (boolean), sourced from Nextcloud's public OCP\Util::hasExtendedSupport() API. Helps us understand which share of IntraVox installations runs on Nextcloud Enterprise / Extended Support — relevant for compatibility prioritization and the Nextcloud ISV partnership. Falls under the existing telemetry opt-out (no separate consent), and is listed in the admin "What we collect" overview for transparency. No personal data, just a single yes/no per instance (TelemetryService.php, SupportSettings.vue)
  • Persistent column widths in tables — Column widths an editor sets by dragging the TipTap resize handles now survive save/reload. A post-render hydrator in markdownSerializer.js builds a <colgroup> from data-colwidth (modern) or colwidth (legacy) cell attributes and any pre-existing <col style="width: Xpx">, then converts pixel widths to percentages so the table always fits its container — even when the saved widths sum higher than a narrow page-row column. Tables without explicit widths keep the previous auto-layout behaviour (markdownSerializer.js)
  • Table width presets — New "Width" row in the table toolbar dropdown with presets Auto, 25%, 50%, 75%, 100%. Stored as data-table-width on the <table> (InlineTextEditor.vue)
  • Table alignment — New "Alignment" row in the same dropdown with Left/Center/Right buttons. Stored as data-table-align; rendered as margin-left: auto / margin-right: auto so a 50%-wide table can sit left, centered, or right with surrounding text (InlineTextEditor.vue)
  • Free-form table width drag handle — A custom ProseMirror plugin adds an 8px-wide drag area on the right edge of the active table. Click+drag to set any pixel width between 80px and the widget container's width; the resulting style survives save/reload via the same hydrator. Coexists with the column-resize handles inside the table — different hit zones (tableResizeHandle.js, InlineTextEditor.vue)
  • Horizontal scroll wrapper for wide tables — Tables wider than their page-column scroll horizontally inside a .tableWrapper div instead of pushing the page layout sideways. Read-mode wraps every table via the hydrator; edit-mode reuses TipTap's built-in .tableWrapper element with the same styling, so what the editor sees matches what readers get (markdownSerializer.js, Widget.vue, InlineTextEditor.vue)

Changed

  • Toolbar reordered — Text editor toolbar reorganized into logical groups based on analysis of 10 popular editors: (1) Inline formatting: B, I, U, S (2) Block structure: Heading, Lists, Blockquote (3) Alignment dropdown (4) Insert actions: Link, Table. Compact mode follows the same grouping in the "More" dropdown (InlineTextEditor.vue)
  • Alignment as dropdown — Text alignment uses a single dropdown button (like the heading dropdown) instead of 3 separate buttons. The button icon dynamically reflects the active alignment. Keeps the toolbar compact on all screen sizes (InlineTextEditor.vue)
  • Telemetry includes license key for Enterprise claim verificationTelemetryService::collectData() now adds the configured license key (or empty string for community instances). The license server uses it to verify hasExtendedSupport claims against the bound license_usage row before honoring them; without this binding the boolean would be anonymously spoofable. The key is the same value the app already sends to license validation/usage endpoints, so this introduces no new disclosure (TelemetryService.php)
  • Table cell text wrap policy — Cells use overflow-wrap: anywhere (CSS Text Module Level 3) so long unbreakable tokens (URLs, hashes) wrap mid-word when needed. Edit-mode and read-mode use the same rules so what the editor sees is what readers get. Replaces the deprecated word-break: break-word combo with the modern one-line equivalent (InlineTextEditor.vue, Widget.vue)
  • Page rows allow narrow content.page-row, .row-content, .page-grid got min-width: 0 and max-width: 100% so a wide table inside a multi-column row no longer forces the row beyond its viewport. The grid columns now use repeat(N, minmax(0, 1fr)) instead of repeat(N, 1fr) so a 1fr track can shrink below its content's min-content (PageViewer.vue, PageEditor.vue)

Fixed

  • Aligned text not surviving save/reload — Content with text alignment was escaped to raw HTML after saving and reloading. Root cause: markdownToHtml() had a validation check (html === preservedMarkdown) that incorrectly treated HTML blocks passed through by marked as a parse failure, triggering escapeHtml(). Fixed by skipping this check when content starts with < (markdownSerializer.js)
  • Table widths and alignment getting stripped on savedata-table-width and data-table-align were not in the DOMPurify allowlist, so user-set widths and alignment from the table dropdown silently disappeared after saving. Added to the allowlist together with the <div> tag we now use for the scroll wrapper (markdownSerializer.js)
  • Text overflowing table cells — In fixed-layout tables, long text in a cell could push past the cell border into the next column or beyond the table edge. Multi-cause fix: paragraphs and headings inside cells get min-width: 0; max-width: 100%, cells get white-space: normal (overrides a Nextcloud core rule that set nowrap on <p>), and the entire page-row chain was given proper min-width: 0 so a wide table can no longer push its ancestors sideways (InlineTextEditor.vue, Widget.vue, PageViewer.vue, PageEditor.vue)
  • TipTap auto-generated table widths preventing fit-to-container — TipTap writes <table style="width: 422px"> based on summed colwidths; in narrow page-row columns this pinned the table beyond its container even with table-layout: fixed. The hydrator now strips that auto-style and rebuilds only from user-set data-table-width (markdownSerializer.js)

Removed

  • Organization name & contact email from telemetryorganizationName and contactEmail fields are no longer included in the telemetry payload sent to licenses.voxcloud.nl/api/telemetry/report. These were the only direct identifiers in an otherwise pseudonymous payload, so removing them brings telemetry closer to true anonymity. The fields had no functional purpose for telemetry — the license server doesn't use them — and no direct identifiers remain (TelemetryService.php)
  • "Your organization (optional)" admin settings section — Removed the corresponding UI section, Vue state, and GET/POST /api/settings endpoints from LicenseController. Pre-existing organization_name / contact_email config values remain in oc_appconfig on upgraded instances but are no longer read or transmitted; they can be cleaned up in a future migration (SupportSettings.vue, LicenseController.php, routes.php)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDR0XAuKJCLgbWV58zbVn9unXzIqAifDSrOYOGR04PcRtLR9ZDkgt/FbrI0HctxpnWmXD2zcV5pjYAu4Xc+m5OyWl+o9aMgKao4LZqyVkLiE6KeagdVonIEHbDd5wvNfSG9KXBWjcVu31jH831sBhodRmJ/ovY795C3q5cOFNYoLIGVHi278qa4r/wSqbsvULzu1vPEUpY3hukQn6XjzkRyh+gahUDmcU76xKeNL6f2pEdKkDKqFUN3TgBOJDaZYwJpy3tCwLRZNwFkLLoLy2XihULJxIlc800+zuIFlI3e1EfbhYtdBJXc449sJo7pIBHaHhF1vPU6eFgVmk+J8sPj1RoXiC7CRYNje41NOy0Bvkdx7QeB2O4ElH3huRnsS66oCrzcr+FJ1zRe8USai20NO8zfQifO0W5JR8Y1aWl/aKrzWIKtkZAYRptfMb4T+c0Sc9h1XPgfm5wK5D2eAJfnDgXJ3sUSfg8bf66tFQbvEmrbtG1n5C0X7j3i8jCL/7CqyWHpFbfCTsh4hmm6jnGSHVQvFoFwTcnbiLAamCMbkcRQ5DnaLMIXY/B5r2I2xzy8wEDhl4CJI8imIkjMTsFjrj8/UcTjQ1fL9bO5q8M4wfupSpPE62BIQcyvsKhfD+vfjRKegu3C60e52A9XtErd9sPUGFZNpXvz+DHGk6VHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.0
Release Details
UpdatedApril 21, 2026, 9:26 a.m.
Changelog

Added

  • Feed widget — New widget type for displaying external content on intranet pages. Supports RSS/Atom feeds and admin-configured connections to external systems (Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, and custom REST APIs). Features include: list and grid layouts (2-4 columns), configurable display options (image, date, excerpt, source, author), per-user OAuth2 personalization for LMS content, OIDC auto-connect for zero-click SSO, manual token fallback, 15-minute server-side caching, and public share support (FeedWidget.vue, FeedWidgetEditor.vue, FeedReaderService.php, FeedItem.vue)
  • Feed widget: connection presets — Administrators configure connections in Admin Settings using platform presets that auto-fill endpoint paths, auth methods, and response field mapping. Presets available for Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, and Custom REST API. Each preset supports platform-specific content types (e.g. News/Courses/Deadlines for LMS, Pages/Documents/Lists for SharePoint, Bugs/Recent/Created for Jira)
  • Feed widget: content type selection — Widget editors choose what content to display per connection type. LMS connections offer News/Announcements, My Courses, and Upcoming Deadlines. SharePoint offers Pages/News, Documents, and List items (with library/list selector). Jira offers project filtering and content types (bugs, recent, created). Content type selection happens in the widget editor, not admin settings
  • Feed widget: SharePoint integration — Full Microsoft Graph API integration via OAuth2 client_credentials flow. Automatic token acquisition and caching using tenant ID, client ID, and client secret. Supports SharePoint site ID resolution (hostname:/path: format), page/news listing, document libraries, and list items. Admin configures site URL + Entra ID credentials; editors choose content type and library in the widget
  • Feed widget: image proxy — Secure HMAC-signed image proxy bypasses Nextcloud CSP restrictions for feed images. Supports JPEG, PNG, GIF, WebP, AVIF, SVG (with sanitization via enshrined/svg-sanitize), and ICO. Daily signature rotation with yesterday grace window. All feed images (RSS, LMS, SharePoint, Jira) are proxied automatically (FeedReaderController.php, FeedReaderService.php)
  • Feed widget: OAuth2 account linking — Users can connect their personal LMS account via OAuth2 popup flow (Canvas, Moodle with local_oauth2 plugin, Brightspace). Connected users see personalized content from their own courses. Token refresh is automatic (LmsOAuthService.php, LmsOAuthController.php, LmsTokenService.php, OidcTokenBridge.php)
  • Feed widget: sort and filter — Feed items can be sorted by date or title (ascending/descending) and filtered by keyword. Filter searches in title, excerpt, and author (case-insensitive). Applied server-side after caching for instant response
  • Feed widget: custom request headers — REST API connections support configurable HTTP headers (key-value pairs). Enables Nextcloud OCS API integration (OCS-APIRequest: true) and other systems requiring custom headers
  • Feed widget: design principle — IntraVox focuses on organizational content (news, team updates, external feeds). Personal Nextcloud data (activities, notifications, recent files, Talk, Deck, Mail) belongs on the Nextcloud Dashboard. IntraVox does not duplicate Dashboard functionality. For organizational Nextcloud data from remote instances, use the REST API (custom) source type with OCS API endpoints
  • Calendar widget: external ICS feeds — Editors can add external ICS calendar URLs (e.g. from Moodle, Canvas, Brightspace) directly in the calendar widget. Events from these feeds are visible to all page visitors, including public share viewers. No Nextcloud Calendar subscription required per user. Supports up to 5 ICS feeds per widget with 30-minute caching (ExternalIcsService.php, CalendarWidgetEditor.vue)
  • Calendar widget: LMS event deep links — Clicking an external calendar event opens the event in the source LMS. Supports Canvas (native URL field), Brightspace (URL constructed from UID), and Moodle (URL constructed from UID). Unknown sources link to the feed domain
  • Feed widget: singleflight lock — Prevents thundering herd on cache expiry. When the feed cache expires, only the first request fetches from the external source; concurrent requests wait and read from the freshly populated cache. Uses a distributed lock with unique request ID verification (FeedReaderService.php)
  • Feed widget: circuit breaker — After 3 consecutive failures for a feed source, the circuit breaker opens and returns immediately with "temporarily unavailable". Resets automatically after 5 minutes or on first successful fetch. Prevents cascade failures from unstable external sources
  • Feed widget: background refresh — New FeedRefreshJob background job proactively refreshes configured feed connections every 10 minutes, before cache expiry. Users almost never trigger a cold fetch. Includes its own circuit breaker to skip failing sources
  • Feed widget: rate limitingUserRateThrottle(30/min) on authenticated feed endpoints, AnonRateThrottle(30/min) on public share feed endpoint (FeedReaderController.php)
  • Page metadata database index — New intravox_page_index table stores pre-indexed page metadata (title, uniqueId, path, language, status, modification time). Eliminates O(N) filesystem traversals for page listing, tree, and search operations. Updated automatically on page create/update/delete (PageIndexService.php, Version001300Date20260420000000.php)
  • Nextcloud search: index-first — The unified search provider (Ctrl+K) now queries the page metadata index for fast title-based results (~1ms), with fallback to full-text filesystem search for content matches (PageSearchProvider.php)
  • Distributed page tree cache — Page tree is cached in Redis/APCu (distributed) in addition to the existing in-process static cache. Shared across PHP processes/requests for ~70% reduction in tree response time. Invalidated automatically on page create/update/delete (PageService.php)
  • People widget: scalability guardrails — Hard cap of 5,000 users on the unscoped filter path to prevent OOM/timeout on large Nextcloud instances. Filter results cached in Redis/APCu for 1 hour. Batch status prefetching reduces API calls from N to 1 (UserService.php)
  • Rate limiting on mutating endpointsUserRateThrottle added to page create/delete (10/min), bulk operations (5/min), comments (20/min), reactions (30/min), and analytics tracking (60/min). Covers ApiController, BulkController, CommentController, AnalyticsController
  • GDPR user deletion handlerUserDeletedListener automatically cleans up analytics records, page locks, feed tokens, and LMS OAuth tokens when a Nextcloud user is deleted (UserDeletedListener.php, Application.php)
  • Audit logging — Administrative operations logged with IntraVox Audit: prefix for SIEM integration: bulk delete/move/update (with page IDs and user), license key changes, organization settings, engagement settings (BulkController.php, LicenseController.php, ApiController.php)
  • Health check endpointGET /apps/intravox/api/health returns app status and version for monitoring and orchestration (Kubernetes, uptime monitoring)
  • Scalability documentation — New SCALABILITY.md documenting all performance, caching, resilience, rate limiting, and enterprise features
  • Admin: connection test button — "Test connection" button on each feed connection card verifies credentials and endpoint by fetching a preview from the external API
  • Admin: connection export/import — Export all feed connections as JSON (without tokens/secrets). Import on another instance with duplicate detection and preview dialog
  • Admin: connection active/inactive toggle — Each connection has an NcCheckboxRadioSwitch toggle to temporarily disable it without deleting. Inactive connections show a specific message in widgets ("This connection is currently disabled by an administrator.") and are excluded from the widget editor dropdown. Re-enabling restores all widgets automatically — no reconfiguration needed. Toggle saves immediately
  • Admin: connection status badges — Connection cards show configuration status as text badges: "Configured" (green), "Not configured" (orange), "Token missing" (orange), "Credentials missing" (orange). Replaces the previous green/grey dots for better visibility
  • Admin: connection remove confirmation — Removing a feed connection shows a Nextcloud-style confirmation dialog instead of a browser prompt
  • Admin: Clean Start DELETE confirmation — Destructive "Clean Start" action now requires typing DELETE to confirm
  • Admin: orphaned data banner — Automatically detects orphaned data on admin panel load and shows a warning banner with link to Maintenance tab
  • Admin: advanced options collapse — Endpoint path, response mapping, and custom headers for custom REST API connections are behind an "Advanced options" toggle
  • Admin: column width warning — Shows a warning when the configured number of page columns may be too narrow for the available width, with a recommendation for fewer columns
  • Feed widget: error messages — Specific error messages for inactive connections, 404 (connection not found), 401 (authentication required), 403 (access denied), and 429 (rate limited) instead of generic "Could not load feed"

Changed

  • Feed widget: HTTP timeout reduced — Outbound HTTP timeout reduced from 10s to 5s to prevent PHP worker blocking when external sources are slow (FeedReaderService.php)
  • Bundle splitting — Enabled webpack splitChunks to separate vendor code (~2.9 MB) from application code (~220 KB). Main bundle reduced from 3.7 MB to 220 KB. Vendor chunk is shared between main and admin entry points and cached separately by browsers (webpack.config.js)
  • TipTap lazy-loaded — TipTap editor and all 8 extensions (~240 KB) are loaded dynamically via import() on first editor mount. Pages viewed in read-only mode never download the editor code (InlineTextEditor.vue)
  • Widget components lazy-loaded — All widget components (News, People, Calendar, Feed, Links, InlineTextEditor) loaded via defineAsyncComponent. Pages only download the widget types they actually use (Widget.vue)
  • Widget watchers debounced — Deep watchers on News, People, and Feed widgets debounced with 300ms delay to prevent API call bursts during editor configuration changes (NewsWidget.vue, PeopleWidget.vue, FeedWidget.vue)
  • Widget initial fetch deferred — News and Feed widgets use requestIdleCallback for initial data fetch, improving perceived page load performance
  • Page + lock fetch parallelized — Page content and lock status are now fetched in parallel via Promise.all instead of sequentially, eliminating ~100ms waterfall (App.vue)
  • Engagement settings cached — Engagement settings now use CacheService with 5-minute TTL, consistent with navigation and footer caching (App.vue)
  • News widget: collection limit — Recursive folder scan stops after collecting enough items (default: max(limit * 4, 200)) instead of scanning all folders before applying array_slice (PageService.php)
  • Tree components: progressive rendering — PageTreeItem and PageTreeSelectItem render max 50 children per node initially with a "Show more" button for additional items. Prevents DOM bloat with large page hierarchies (PageTreeItem.vue, PageTreeSelectItem.vue)
  • Navigation/footer HTTP caching — Added Cache-Control: private, max-age=300, must-revalidate and ETag headers to navigation and footer API responses, consistent with the existing feed API pattern (NavigationController.php, FooterController.php)
  • Feed widget: unified connection architecture — Replaced separate source types (Moodle, Canvas, Brightspace, REST API custom) with a single "Connection" concept. Editors choose RSS or Connection; the admin configures connections with presets (Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, Custom, plus LMS types). Presets auto-fill endpoint, auth method, and response mapping. LMS-specific logic (Moodle POST body auth, Canvas context_codes, Brightspace org unit) is preserved internally but hidden from the user. Backwards-compatible with existing connections
  • Calendar widget: IManager refactor — Replaced CalDavBackend with OCP\Calendar\IManager for fetching calendars. This properly handles both regular calendars and ICS subscriptions. Calendar identifiers changed from numeric IDs to string keys (CalendarService.php, CalendarController.php, PageService.php)
  • Calendar widget: hide ICS subscriptions from selector — Nextcloud ICS subscriptions are no longer shown in the calendar selector since external feeds are now managed via the dedicated ICS URL field
  • CSS theming compliance — Replaced non-standard --color-text-light with --color-text-maxcontrast in Feed and News widgets. Replaced hardcoded #fff/white with var(--color-primary-element-text). Replaced hardcoded border-radius values with NC variables. Standardized font-weight to 600 (NC convention). Dark theme backgrounds now use var(--color-primary-element-light) instead of hardcoded rgba values. Affects: FeedItem.vue, NewsItem.vue, CalendarWidget.vue, FeedWidgetEditor.vue

Fixed

  • Calendar widget wrong events shown — When an ICS subscription had the same numeric ID as a regular calendar, the widget showed events from the wrong calendar. Fixed by switching to unique string keys via IManager
  • REST API SSRF hardening — Connection base URL is now re-validated on every fetch request, not just at save time. Prevents SSRF if an admin account is compromised and a malicious URL is injected into stored connection config
  • Version restore not persisting — Restoring a page version appeared to work but reverted after a hard refresh. Root cause: the backend reused a stale file node after IVersionManager::rollback(), and the frontend masked the issue by showing a version preview instead of the actual restored page. Fixed by re-obtaining a fresh file node after rollback and clearing the version preview after restore
  • SSRF hardening: LMS connectors — Added validateUrl() with private IP range blocking to Moodle, Canvas, and Brightspace fetch methods. Previously only the generic REST API connector validated URLs at fetch time
  • SSRF hardening: ICS calendar feeds — Added private/reserved IP range blocking to ExternalIcsService::validateUrl(). Previously only enforced HTTPS without checking for internal network addresses
  • SSRF hardening: SharePoint & Jira — Added validateUrl() to resolveSharePointSiteId() and getJiraProjects() to block requests to private IP ranges
  • SSRF hardening: Confluence API importer — Added URL validation with private IP range blocking to the Confluence REST API importer's base URL
  • XXE hardening: Confluence importer — Added LIBXML_NONET flag to DOMDocument::loadXML() and loadHTML() in the Confluence Storage Format parser to prevent external entity resolution
  • Token handling: Jira project listing — Replaced direct admin token decryption with resolveToken() for consistent token resolution across all connector methods

Security

  • CSP hardened — Removed unsafe-eval from Content Security Policy. The Vue 3 runtime-only build and TipTap editor do not require eval(). This was a historical precaution that is no longer needed (PageController.php)
  • HMAC key hardened — Image proxy signature key now uses hash('sha256', ...) for proper 256-bit key derivation instead of string concatenation (FeedReaderService.php)
  • API response size limit — External API responses larger than 10 MB are rejected before JSON parsing to prevent out-of-memory conditions (FeedReaderService.php)

Accessibility

  • Feed widget aria-live — Loading and content states announced to screen readers via aria-live="polite" and role="status" (FeedWidget.vue)
  • Feed item semantics — Removed conflicting role="article" from feed item <a> tags. Added focus-visible outline for keyboard navigation (FeedItem.vue)
  • Admin loading spinners — All loading spinners in admin settings now have role="status" and aria-label="Loading" for screen reader users (AdminSettings.vue)
  • Connection card keyboard nav — Feed connection expand/collapse headers are keyboard-accessible with tabindex, role="button", aria-expanded, and Enter/Space handlers (AdminSettings.vue)
  • Status dot contrast — Disconnected connection status indicator has a visible border for better contrast on light backgrounds (AdminSettings.vue)

Documentation

  • New SCALABILITY.md — Comprehensive guide to performance, caching, resilience, rate limiting, GDPR, and enterprise features
  • Updated ARCHITECTURE.md with scalability section
  • Updated SECURITY.md with CSP, rate limiting, GDPR, audit logging, and feed widget security sections
  • Updated ADMIN_GUIDE.md with health check and audit log sections
  • Updated ADMIN_SETTINGS.md with connection testing, export/import, enabling/disabling connections, Clean Start confirmation, and advanced options collapse
  • Updated FEED_WIDGET.md with RSS example screenshot, SharePoint setup guide (Entra ID app registration), content type selection, error messages table, and screenshots for all connection types
  • Updated ACCESSIBILITY.md with feed widget and admin panel accessibility improvements
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLc6iFEUpymkn2oOpihHrtxmTjKYFZWKcuvfBrf1Xr3us6SzOBhArJpj7t5GHUekRY6sJiuf47lqIDbjzf9fby51vse5bF+n1/QHXdApMDmsxo6EhtM5e3VRWje9A+ZuT2W+Xspdu1owszLqJfQw3TMBFmtAF2QNLAxTU6X8BOwc2Px6MUJnD+aNrOaE4117bBqSv27JihzvyHoz21ey+kZK+vrXaZoXrLzKkf69mPYKMEiVuyKaueTLhuRcihJPZAuVC+ClgZVTueZGDmNQA39xfL9Puy5JpbQx6+7MSL6FKhoN4bXD3ve3DloPsIC35KF+gpH/T8hY6f3vWQgX5mGh5mQSJLHTTkYulKiDcXRq82cDg/o2tpw7D6Uu3R/wVafqGrndtl8A5/okhCHGJnwh7FdG3vzoMFMLdEM03Zlk4W5hiVio5fd1Wy0LVM6SaGM81S9+TrOV0S35vuONStfe56e17wDC9DVaznDTQJW7E7qj4eihX/r0sVD0qQzYoIQ7PvnJ5XNAobWh28TA0eXwOnTwlOSsFhHxBLyt/DJE2CYoEz8YYBNnBgTGthYVKPp/grlWfFGNrRygNOYYMbMSmVqZQ/8liz1OrMcFwC0DoW/IVtmaB8PIGYs7XO8D8IBYRVpklTlQpgFrEf8PpD/8rfnp04VGlWCb/E9tR9x4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.2.0
Release Details
UpdatedApril 16, 2026, 10:48 a.m.
Changelog

Fixed

  • People widget filter persistence — Filters using the "does not contain" operator were silently converted to "equals" on save because not_contains was missing from the backend operator whitelist. After a page refresh the filter showed different results. The operator is now correctly preserved
  • People widget filter value encoding — Filter values containing special characters (&, <, >, quotes) were HTML-encoded on save via htmlspecialchars(), causing them to no longer match user profile data (e.g., "R&D" became "R&D"). Filter values now use a dedicated sanitizeFilterValue() that strips tags and control characters without HTML-encoding. Existing corrupted values are automatically decoded on read
  • Editor contrast on colored rows — Column labels, placeholder text ("Enter text..."), column borders, and "Add Widget" buttons now adapt to dark row backgrounds (Primary color). Previously these elements were nearly invisible on dark backgrounds

Added

  • Skip-to-content link — Keyboard users can skip past the navigation to reach the main content directly (App.vue, PublicPageView.vue)
  • Semantic landmarks<header>, <main> elements replace generic <div> wrappers for better screen reader navigation
  • ARIA tab patterns — Proper role="tablist/tab/tabpanel" with aria-selected on NewPageModal and MediaPicker tab interfaces
  • ARIA combobox pattern — PageTreeSelect now announces as a combobox with aria-expanded and role="listbox" on the dropdown
  • Carousel accessibility — News carousel has role="region", aria-roledescription, aria-label, aria-live="polite" for slide announcements, and respects prefers-reduced-motion
  • Live regions — Loading states use role="status" with aria-live="polite", error states use role="alert" (App.vue, PublicPageView.vue, CalendarWidget.vue)
  • Focus-visible styles — Global *:focus-visible outline for keyboard navigation visibility
  • Reduced motion support — Global prefers-reduced-motion media query disables all CSS animations and transitions. Carousel autoplay is skipped when the user prefers reduced motion
  • Visually-hidden utility class.visually-hidden CSS class for screen reader-only content
  • Breadcrumb current pagearia-current="page" marks the active page in breadcrumb navigation
  • Accessibility documentation — New ACCESSIBILITY.md documenting WCAG 2.1 AA compliance status, legal framework (Wet Digitale Overheid), and implemented measures

Changed

  • Form labels associated with inputs — All form inputs across 15+ components now have programmatically associated labels via for/id pairs or aria-label attributes (WidgetEditor, NewPageModal, PageTreeSelect, CommentSection, MediaPicker, AdminSettings, PageEditor, NewsWidgetEditor, PeopleWidgetEditor, CalendarWidgetEditor, LinksEditor, NavigationEditor, PublicPageView)
  • Icon buttons accessible — All icon-only buttons in InlineTextEditor toolbar, carousel navigation, MediaPicker, and AdminSettings now have aria-label attributes
  • Draft badge contrast improved — Fallback text color darkened from #856404 to #6d5003 for a 5.5:1 contrast ratio (WCAG AA requires 4.5:1)
  • Dropdown accessibility — Navigation dropdowns have aria-haspopup and aria-expanded attributes
  • WelcomeScreen heading — Changed from <h1> to <h2> to prevent duplicate h1 on the page
  • Password error announced — Public page password error message has role="alert" for screen reader announcement
  • MediaPicker strings translated — All hardcoded English strings wrapped in t() translation function

Fixed

  • Focus anti-pattern removed — Removed event.target.blur() in Navigation.vue that was stripping keyboard focus after clicking the page structure button

Documentation

  • Added ACCESSIBILITY.md with full WCAG 2.1 AA compliance matrix
  • Added accessibility link to README documentation section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWi2Kezb67KRxkFi/zRvjUrCCpNNRc2DBOWtuhOITpNScggVnaSiP+zLGO3s+/fPnKmgGrFoPeSuTSQifpEA37aQrwWx1comrLRq6k9SG+4+VhgAxVjvYdha0fqhah0HDjsgfC1cLhOBExqudxnijKEf+NCGgZqf1tHFnLtUbM1Z+x5o0CjAjv47c8Qrz/LD5NTvDcmU2vkkePA4nNjMheGuxC70rmwceaXaoA2CRf9BZ2XQsI8AgE9yoTEFvdWVdpN/BR+DKoAQya6XBZitrAp1jvH3okVMMap+XDBJrhD8mfBC/9eEn4Q/UW1Xc/m3WnCMVy5MiuY3Jv0b9pl+BghH8elxTjsZZRQJ7riGX1k9e/I3hjl4GZKO96USxGi5tDoWWtq/dKLddmrzy00o0cBMuKaAJ/sFal+OyZg++OWO7Zi0sxeL12T2OaojmJ4u22sZmgaZi+Tl5naidjOE9cz3Tv41C7IIAKpW4j1Xrj7L2D9vA5C7rKH/7vIbY/iLWnIY0df5BDs7NsccnftNNLXGA24PjtN7C21SoLbSHA2hDk81Lq3QohMyCod13UkcCO4/OjKFH523IEmLnzxujA+YXNxnfEvaEW66AQn56pDKgBN0tmLKjMBd8hIAEBzpBP67buSytYIj3XjoRtR9rMHq1W125eljViPQlVVd0vTM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.2
Release Details
UpdatedApril 10, 2026, 10:41 a.m.
Changelog

Fixed

  • Telemetry error feedback: The "Send report now" button now shows the actual server error message (e.g., rate limit, connectivity issue) instead of silently failing
  • MetaVox icon dynamic loaded — MetaVox sidebar tab icon is no longer a hardcoded SVG copy. Now loads dynamically from the MetaVox app via imagePath('metavox', 'app.svg'), so logo changes in MetaVox are automatically reflected in IntraVox. Dark mode handled by Nextcloud's automatic app-dark.svg serving

Changed

  • App Store description rewritten — Expanded from ~150 to ~250 words, structured in 6 sections: page editor, widgets, collaboration, content management, enterprise, and requirements
  • App Store summary — Changed to "SharePoint-style intranet pages for Nextcloud — no code required"
  • Author updated to VoxCloud — Author name, email (info@voxcloud.nl), and homepage (voxcloud.nl) now reflect VoxCloud branding
  • Screenshots expanded from 3 to 7 — Added calendar widget, people widget, news carousel, templates, and engagement screenshots
  • Category social added — Reflects engagement features (reactions, comments, people widget)

Added

  • Documentation links in App Store — Editor Guide, Admin Guide, and API Development Guide now linked from the app listing

Security

  • axios upgraded to 1.15.0+ — Fixes critical SSRF vulnerability via NO_PROXY hostname normalization bypass (GHSA-3p68-rc4w-qgx5)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturedEPa13irIrVkzszfHig0ZkpEhHIKNvbSxRdMHeALc3YGKW3H/pXgEyzlSiOgTRlYG9JwD6bAo8ANVhK9tBaIMr5nzOO0JrgExrnHniBe4LtGgJ2xbE1TeVVKEnlgcmwi8SG60ueKvIJU/x/Vy2yIJJGe/ShTntep5qiwGJBe8QksUTojfPiDaqDXzcgVRyYhbvIuT44/TF5oohBzbLLHvXm5bhcbUP6WyWz2KsTF7sgMtkKmClOiY/vZYVG2QaK87+QbwBwnW5icirect8ZzPzxSHqsg3LJdP4InayQhs21ZSm6rdrmBhT8Z36OJv9Mu2Dzdvl5cbqalUJbLs5ILHh/i4LKcIgt5fd9yvPHrtH7DNKQHeYMdH6x9saOq6zDC/g71N2zb1klXypSNpnkb/Ki9ZniJd0AQq2vxj4i0rguZZSM2HyMgnQnmAUU/HHbZGExGVQ6qqZl2xdVp3PZMZiQKJvIoVFqev4CbHr1Mite0cy2aYcb8iGnAdGYBL8Q2YahPyL3+dgHmi6/ywY3pmo9w+4O+JDggH3O7Mt2rlgbEQAaR0qLafrRU0yTB54Xyk7CNQE4kV1oGzl+wIO0LBBpDnuQAqenvuh7ac4W3kil3fbjVs9lk3JiH9q0Wb9gQ50ZE9T00RM/VhSDacfnmghY1udXhgAThMrNXeOjQ3m0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.1
Release Details
UpdatedApril 8, 2026, 11:53 a.m.
Changelog

Added

  • Support contact settings — New admin settings section for configuring organization name and support contact details. Contact information is included in telemetry for easier support identification
  • App Store screenshots — Added calendar widget screenshots (layout, editor, primary, sidebar) and updated admin demo data and edit mode screenshots

Changed

  • Contact info updated — Author email changed to info@voxcloud.nl and website URL to voxcloud.nl
  • Admin settings refactored — Extracted support/contact settings into dedicated SupportSettings component for cleaner code organization

Security

  • serialize-javascript upgraded to 7.0.5 — Fixes excessive CPU usage vulnerability in array-like object serialization during webpack build process (#42)
  • brace-expansion upgraded to 5.0.5 — Fixes bracket handling vulnerability (#40)

Fixed

  • Demo data imports all languages — Demo data setup now detects the single active language and imports only that language's content, instead of importing all available languages regardless of configuration
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureaKR0xRRjvews2FOdXJ446XMnOvUrRh3oPx3N7dR/TGujbDnjFFXwF8qC7wXo9CrwLD164arXII26lxxH509xmimeAfARht3+m5iFU8X2UdeWfszCJtuf2TilPEp+3ZDcgKOpN3o9dkcas6hV7rYfsqVJTkLAPqvAhOA3lRQOM70SKV8P5Jo3wSKHiXocbdsk094u2jd640LIR3EFfkdCrzxQJ9KetiH3w+h135bz1qwU8/eceKTH+O9aHYtphsbfFqRvZzMqnZ3qEABfWzSdOMgkvSIrpYZDWy20aPi1vagdi9VtLBzuzVNvmzjLKcCu3HNdJ2mrITGFykR1JM+EKG5AmdoIovqjunLgwpoCQCmLYnvhLegYfsIz1MbG0mgfJ1ZeHwW/DI/9usLGtlNOwRqJjaL9WIgT2zk4wPkG0P0N8f+i/S4limsWXHilNlqj7nZJWQftBm+UoecxZ4hewwGbQZZIGdBDIFkbKV3JPsnN8y6OXohEIAWXfgy66SXM5n2KdYVlFAiMyAcIPWkab+ZjB/o+jrpkGuC/9+eJ0fTd8LAwSKzupt4hTCqmmru5t2Or/6YSEZxl3LlghWtC3ivSefxvqLuKy95vPVmT+ylOPohgmzUxPzlOHHcOp/N9YIP3YSWwMZ2cDbvAI4PeZD3UjHpnhm3t9q8lHOrygyk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.0
Release Details
UpdatedMarch 29, 2026, 7:49 a.m.
Changelog

Added

  • Calendar widget — New widget that displays upcoming events from shared Nextcloud calendars. Supports multi-calendar selection (merged view), configurable date range, event limit, and show/hide time and location. Events are shown with colored date badges matching the calendar color. Recurring events (RRULE) are correctly expanded into individual occurrences
  • Responsive calendar layout — Calendar widget automatically adapts to available space: 1 column in side columns, 2 columns in medium containers, 3 columns in wide content areas (via CSS container queries)

Fixed

  • People widget users lost on reload — User IDs containing dots, @ signs, or spaces (common in LDAP/SAML/OIDC environments) were silently stripped during save, causing selected users to disappear after page reload (#41)
  • Deploy script OPcache — Added Apache/PHP-FPM restart to deploy script to clear OPcache after deploying new PHP controllers

Security

  • Rate limiting on public People API — Added AnonRateThrottle to the public share endpoint for the People widget to prevent user enumeration

Documentation

  • Language & demo data — Added guidance that Nextcloud language setting must match the imported demo data language. Added troubleshooting entry for "Admin sees empty Welcome page after demo import" (#37)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureZBIZ5aIC0Jf+cgyuNd3xYfy7lZbE7fbg38Xem2/zEuWkI5PWOSY/WmCebThcm9NHRdFJIL74zHRIUbfE2XaicmcqwgSZozNcUeUG8kpK5elRhLYJXPdPZMAN1LpKiPlrz3951koLc2f0LNpTvOBvsXgk0Fjlsj/NRmYcn6Oy224uzlYrkwpwBn8UDRA6CBC8qJLG+TYF4/VnIfJLEomG01HV9Ar2TGb+dDUobWPWAgfXfkdNtrc7gfLPipGlAs8enaBWbEhLQi/qRVfU2W1azSTYzFgl1rwBMnFG5V9g8ymkZpakbioOnL074u9JUYwBIcXGSq+7w9oKo5LFmzidPmSALp8B12aM+lAElH/vBKlHBYSoDv3A/KoqWfXW5BZvXQXmtFa043vK0kHD5M0PARFfvPN7xkVXUYoQX5o9Ptre/I+UkINXO6FX7X4KepWM57WFVidCOMwwCl9e6b5UQdt6aeYSl1qoAnBNQgAxtYm2QgRJa9FyDEl4+yup+bBwrYU8URBCQJk6GTbAFaA5397wE12N3OLpwoiIx3g7ZBP+ppRmO1eb1SDGN9tJWa5AKgEg7CBnBaV5YNtWRlmoUfsgfCt1b039Dca7fEVcL523m5zgmxqkiCbO70fwlTdhoe00hQpcZomfmEP6wB7FftWIqMR63Ndw+7WmoGIouhM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.1
Release Details
UpdatedMarch 9, 2026, 3:12 p.m.
Changelog

Added

  • IntraVox Editors group — A third permission group (IntraVox Editors) is now automatically created during setup with Read + Write + Create permissions. This provides a three-tier permission model out of the box: Users (read), Editors (read/write/create), Admins (full access)
  • Scenarios documentation — New SCENARIOS.md guide with step-by-step recipes for content approval workflows (using the Nextcloud Approval app and MetaVox) and department-based intranets

Documentation

  • Updated ADMIN_GUIDE, AUTHORIZATION, EDITOR_GUIDE, and README to reflect the new three-group permission model
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQuql4/Qdcw6lDxelq5UHCLVmlFf7+6YjcNPpfIDS+ynsrL+9QbyGsGQyx8fZdisovKtKJODYvfEou6EmcdD8l14mvBc4P6v6PZwzRmgP3qGMG4fYX0lFfniULGs8YGtKVGtgqilJ1gLnHQrO4qIxQqvvNGtTKmr8N3GehbHprT/tTzgPTlhmIHPIjKrw6q5m380WyUBhq9Hw9o16MekCX5obAshT2pwQuQvkmEYuprV4wr3dFOqKC5vM04yd1x6s2y72ZLcCC4YDPRoMP75vClpQaaScIYwVoulnFlLqOZUw/qlywWttwMAalDJkRPmC3E08xlOup4RwZkGSdu9jv5ESDemPoxvtV4alDMkf/qECW8KZkjTEX89MuYfFLK7POiH68qJllpAooquc71PAdN/YmTtKPplKBKqiJwWReAgDK4dZdls1komf17vcn+usYsJhzVT5Jarp8jjT0aQpBFAUDIuEJmeF0nzI/Q0xV1bMeCs/j2yjDdSIJPLHr27uk68Tb+gBQbhYdpPR6sYxLT2DT3xbbvq9z3RPlowcO3/kvN71ojGEx6xPGOsISJbRDpg4v3ixzVaKa9nUurb44Hsp7E1GsF19ARAlEquCuJxkCXONHc4jjW0pPGUxyBAt5V4kvWqRhS9Whl1JjSWOd7X30GvShRSWwWu59BiaTpI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.0
Release Details
UpdatedMarch 8, 2026, 10:37 a.m.
Changelog

IntraVox 1.0 marks the first stable release. After 19 iterative releases, the app offers a complete intranet platform: a full page builder with 10+ widget types, page versioning, templates, public sharing, RSS feeds, engagement (reactions & comments), draft/published workflow, concurrent edit protection, and multi-language support. The JSON page format and REST API are considered stable from this version onward.

Added

  • Page locking — Pessimistic locking prevents concurrent edits. When a user starts editing a page, other users see who is editing and the Edit button is disabled. Locks auto-expire after 15 minutes of inactivity, with a 60-second heartbeat to keep active sessions alive. Locks are released on save, cancel, navigation, and tab close
  • Lock safety net in API — Backend updatePage() rejects saves with HTTP 409 if the page is locked by another user, preventing data loss even if the frontend check is bypassed
  • Force unlock for admins — IntraVox Admins can force-release a page lock held by another user (e.g. after a browser crash). Includes confirmation dialog to warn about potential unsaved changes
  • Draft pages (#32) — Pages can be saved as "Draft" or "Published". Draft pages are only visible to users with write permission and are hidden from read-only users, public shares, search results, RSS feeds, and the page tree. Editors see a clickable status badge in edit mode to toggle between Draft and Published, and a "Draft" indicator in view mode. Backward compatible: existing pages without a status field default to Published
  • Duplicate row (#32) — Editors can duplicate a complete row (including all columns and widgets) with a single click. The duplicate button appears in the row controls next to the delete button
  • Sticky edit toolbar (#32) — The header toolbar with Save/Cancel buttons stays fixed at the top of the viewport when scrolling, making it accessible on long pages

Changed

  • Page lock translations — Lock-related UI strings translated to English, Dutch, German, and French
  • Draft/duplicate translations — Draft, Published, and Duplicate row strings translated to English, Dutch, German, and French
  • New pages default to Draft — Newly created pages (both blank and from template) start as Draft and automatically open in edit mode so editors can begin working immediately

Fixed

  • Links widget tile overflow — Tiles in narrow containers (sidebar, small columns) no longer shrink to unreadable vertical text. Tiles auto-wrap to the next row when there isn't enough horizontal space, while respecting the configured column count when space allows

Documentation

  • Editor guide — Added sections for sticky toolbar, page locking, draft/published status with visibility table, duplicate rows, and updated creating new pages workflow
  • Admin guide — Added page locking and draft pages sections, updated security considerations
  • README — Added page editor features (duplicate rows, sticky toolbar, page locking, draft/published), new feature sections with screenshots, updated security section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureiNaCstuvlWhKDNWHxOI3UH2urSyZ8OZCmlMAvQHWW8FDbfo3gBmHCD7ofk/6G78se/+9K8bLaSPMd0f3n3enR62K0ZG0jj5TP4eVvIsVYpVlLdzZlV64fJRcFSUotMFaluWlflLPKhuJbPJTCLivaYwzxX8QhfG7f9SUgZcsb/YZrCU0exRzekrFevLtHNsVE5aj7UWGg3lQh/zYZ28tlpsoWUPCJ2dT4qQ56kFO6IYvc4Wmf2diEzLLye1XaVpLaBbldRfDt2b4siu3uUMPePJHij6EDYL1dQAPuYAa12slvrh9TTRlffbtU1ny3b+1t9yLAVBiE6NEFccX7S/P5pmEPNmoeCECIv8lTyw8GJUeRNT+VdmlOZporvVXn4CWhW4aaQW+qVMLUrKrQ4Ond/ZYmVyVR4TjKiGZr04hr/xIdj0FDPffqe3SiLS5DJ4g3P+q3CCI7vktKlIdOrgpyHFavOfTq9IT2MT94UfJFob8L34g+yDsfdyQdYC2hQTXZsQUJ9TS72pzUC4c52Y4gomtLyUh4E7xOv8hAiGiKvaCDlcQJD7jE95LKw+EEwMvXrDMfhgn8hHMg9JxzSapRggu59B5Butz83jVNRnTWht9gaGu3nlpvMnNoE0YdFyU2c1yj0w5DoB7VmKd+4+1S32aO97qba7DCBpqrdQYc8o=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.18
Release Details
UpdatedMarch 7, 2026, 11:51 a.m.
Changelog

Added

  • Spacer widget rendering - Spacer widget now renders correctly in view mode with configurable height (10-200px). Previously fell through to "Unknown Widget Type" error display
  • Links widget tiles layout - Links widget now supports a tiles layout alongside the existing list layout. Tiles display a larger icon (36px) with a separate title and subtitle on two lines, creating a card-style presentation. Editors can switch between layouts and set title/subtitle per link in tile mode
  • 30+ extra link icons - Added icons for common intranet use cases: folders, chat, dashboard, contacts, forms, code, support, security, organization, news, and more
  • 5 unique demo showcases with rich, diverse layouts demonstrating all widget types:
  • de-linden (Universiteit) — 4 photos, 1/2/3/4-column rows, video, people grid, SURF services, right sidebar
  • van-der-berg (Advocatenkantoor) — 3 photos, header row, news grid, file widgets, no sidebars
  • gemeente-duin (Gemeente) — 3 photos, 1/2/3/5-column rows, left sidebar, news list
  • de-bron (Zorggroep) — 3 photos, 4-column department overview, people cards, video, file widgets, right sidebar
  • horizon-labs (Tech startup) — 2 photos, news carousel, culture row, right sidebar

Documentation

  • Showcases guide (SHOWCASES.md) — Complete documentation of all 5 showcases: widget coverage matrix, technical structure, background color guidelines, image handling, and people widget portability
  • Editor guide updated — Added documentation for file, spacer, news, and people widgets; updated column support from 1-3 to 1-5; documented collapsible rows, header rows, and side columns
  • Export/import updated — Widget types list expanded from 6 to 10 (added links, file, news, people)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCnOojEkcaYY3IrqfW3cj9gDhgOnlVkTd+sZpTFow4jh1pH+IrZ1NgXRjGgIKZiQtdvlh3AqgHdEE7kWidNvVTps4SL79TTLcQlO+aT223Sf9OOMC+GQsGkxUVKVY1d456mupVrZyslUCopbxr4Rf2aYxfsm3GFdMxPFGByXWE4VkJztuo8UI4krp2rfVRcBbv2m8RWd2w+1mAlkOiRK7176eS+d4jHn0h6Kslde5E/E4DfGML8uUyyu5yACJ/MMkUcJ+wxLvu2esOM5oPkbMrAHpWCa5TRzqVtbpoplcmDq4pYVw84AXc/+V91HduZOVLHgzWXhkV6O0qXjsWgsDfAPiZ1t9EWFuUMuV0EY2WbIxdo5eBSQsDaG4R60JKVlUvbx07OXecWG80VRslsngbXbTtvWV/AwHGWN60MufTQbEU8+cw3tIBD5RAlXwcnIVDHawBvasxQ7wlWU5/B8BZZkEDGdQMBlXTQE45+FVEbwXOaaQPD8s7cde2zCGk7Ze4MfIqZDyD5cBuszuVf5ljCpm8BQvt4oBGRPX9C0K8TB+l3vp6XzuMOvxixdIES9E20e9LYn1Yve0tTf3PzBQgUvPM4eYjXHD3U24w/0PNPNrBtLzg0uePqmm01dHBkVTqQC4CdmLD/cRG7GIH8bVBey+9XsftagMXH2LGuz8NS8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.16
Release Details
UpdatedFeb. 25, 2026, 1:50 p.m.
Changelog

Added

  • RSS feed - Personal RSS feed for each user with token-based authentication, feed media endpoint, conditional requests (ETag/Last-Modified), and brute force protection
  • RSS feed settings UI - Generate, regenerate, and revoke feed tokens with configurable scope (my language / all languages) and item limit
  • RSS feed sharing policy - Feed respects Nextcloud's "Allow users to share via link" admin setting; shows clear error when disabled
  • RSS feed cross-language links - Feed items link via #page-{uniqueId} format, automatically resolving pages across language folders

Changed

  • Dummy text generator - Removed =dad() alias, only =dadjokes() and =lorem() are now supported
  • =lorem() rich formatting - Now generates richly formatted content showcasing all text widget capabilities: headings, blockquotes, bullet lists, tables, ordered lists, and mixed inline marks (bold, italic, code, underline, strikethrough)
  • Dummy text multilingual labels - =lorem() section headings, table columns, and status labels are now localized for EN, NL, DE, and FR
  • Documentation - Added RSS feed admin setup guide with GroupFolder permission requirements (Read + Share), ACL examples, and troubleshooting

Fixed

  • People widget "Invalid Date" - Birthdate now correctly displayed regardless of Nextcloud locale settings. Added backend normalization of locale-specific date formats (DD-MM-YYYY, DD/MM/YYYY, DD.MM.YYYY) to ISO 8601 before sending to frontend, with additional frontend fallback for edge cases
  • RSS feed empty for ACL users - Documented that GroupFolders requires both Read and Share permissions for public feed endpoints; updated all permission tables and recommendations
  • Webpack build failure - Added string_decoder and buffer to webpack resolve.fallback to fix build error caused by @nextcloud/dialogs 7.3.0 pulling in Node.js core modules via sax/is-svg
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLkqXT+TE7U884io7bEDmL/gZLvaShUTg97nU7qIjNMBXEkd4nqo9nooA8+Y8qLUQEIjP1wFkw2p/TMduDHbWgZcPe+SIDuvfyQhqSlO5aeD8Q+pW+KmGAy0XbbQlVX6neiqaNGhD8TpCdnIStIHuPkjRngBSOuXf4JjeV3DNM2QKlck2at1svnElJOWujwLerTqWVGWQEaXSBvn0YGAHiLorgKXVitgZRMOxviUeSTxdWtwNsJ3vVIZ+mr+4UllElQh1jLgnePi2xa3DXs3b+r9CqebhIIQ2Brt8r0U2l3W5LIsjZJtf+/PHf9ytfAag51+XHLb/xMEZx9NDxakeGZlDPdQ652np7z7jgUxwE/wASSpVJ4LePTzwoBrdg4EDocI114Gtz0vqJGoTOJBHxZEovydDEXjOZSJcnLvzpfs1nkQBQYUvQGzSVti+0W64vSCh/I53o/U7GRYmCL03pYbNYZ9S2nk32usjfFizVbpGvKFrA5crLqxBns5Yb6bYY5QNtZtqHJiobkijwP19esHX6eCNLIKvI6aozaMtpawOQ/IDCDdJFI7N1+QFcoMgUsbbpfBXhImJ1I3LjWOjbzl+ZQ4d6CrHC1Gmd/KohKuvx5ER7RmgvLIhpgEEAKvdpFxgBc2gnQeVwTLUOBlzjJhS+I+7ggkrmX7+5HarwP0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.15
Release Details
UpdatedFeb. 19, 2026, 6:35 a.m.
Changelog

Fixed

  • MetaVox sidebar on NC33 - MetaVox metadata tab now works in IntraVox on Nextcloud 33, where MetaVox registers via the new scoped globals API instead of the legacy OCA.Files.Sidebar API
  • MetaVox mock Node object now passes correct mountType and mountPoint attributes (camelCase) so groupfolder detection works properly
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signatured13CndlYRWziam4mAOeDoHdjExboNyPiyFqfTRdrqRtcJkWVhRE0vN7wCEpWqUZaAni+r5JOpmwhpD7ePTFB8j77sIMq2K2ahdeGOVhnRrhQ3Qk055iXrnxzm3lvwaaerShVPa9D5fga3auYwpcuJxW4NDj36QvCwybkhwzJx381shlVjGyuZKQFJJWn3d3ZAzC2u1El8OlLIeBEDeszJizpa3EBEGdftZ7sfqkem+UMU9jWOGrXMwkYsauDhp+0mW6TNb7lDV84gZUKoE9lAYYLTPzFU5VWDA2mtvV6h09kwtZrXfkMxoh+S/qAcFkP9gwXFHKZKCDs3Z/HGTqeDxrbW6EM5sboYLOS7+VQapwes/UsGRO3XO9jzo5cfe4+c6fy32mjgwyhskSBm5UYdpYANsRgvOj0D9GQFNLYSuktoHaV0lq7BAtroDDk7B09k/422Eia0taM9PuoTmbMZ97yhgYZpEyJMLVx4nTMu30zXXkw0fkF3KfF0vZMnsOaAgYfQWXzChqpOlvemmz7bx/Ew7Murqz5ytaXfZvQ09WtWEV4l1b4AdCaf1ow/+w+V5BtXM/tCvaUmjQtdK+mf70ptdCr/+crxjhytihIm+NFMZSB/FMNlOKGcM3J0wz/kcBJ6tCLAcCIjzaf9p+42yUo8bgi+WzJTNp0r6EZSLA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.14
Release Details
UpdatedFeb. 18, 2026, 2:07 p.m.
Changelog

Added

  • Nextcloud 33 support - App now supports Nextcloud 32 and 33 (PHP 8.2+ required)
  • Page nesting depth increased from 3 to 5 levels for deeper page hierarchies
  • Dummy text generator (easter egg) - Type =dad(), =dadjokes(3,5), or =lorem(2,4) in a text widget and press Enter to generate dummy content (inspired by MS Word's =rand())
  • Birthdate field support in People widget - display, filter (is_today, within_next_days)
  • Bluesky social link support in People widget
  • Date filter operators for People widget: is today, within next X days

Fixed

  • People widget display options now correctly control rendered fields in grid layout
  • Removed gridShowFields override that forced fields off
  • Removed hardcoded layout !== 'grid' template restrictions
  • Removed CSS rule that hid headline in grid layout
  • showFields is now the single source of truth across all layouts
  • All display option checkboxes now always visible in editor (no longer hidden per layout)
  • showFields whitelist expanded in backend (PageService.php) to support all 15 field types
  • Legacy title field synced with role for backwards compatibility
  • Heading widget bottom spacing increased
  • Comment cascade delete now properly deletes replies and updates count
  • Security: markdown-it updated to 14.1.1 (ReDoS fix in linkify inline rule)
  • Security: ajv updated to 8.18.0 (CVE-2025-69873 ReDoS fix)

Changed

  • Twitter links now point to x.com instead of twitter.com
  • Dependency updates: axios 1.13.5, qs 6.14.2, webpack 5.105.0, ajv 8.18.0
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureKx4wBbCHSaA+wD5HWQ0/arQjdIOdtmxLwRYyh1GhcBKDiUVrfNUoFlOreUrs/FPv6heMXFD8XdJcVn6XXxPZzSOAYVCnKaIGGYea4RfsTlCbrShkasX2TxQ/1Kn1vH2QM+qe0aNdZstYv1QxhFgQyb82tWreFTuhisKgndvWqE5LouHSIDzamgr+iKmEoxf/LvCbPt4UvWc8nQdCc+XdnDa7WzMrjAB1xu5tHXE3coFmEqAWUwdMpp+vR9YanFLjC8CKfJEl+S4qL0DhDviXXUzjlOmIEttrXwRI1nv5rLg+Ucy1fBdZPUmMLXqgh7eUTWCSAlTVsTPYMvdhNQAZMWpioKf7X7pZcbp9JvcmbTZ6+VJVIT8tGGJROwpx/Z8v1fN3e5Gcv+pSq0yHpKM43v2S8LSa+Z5HB7BIV5GeUCmSIGfrWYEJvXYhpHtyHJrdVYfH2YuYbqkAH5bKuURwKQdJ0Y6A9v/gpEdwso44dNpPh0CY2uaGk/FwrJs1IYYmCI59OqF6l1/ffo9l/jR+PA5Jh3nns9lUR+hhfTJ25hF3+xhYdQV818Acbnl24c59rugq7+hX++cVn/b8VXen5WIUdVK4nl8eHNSYYVJoRLoz0PqhEVitwSF9k6zU+6/kSWIe2UiEwiOALXTSS89q+TVRT1J1oX1L//SPTg0b988=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.13
Release Details
UpdatedFeb. 12, 2026, 8:31 a.m.
Changelog

Added

  • People Widget: New widget to display Nextcloud user profiles on pages
  • Three layouts: Card (detailed with contact info), List (compact rows), Grid (avatar gallery)
  • Two selection modes: Manual user selection or filter-based (by group, role, department, etc.)
  • Group filtering: Show all users from specific Nextcloud groups automatically
  • Field filtering: Filter users by any profile field with operators (equals, contains, does not contain, is one of, etc.)
  • Customizable display: Toggle which fields to show (avatar, name, email, phone, role, headline, department, biography, social links)
  • Display options grouped: Basic Information, Contact, and Extended categories for easier configuration
  • Role and Headline fields: Separate fields for official job title (Role) and personal tagline (Headline)
  • LDAP/OIDC support: Custom fields from LDAP or OIDC are automatically detected and can be displayed
  • Nextcloud integration: Clicking avatars opens Nextcloud's contact menu (view profile, send email, check availability)
  • Privacy-first defaults: Phone numbers and addresses are hidden by default
  • Sorting options: Sort by name or email, ascending or descending
  • Column configuration: 2, 3, or 4 columns for Card and Grid layouts
  • Pagination: "Show more" button when there are more people than the configured limit
  • Dark background support: Proper text contrast on colored widget backgrounds
  • People Widget Guide: Comprehensive documentation at docs/PEOPLE_WIDGET.md

Changed

  • Filter field order: Filter fields now match the Display Options order (Group, Name, Pronouns, Role, Headline, Organisation, Email, Phone, Address, Website, Biography, Twitter/X, Fediverse)
  • Filter operators: Added "does not contain" operator for text fields
  • Column alignment: Fixed page columns aligning to different heights (now uses align-items: start)

Fixed

  • Dark background text contrast: Pagination footer text now readable on dark widget backgrounds
  • Widget title alignment: Widgets with background color now align with widgets without background
  • profileEnabled filter: Internal Nextcloud field no longer appears as a filter option
  • Avatar filter: Avatar field removed from filter options (not useful as a filter)

Documentation

  • README Updated: Added People widget to features list and documentation links
  • Internal Docs: Updated Additions.md roadmap to reflect People widget completion
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturehV3i13h8ckL9hELKxdaQ8Uyr/kUJCtjteUUgczGkj0i4AUY1qmxOQpr7h3SZSYG/5V7cOWG0VcT6eofmd2tM2zTY21oQjMEs+vlojzYwU0TgjXUQJlwkremsvgKJJsa28o6Np3w43G7RDk3/xVWl8Rcp+McTwCw3jIYGHJLnOTshQgmWIahWCynsLDUVGxidb5kwUoDGMZKii7tS9oM5l/1H5RnNGtlD7fvquDNemQ6wBVJ2u2ijvPXCdFzn20gfwfWk3T2O7Hwjz50fnkrdvd5vO7OzaxjbIhBKy7mZanIEHuRNHA7xjzCvB+Cd6yPk6SRHR/5vY3igFgSTdpF8pJCopnnNr8Tid+lWeprqIl51wwgjb1Gz2Z+OQQ84zVj2bmpV9i36aY/r3TuWw551KhqTFSMnMUQmk2vYw91wP5iPQGX6kxu0h99Qmt9Zs8HjFoikwLWtDb7iAGHa77pC+SBTdrV5fP7BCD//AD5owXapaFJT2NXrGcMoFJBQes6CR9dBVHZ04WU9lMINnqh3G/EzigknzoMwheQ/dqD7mH2PVuIMFNm/FIEWXUPbIwgYvjrX/pkeFVtU4U7O2Tt7jbBYD2kwSMFEM4loiC7wNEzCUJ+UAwBj3ajE5PL3o11UHademWD2HzCTabzlQg0K3seX4M+aig2MzmEugamVGhw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.12
Release Details
UpdatedFeb. 9, 2026, 5:01 p.m.
Changelog

Changed

  • Automatic Template Installation: Default templates are now automatically installed during app install/update
  • No longer requires manual occ intravox:setup command for templates
  • Existing templates are preserved (idempotent installation)
  • Templates are installed after demo data import completes
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturerVvT4H+yHmCH6KJhXQzLiyYtLlPHVtbrH3egQgcFN1xupxG4LNuGDzHOx097ODYQew0KOYcfb388+/V1Y7XxTiqXUeFRxX6hANfZo3TWoMP2YUW37X8IYiGFbpWsBxSbxP2qgrgsjbegXDNDmXOzPA264ee7O5yIPHyWtm5ZLD49RFOMItOB5phR8h7+4digwmdfAwtg9HR9OkBXJZI0mUmFUuJ/CWpDhFVTi/RUbNQ40D8Vyl8PWgiYN/00SmzFq4IwMRKpaGcSTeD7xU4exMKi06Rn/IO8zdpjSJJXN2gS2YUm9+c+cOxJ4p22QR6oPO7buPS9R5hN3AiwoW3Y7W9mu15NsRIOAHlgSiGpPiqAUfd02iKUHllL/ZH3cWYK39xynRoyqAOz64vKUiGo7O6thbOfrsua501HN6Xu9EkPMjTOeljcu1ZgErJCJr/W+XbvXbj62L8DnxiJW6fwTTUZQiFTpPeBBwgzKjX29qj4f/c+w9RJH8r4etu4YWj+kgVvBVU9tmn1ZOoDO4O8e5LiudB+kG0Rt0+hwxy1xyU/zybjiVtTeIjRIaIqXtbXMRfTO8lDcQjoLdGxkuOLN8f96VmIPSTzPUp9+DC67c7SCAQEO0mmR1iYu5o7UsiCZKg26kFdmU8sJIxJcjM3D2DSIvs1/HRvZqdRjBBAtyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.11
Release Details
UpdatedFeb. 9, 2026, 4:20 p.m.
Changelog

Added

  • Default Page Templates: 7 professional page templates installed automatically during setup
  • Department: Team info, services, and resources layout
  • Event: Program schedule, speakers, and registration sections
  • Knowledge Base: Documentation hub with categories, FAQ, and popular articles
  • Landing Page: Visual homepage with hero, features, sidebar, and call-to-action
  • News Article: Single article layout with hero image and related links
  • News Hub: Central news page with carousel, featured articles, and categories
  • Project: Project management page with status, milestones, team, and documents
  • Template Preview Cards: Visual layout previews when creating pages from templates
  • SVG-based schematic showing column layout, header rows, sidebars, and collapsible sections
  • Widget type badges showing which components are used (heading, text, image, video, news, links, divider)
  • Complexity indicator (Simple/Medium/Advanced) based on layout structure
  • Column count and widget count statistics
  • Enlarged Template Modal: Larger "Create new page" dialog with improved template gallery
  • Grid layout with 220px minimum card width
  • Scrollable gallery area (450px max height)
  • Template Translations: All template titles and descriptions translated
  • Dutch, English, German, and French translations
  • Automatic fallback to original text for custom user templates
  • Template Stock Images: Professional placeholder images included with each template
  • Hero images, feature images, team photos, speaker portraits
  • Images automatically copied when creating pages from templates

Changed

  • Template installation now runs automatically during occ intravox:setup
  • Templates are installed to {lang}/_templates/ for each language folder
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturef4SDWLwiEFHMcQ9i+1jUrkEJL3RcJA3/36FDPoI6nVf5uS3h8kmnF/tnNLGzj7gr5SKdvn9AglqkSTF9L6a/uz28LTgVq+9QaLPlBUDdjhuIDMIJwPbN1Z+kiWIcCVpz0gjNkhbyCQJ4ZQNv/ViYQHFG74Xk2GCIuRfXeopAyklSJcL2cZHfTQhoJDv42nLS4aJ7Umgx7XXiQgi9aAX5u911NTer++UU32Tu9ywlCx/XmI7IRLB/yv/Lufgzm44PiNpejcnCYsCuXTGemqUZhO44LcNN6299uwiz0X7A72r4KblNo1HDBjCeBTrut0EdguRCOeZuRIrW1xBC5nLK0ETn8C03BAomGvqHVcdxehgZ7V3dstxE82DwQ0/CGok3DiWg3k9xlQItM/Hej/Ztss6YJmgZafrN8yx8hrvu21yCnPUYzBurL4Xz3odQOa3+NqIWx9YPB10nsmHti2mnxm36wKxIl7Lcw53prdUhWrVMateZyOUXHJhIlHOUjAs2IkkSrWAcr6r9gqCasTYADMNGb3SK2q7ne8Xc07A9KHJR+gxen4HYVINqCNZXtEgKc3c6e9yTFoVp05d4NkVHT4eEjzAjr5q6fyzLDYtZnRqznFTtMdlIeutKI+a6s0Np9iMt6XU8E0hvB8x+i6uTsNN4ebCRu7DmJma7GZripmA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.10
Release Details
UpdatedFeb. 5, 2026, 6:29 a.m.
Changelog

Fixed

  • Text Editor Table Spacing: Fixed blank lines between tables doubling on each save cycle
  • TipTap inserts phantom <p> elements between block-level nodes, causing newline growth
  • cleanMarkdown() now caps consecutive newlines at 3 (one visual blank line max)
  • Preserves user-added blank lines while preventing accumulation
  • Text Editor Asterisks: Fixed * and ** appearing in text after saving bold/italic combined with underline
  • Mixed markdown + HTML (**text<u>underlined</u>**) now correctly serialized as pure HTML tags
  • Error fallback now escapes content instead of returning raw markdown
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureRb0bxVoFDn0onuvt08cN9KDhGJKkZ7Ywexlj2Gc1E67YHFQLxeR+6iSbf2/p+vRuIi6rOBpSzlycylZNcgtyMLbD5/Qr5YFTyX+QxVPyu4l8HtySuCpyzBk0roO2gJZMYOC/iBvFVqmRojoURC5x4wwNhmoQtK1l8vM4rDVVX/IA3bn2kj5TD14EzAyG8nWkTogmwmDmNDiRu0Ut+uPOTznHSb3NbeoTQb55q88uljKHc52dqLeR/C/zxyxZdmNJ3jnHkLdqfr01SMFw2cXh8VnVa7fEy0kwvbY/JOXX/5puMGDu61ViuNDhrldm+tw+fPpswuwiSE/fax4JuJHw2Xpt3le47BQ0ulWVXoPABervbAK40QFxAtQAQwa6KB7AgSQS2/mArmBS+lmJWhWxduYnrWLmrmP2os4n/8Z6hS4CCjpqhbUKYJTmyGh3ZILw3ILvuqGXW8q63f6D0uccAwM9hkRYAQtdtJWf0/MoI8q2gzxe6k6n8TH+UOor8GzwqIq2QrR02xBGak+M8QyQ939BeZGzki6ZLX9K3eJ0pPeuf998szkZWDqm0NR40b9CCTepv6VzpwQK99C2YgDDW8TynbZQlz1FKHZouiUDFlct7PC7Jt530foYbSuO+j4gP+5Orz2AaFD/JJjT69UkaZ/NskvxawLKF8ypfXLjCT4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.9
Release Details
UpdatedFeb. 4, 2026, 5:04 p.m.
Changelog

Added

  • Orphaned GroupFolder Data Management: New "Maintenance" tab in admin settings
  • Scan for orphaned groupfolder data (from reinstalled Team Folders app)
  • Recover content by migrating to the active IntraVox groupfolder
  • Delete orphaned data permanently
  • Useful for production environments recovering from Team Folders reinstallation

Improved

  • Team Folders Error Messages: Renamed "GroupFolders" to "Team Folders" to match Nextcloud App Store naming
  • More specific error messages when the Team Folders app is not installed or enabled
  • Separate error messages for different failure scenarios (app not installed, folder creation failed, access denied, unexpected error)
  • Full translations in Dutch, German, and French

Fixed

  • Public Share Page Tree: Fixed current page not being highlighted in page structure popup when viewing via public share link
  • Public Share Page Tree URL: Fixed 404 error on page structure in public share view (was calling /pagetree instead of /tree)
  • Password-Protected Share Navigation: Fixed "page not found" error after entering password on public share links
  • Generic "Could not create IntraVox GroupFolder" error now shows specific guidance based on the actual problem
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCLK9mZDM5DTV0G98PiLFat4vI+clsiUTK4u6rci3QZo3gGoEfdS9scFLnDFufZAX38L1jetr0rM7ox0+DJz4xLXmZ+dTEjPT+ACNuja3PIGIkp/qO2+4E8nZfKU5xmSWT8oIPylplzgJ9xJ3BkbeRmz+V63g7yRa4AD/OSg2j9sXudoSBci2+qmIyKm0WML6erw+rUw4NY7bOLo2GCe1UrVFel92VJ73bm6ASSMPgg1un6880sSu+Hoc+Y/3HXQYUftfkv9fWWLvcIv2lDcsDQqC8+2i+F5DjLgS7EC7u+nLJKCxDyeAinA+oC67q2Q3ztXb66OcvDDe1C73tgp/4K4d1a5hNwzBs26LrkvnTf95hT1IiVWdIIxSMJ9mFCDtzAlyThKm6IQub8De8bcpGocMN5jkNiZgt6eAj4oTbCvB3P1m0oRHa7+FWvTkLC8n81NLQg7JteoR4BzSM7IpmWs6X3AFv6TfHfTmRTOQgwHtLietzq4WFlD927LtTYwHJwuyb8/JAbsDGvzhKO40V+Jw25FuolqF808s64TWjrjz9ejta5yuk1eg44FlrqVXICwUvOZ1Qcx/kIaOUgpG0N1zvPmiU6Z0sB3bCkVyujYFmP7ouL3pOrkh1LsCEGFMxtrnx6x0O/fCfpqr8TLA1p/nSGRddchhwRhc/DKz8DE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.8
Release Details
UpdatedFeb. 1, 2026, 1:57 p.m.
Changelog

Added

  • Public Share Links: Full anonymous access to IntraVox pages via Nextcloud share links
  • Share any folder scope (language root or subfolder) as a public link
  • Anonymous users see pages, navigation, footer, page tree, and breadcrumbs without login
  • Share scope enforced: only pages within the shared folder are accessible
  • Rate limiting on all public endpoints to prevent abuse
  • Public Page Viewer: Dedicated read-only view for anonymous visitors
  • Full page rendering with all widget types (text, images, video, links, news)
  • Navigation menu with mega-menu support
  • Page tree sidebar for browsing available pages
  • Breadcrumb navigation
  • Footer display
  • Responsive layout for mobile and desktop
  • Password-Protected Shares: Full support for Nextcloud share link passwords
  • Server-side password challenge screen (rendered before JavaScript loads)
  • Session-based authentication — enter password once, navigate freely within scope
  • Brute force protection (10 attempts/min per IP) with random timing delays
  • Password verified via Nextcloud's IHasher (bcrypt) — plain text never stored
  • API endpoints return 401 with passwordRequired flag for expired sessions
  • Vue.js fallback password form for session expiry during navigation
  • Share Dialog: Redesigned public link modal with full share context
  • Scope indicator shows whether link shares a page, folder, or language root
  • "Password protected" badge with lock icon when share has a password
  • Navigation tree showing shared pages structure
  • Clickable "Manage share in Files" link opens Nextcloud Files sharing sidebar
  • Copy public link button
  • Share Button: Always visible in page toolbar with two states
  • Active state (theme color): share link exists — click to open share dialog
  • Inactive state (muted): no share link — click for guidance on creating one
  • Detects existing Nextcloud share links for the current scope
  • Admin Shares Overview: New "Sharing" tab in IntraVox admin settings
  • Lists all active Nextcloud share links on IntraVox content
  • Shows scope, file path, creation date, and expiration
  • Direct link to manage each share in the Files app
  • Useful for auditing public access
  • Sharing Disabled Warning: Clear feedback when NC link sharing is disabled
  • Warning dialog with link to Nextcloud Sharing settings
  • Explains the prerequisite for public sharing
  • Public News Widget: News widget works in anonymous share view
  • New API endpoint /api/share/{token}/news for fetching news without authentication
  • Supports both sourcePageId and legacy sourcePath filtering
  • Share-aware image URLs for media in news items
  • Only shows pages within the share scope
  • Public Media Access: Images and resources accessible via share token
  • Page media: /api/share/{token}/page/{uniqueId}/media/{filename}
  • Shared resources: /api/share/{token}/resources/media/{filename}
  • Resource subfolders: /api/share/{token}/resources/media/{folder}/{filename}
  • Links Widget Color System: Redesigned color options for intuitive background control
  • Container background: 4 options — None, Light, Accent, Primary (with visual color swatches)
  • Individual link background: 3 options — Default, Light, Primary (with visual color swatches)
  • Default links blend transparently into their container/row background
  • Automatic contrast detection: white text/icons on dark backgrounds, dark text on light
  • Telemetry expansion: Added 7 new server configuration fields to anonymous usage statistics
  • Country code, database type, default language, timezone, OS family, web server, Docker detection
  • Send report now button: Manual telemetry report trigger in admin Statistics tab
  • Breadcrumb Home label from navigation.json: Home breadcrumb now reads its label from the first item in navigation.json instead of hardcoded "Home"
  • Public sharing documentation: Comprehensive guide covering setup, scope, password protection, security, and admin overview

Changed

  • SystemFileService: Extended with news page retrieval for public context
  • getNewsPagesForShare() uses system-level GroupFolder access (no user session)
  • Recursive page discovery with share scope filtering
  • Excerpt extraction from first text widget
  • First image detection with share-aware URL rewriting
  • Color Utilities Refactored: Separated DARK_BACKGROUNDS and LIGHT_BACKGROUNDS arrays in colorUtils.js
  • New isLightBackground() function for accurate contrast detection
  • --color-primary-element-light correctly classified as light background (was incorrectly dark)
  • News widget layouts (List, Grid) updated to use new light background detection

Fixed

  • Public Share Page Tree: Fixed page tree only showing homepage when sharing a language root folder
  • extractSubtreeByScope() now correctly returns the full tree for language-root shares
  • All subfolders and pages are visible in the sidebar navigation
  • Links Widget Contrast: Fixed white text/icons on light backgrounds (Accent, Light)
  • Links without explicit background now blend transparently into their container
  • Correct contrast for all container/link background combinations
  • Webpack Chunk Caching: Fixed TypeError: n[e] is undefined when opening page editor after rebuild
  • Added content hash to chunk filenames ([contenthash:8]) to prevent stale cached chunks
  • Telemetry countryCode and timezone: Country code now derived from default_phone_region instead of default_language. Timezone uses smarter fallback: Nextcloud config → php.ini → UTC
  • Telemetry sending to wrong URL: Fixed telemetry using deprecated endpoint. Now correctly uses TelemetryService::sendReport()
  • Homepage breadcrumb label: Fixed breadcrumb showing page title instead of navigation label on the homepage itself
  • Files URL in Share Dialog: Fixed file ID using internal GroupFolder storage ID instead of user-mounted ID, and corrected URL format to include index.php prefix

Removed

  • HMAC token system: Removed unused PublicPageService, PublicPageController, and templates/public.php — dead code from an earlier public sharing approach that was never used

Security

  • All public endpoints use #[PublicPage] and #[NoCSRFRequired] attributes
  • Share token validation before any data access
  • Share scope path enforcement prevents access to pages outside the shared folder
  • Anonymous rate throttling (60 requests/minute) on all public endpoints
  • Password brute force protection (10 attempts/minute per IP) with random delays (100–300ms)
  • Session-based password auth — password never sent to browser or exposed in API responses
  • Nextcloud share link settings respected (shareapi_allow_links)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturem52gHbT8mXTWqFH4iSNkuu5vB+wlx9soo59UPs31A7tFoHe9ipoUyemUw94tnosKwj12P217nOwEQEFnSr059Bmndx8PbO4OGgALv3MkZppE6KJoglXIt2oLYwh48ALSlGDRkNU3ciWDTruxcO2KF541cglphiykpfqrp0nTBwz9KDiseor0Ts9qE9aXjYmxPQGKTmb1XEYg0L0h01T0+QTS0pyl4mozMspZY6wok7y6hMe7/GAv/tE2EOBlUudKN/l8cG6T8I4p6Qce4ChxHQXrFEOJy4nTnGaL9HAt91iIYl6Pc42qjdzv4gTAYlmHYreAXkxf2duLBapfAhS3mcuoArtf4V0e+IEOji3+yZNR9c9zE0UkeTqBSXSqZ0hyFAUcDMO5VRbHh4CtOYW3yY5skaSNrl6quM881IHN9ipvlFkIimm/gxttYI8Kh+9/kg7QZiEnx59JPkc8jPy7yoeATW/iFLmFNvgGh05j+Gm2EG81SlkgUmkEWxXVOjWKi8g/s0IQlZjzP/0ZwrsbnclXAkzxXR66jx0K9ajZbu9hLkCDDlJ71lYk5WnSYiZgqdllraAhc7kaPRQDIPW/PqH+CxVV+KB68TW/3wUwJvPewuMpTDxXN6uuZC2IymxXib9wn59TiXGpxRJDk6R9K4hqPmnwBV99NW9Oj8J6q1I=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.7
Release Details
UpdatedJan. 26, 2026, 9:51 p.m.
Changelog

Fixed

  • Code Block Rendering: Fixed code blocks corrupting after editing (#15)
  • Backticks no longer accumulate when saving and re-editing code blocks
  • Fixed double-processing of nested <code> tags inside <pre> elements
  • Code block content now correctly preserved through save/load cycles
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturefR/S9LkpLomqMbPE9qRCN51jLKAOMSBBCKWk1nyzwc5cK5N6NGBgTR5N2dcU038O2He96+BawNXePcpw4tUMoKYjLAt6DLr8iGq4+CSfGoFCYaGpoRm9RZS3hd0iVIgGeh81hXnEkWGII3bTaS0I2Mb4HWb2zxhViJESD8AiFYGtkdO4lIhwa0Sw1r5yQMxn2G+rNJM2XB+ySqeH5krhF6DnPMAsED9dK6R/LVXFfrgTpc2EFUoFPlXIqzwRM8bFAWbpNkRBb88n2wnKFYiE3bYJALPDXeUa7nw72NV15VK6K2JVpc5fZvcy8/Xz6M61aTPA6JtTMczbpzhzlwYeMk0W0/7PWbNdvtAXn6OYNuqkGHacCZcGMzf01Qb0HrQQm7kGGngfwK/avoPiz3oclnB75vQeH4wKMZojhoggxCzWwnfRPCF10UDh0AY/ofN2JOkMFLbpKUjI7suVty3r+vWKGZk5qbfbZ4w3E2YGBYnFZYVlceRa86EEBJuhCIvbXPWQDriyCWoAvgUksmuB/Nhhdbp1btDoqzGK9l2W44W4EAyOk2JX32cAKdzAjBcQlqvuvQoGuIhn8E0pORBH/w1T1J5tj8VPZl76lVopDOq400BQg0eaJQhURnlCCa/XAt5NY+AbBLXfaYFhYJiZGDLfg5QWenLgLNdjfaQd/3M=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.6
Release Details
UpdatedJan. 20, 2026, 10:05 p.m.
Changelog

Changed

  • Database Exception Handling: Use OCP\DB\Exception instead of Doctrine exceptions
  • Follows Nextcloud coding standards for database-agnostic error handling
  • Cleaner code without string-based error detection

Security

  • svg-sanitize: Updated from ^0.20 to ^0.22 to fix medium severity vulnerability (GHSA bypass)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureFKbWtadpIkxyQORuyKmtdyhKihh+TnOpv5TLpiInVKZE91KqljyU+oxQEOMEghDVY//reBY+zgArAWYOGB+c77eMdrpeblpFleaLPEPME9VjGxXK81ehLDtM3hPpnI10nNueL/wg+WPeWqNYG/IiyC1oJH5ks1yeiF91k6vunuDs7nHGw8luQQc6KNoLRwFJba2uQsC9s9eY4nwRSZ8YAlPrTGzU1JqQB0vQVDynOZio3tEvLUW22JPWTbrLOTkB95okcwV1t1h7kdrxb1E3XDYXZ/gkJq0FXUVg+FsKTQQnknZoOz1ZFUOaymknqb+MEQs1pgaufd+5NfcHIFw228GmVCNtGiAd+OCJdIlkWnKG45uL5z+fywTOEroY+liiYCmSCZq6bYDLnk4YP0PvVc02AyktC/0C/UYx5w8G3lh5xq7T4k6BpVvGyohUSr+GbnDybwJw5wfDpL1BRUSo9uWtBMa7/4ZOFFlBCuFe6/R50Vc1F28d5GYYRtRwB0+c58lacFeEluC1QJZBQvv5j+ktOi2FmWch9b8+0mKNdBTjt7XVU2SClcAJrA13+SzPsBJSE1LWeHEWg/10mAxz9P4kjDYfHAJs7SzUAh5E+MORwYKrybx4hLgh6Ufv9qgcXZeRwt0rTPIE3xYCymSUG3guNzsa4dFar/mpb64qy9U=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.5
Release Details
UpdatedJan. 20, 2026, 2:52 p.m.
Changelog

Fixed

  • PostgreSQL Support: Fixed database compatibility issues for PostgreSQL users
  • SetupService: Now correctly handles PostgreSQL duplicate key errors (SQLSTATE 23505)
  • LicenseService: Added null check for shared folder to prevent crashes during setup
  • AnalyticsService: Improved exception handling for unique constraint violations
  • Installation on PostgreSQL: Setup no longer fails when re-running or retrying installation
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCMaJ3B5mnvM6amFSYgSIl1zMz427DUBNfZLUlQ3gkTIaJIqwtTe0GVFB667GBiMomYz9rLe3pUDzGtp1zzd84PfFmXPEvwGftcfAmeawzTphAWlNAdC91KRdQaTWas73h6jEm/ShFCaVTjxE8aDRgjZIZzjrs95mSQFkeRTpN0nML+xqH28AkR2HIJL++3oWN7e1jpWd2HCyOLaMpbRDU+GJ6rGnBvBTj4MsoTVzFMs9cyKXWuaa0R9eCUDCumxAxnWL9aqdkf2A/GxpTGuzR2QktWHEnatZFVAf3LlVSw9YxG/hem9M/FBQ825ErXlsh7LUxBRW9gFpeeDfTn9M06E3Gqcy+BmbjTUn3lmfYjx2TZxU6idCfjr6mgCz2kaTG3vv7myuvyalVdaydrQpzLJ1BpWpEpGJ7tU6jytr/AU4THlvr76j+EvgNgtAor0bvzHgFc8oXbBOLwi5MI9oNC033F4zYKFajqiUuwUVtEtsSYz425NxKh6jSqikaN3F1yG3p2+ZlSBRyUJKsfu5fJraoPKlbqPnoOKnK5K6fv7HQOlCGbD+FYNlVDjN/PhSLFdnypOzP3rq0SUVrjvibzKqASjP6E/FkBrbCwCf+yWHxKE0rLSYPAL6GOFKxtKib1jQ9iJlK1zlQMH7EyyF3maT9cVaBk42M+a4a3JFlkQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.4
Release Details
UpdatedJan. 20, 2026, 6:43 a.m.
Changelog

Fixed

  • App Store Cache: New version to bypass cached signature data in Nextcloud App Store
  • No functional changes from 0.9.3
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureGfWF48G9tm/QACyvvgQbDVriO6sYowvPNvLlP2sDX5bsPsh137Ttl0OtdKKS8z5SRmJ2FhyXUlBDgKyD895MIIjXtlc7QINL/fvk784n/7dm/kvEPIKsVVKAYlUSLt7aTUib0s824ahT0VilV9JZSH4934R8KkDVE3B9Ksk1J/EA37o5Ojmk4WsFCKfMnz0Yaq1dZIpEQ1jLSIdYTfdlVsqEL6Sam3+m1A1uBYqZQqnIczeqh2xoSh8n9QnlBQmDC3hzBW5gybKbXpufSwxaSJgxcfXDbQQBT1P6oOstHbchAeGt84Fb6wDlgVD8I/C2NUE7kwt/wWfojCWtGbiejxPFiz1A/fAgKvt3RpFdW7QhsQLqja0LHmvAb/FLgBNqaqUh4Pv3r+OSDlxXzMvZ/0imvqpp2XmhhpmAgW9CF/T64Pg2nNjwy/Nb+2e7el2sGfmDbYSSE77+P508rcGfexP0D98dfo7bAgsHdXmiK+82PFPc/Vo8cXwLkdChHunk660tIraABOukG4ytJCjNgiqWPMa9gIhJ/2d9/PZyB0b3UFvNkVgRiQxaG39fLzR5zbBCeEbQf2mbVARX080Q+jhkj9EK9ybKvdBJ3whjpeJsFiHsRxlmCXJubj6YMBA9Ilm7LaXDxob6lcLa1cnav/evH7uWX+NExN3GuFHq+Z4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.3
Release Details
UpdatedJan. 20, 2026, 6:24 a.m.
Changelog

Fixed

  • App Store Certificate Sync: Re-registered app with new certificate (serial 4824) to sync with App Store database
  • Previous releases were signed correctly but App Store database had outdated certificate reference
  • Resolves "Certificate 4822 has been revoked" error for all users
  • No functional changes from 0.9.2

Documentation

  • Added certificate verification section to RELEASE_CHECKLIST.md
  • Added warnings about certificate management best practices
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturepiCaGChVVrjsXiKqs1rnsOLZQkqXg3euTL07Lmz8dM/3wvfWDDNczY3NFuwxcvuDJ7ebhaybka6uEsVgQgiTXI48nnNLMoFj7yFYc+NcHNTIpQ8f0wSXvy4K3GaeHYvjAlc30fLegAAcRHLfAVvmNBi6Y7t2xwRfsMCThqTgOrblKRTncOxVsGg7VJ1AeDdTvETLyUT6MWrqYHF/9amV4+M6D9enJ8XNRUI5P+IYDAW84q65EpSiykK3TCfHVQ2GGJJHMblZvGPgS2xVS0tih4N24KRdIPjetD0YDrA25Mj9XJhtIEc1tKvI2T2Cn/C7ErIC3cSW6HjS0oFLNKU4QmjJRhXYSlOJ4k6YaxjPn0pR9tZYLj51EIptOrb8SnAlvUpDnC1v+ExxPwxctomncAVRfXKcRuPE5hCtNBfiElcqGMTtG5G5FwntNaog5yBo3PwibNe5Wb671AwzJ2DnxKseiKxtcgPfEpgNlZnU+BHiam/GXYI29CVHo61QOEGUdrJS59Ey0eXlXdTEisT3LaTi77AMVF2WxG0v0y1yI8uhOWOxzDviLheiRk5/7tLmWK6v7uDLu8IhUzH49jmRNABdCaHALKd5eu+ON5TZ2ZK5YfnxbTDHILzbt+BP/2lToTNh6S+2QgVxx195hk4dCVfGZwfV5B3OAni4VcEfqmk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0