The previous fix (Patch 021) read import.meta.env.VITE_BRIDGE_TOKEN, but
Vite only auto-exposes VITE_* in import.meta.env when the .env lives in
apps/client/. Our .env is at the monorepo root and is loaded via
loadEnv() in vite.config.ts, then injected through the define block
under the 'process.env' key. So the runtime variable lives at
process.env.VITE_BRIDGE_TOKEN, not import.meta.env.VITE_BRIDGE_TOKEN.
Without this, the bridge proxy received no Bearer header and returned
401 Unauthorized for every /database slash command request — exactly
what Corentin reported.
Patch 023.
Cross-origin (5173 vs 4000) blocked the auth cookie from reaching the
bridge — every /database slash command request 401'd silently. Two
changes:
1. vite.config.ts: add /bridge -> http://localhost:4000 proxy with
path rewrite + /bridge-events -> /api/events for SSE. Same-origin =
browser sends the auth cookie automatically.
2. bridge-client.ts: resolveBridgeUrl() defaults to /bridge instead
of absolute http://localhost:4000. Also adds a VITE_BRIDGE_TOKEN env
fallback for dev (the bridge requires Bearer auth and the Docmost
session cookie is HttpOnly so JS cannot read it).
Patch 021.
SpaceSidebar crashed with "Rendered more hooks than during the previous
render" because R3.6 added a useDisclosure() AFTER `if (!space) return`.
When `space` flipped from undefined (loading) to defined (loaded), the
hook count changed and React threw, triggering the Error Boundary and
blanking the page.
This single bug was the root cause of 5 reported failures (R4.7 smoke):
create page, sub-page, wikilink, /database, /template, /sync-block —
all blocked by the white screen.
Fix: hoist the hook above the conditional return. Hook order now stable.
Graph view was empty for users who built page hierarchies (sub-pages) but had
not placed any wikilinks. The graph service now queries pages.parent_page_id
as a second edge source (type: parent_child) and merges it with acadenice_backlink
edges, so hierarchy-only workspaces display meaningful graphs immediately.
- dto: added parent_child to LinkType enum; added slug field to GraphNode
- service: loadParentChildEdges (permission-filtered SQL), parallel merge with loadEdges
- controller: always appends parent_child to the effective type list
- client: graph-client.ts typed for parent_child and slug; graph-canvas renders
dashed grey lines for parent_child vs solid brand lines for wikilinks; legend
with aria-label; title/slug/untitled fallback chain for node labels
- space sidebar: Graph menu item -> /s/:spaceSlug/graph
- new route: /s/:spaceSlug/graph -> SpaceGraph page (injects spaceId filter)
- i18n: en-US + fr-FR keys for legend and space graph
- tests: 42 server + 59 client, all green; 10 new R4.6 tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per Corentin's feedback (2026-05-08): .env should be reserved for
server-side config (SMTP, DB, OIDC). Branding (name, colors, logo)
is admin/UI territory.
Changes:
- Remove BRAND_NAME / BRAND_LOGO_URL / BRAND_PRIMARY_COLOR /
BRAND_ACCENT_COLOR from .env.example, vite.config.ts define block
- Hardcode "AcadeDoc" + #2563eb / #7c3aed as defaults in
apps/client/src/lib/config.ts and brand-theme.ts
- getBrandTheme() now takes optional runtime overrides instead of
reading process.env (used by per-workspace branding hook to apply
DB-stored colors)
- Server getMailFromName() defaults to "AcadeDoc" hardcoded; only
MAIL_FROM_NAME env var can override
- Fix workspace-branding.spec.ts (was importing vitest in jest project,
R4.4 leftover bug, similar to Patch 017 scope)
- Fix environment.service.spec.ts (was missing ConfigService provider
in TestingModule, pre-existing upstream bug surfaced by jest run)
Tests: 13 brand-theme + 13 workspace-branding + 2 environment = 28
green. Per-workspace UI override via /settings/branding (R4.4) works
unchanged.
Patch 020.
Three upstream Docmost services (export, version, telemetry) require
'../../../package.json' relative to source. In nest start dist mode the
relative path resolves one level too short and crashes at boot.
Wrap each require in a try/catch fallback that walks up one extra level,
defaulting to { version: 'dev' } if neither resolves. Boot now succeeds
both in dev (tsx) and in dist (node dist/main).
Also adds docker-compose.dev.yml for an isolated dev stack on ports
5433/6380, kept in repo for future dev sessions.
Patch 018.
- Convert 17 server spec files from vitest to Jest (vi -> jest globals)
- Add jest.mock stubs for ESM-only prosemirror/html and collaboration modules
- Fix Zod v4 strict UUID validation failures in test fixtures (version byte [1-8] required)
- Add JwtAuthGuard.overrideGuard in all controller specs that lacked it
- Fix jest.Mock type inference (ReturnType<typeof jest.fn> -> jest.Mock) to prevent 'never' arg errors
- Delete vitest.config.ts (CJS), keep vitest.config.mts (ESM-compatible) on client
- Add global mocks for @excalidraw/excalidraw and @/main.tsx in client test-setup
- Result: client 38/38 suites 313/313 tests, server acadenice 21/21 suites 210/210 tests, 0 TS errors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bridges native Docmost mention notification pipeline (already active for
collab path) to the REST API path via NotificationEmitterService. Adds
AcadeniceNotificationsModule with mention detector, notification facade API,
preferences endpoint, /notifications full page, /settings/notifications
preferences page, and bell count polling (30s). No new DB migration —
native notifications table handles page.user_mention.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Custom bidirectional markdown converter (no new deps) with full round-trip
support for database-view, wikilink, mention nodes. DualEditor component wraps
PageEditor with a toolbar toggle (WYSIWYG<->markdown), lossy-switch modal, and
localStorage persistence per page. 77 tests covering 24 round-trip cases + 4
custom nodes + 9 edge cases. i18n FR+EN.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Minimal testid additions to 4 renderer files so Playwright can target
stable selectors: table-renderer, cell-{rowId}-{fieldName}, kanban-board,
kanban-column-{label}, kanban-card-{rowId}, calendar-renderer,
inline-editor-input, inline-editor-readonly.
Also adds Dockerfile.e2e for the client build used in docker-compose.e2e.yml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Authentik n'expose pas un scope 'groups' standard — demander ce scope
inconnu peut faire echouer l'authorize selon la config provider. Les
groups arrivent dans le claim 'groups' du scope 'profile' par defaut.
Defaut passe de 'openid email profile groups' vers 'openid email profile'.
Update env.example + ACADENICE_PATCHES.md doc associee.
Adds SAML_DISABLE_REQUESTED_AUTHN_CONTEXT env var, passed through
to the SAML strategy's disableRequestedAuthnContext option.
Defaults to existing behavior (element sent). Set to true to omit
the element when the IdP authenticates the user with a method that
does not match (e.g. MFA, FIDO, passwordless), which would
otherwise cause AADSTS75011 with Microsoft Entra ID.
* Improve cmd-k / ctrl-k behavior
Use cmd-k on macOS/iOS for search and keep ctrl-k everywhere else.
Fixes a bug where ctrl-k on macOS, which cuts to the end of the line,
was also triggering the search prompt.
* comment submit: cmd-enter (mac) / ctrl-enter (win/linux)
The "People with access" list in the page share modal used
<ScrollArea mah={250}>, which caps the container height but does not
make the inner viewport scroll (no fixed height is given to the
viewport). Items beyond ~4 entries were rendered correctly but clipped
out of view.
Switches to <ScrollArea.Autosize mah={400}>, which is Mantine's
dedicated primitive for "grow with content up to a max, then scroll".
Closes#2135