Skip to content

v0.58.0

Choose a tag to compare

@github-actions github-actions released this 21 Jul 19:59
· 552 commits to main since this release
e6f9380

Security

  • Platform role assignment is now enforced at the database layer: the request-path database roles carry column-scoped grants on the user table that exclude the platform role column, so role changes can only happen through the dedicated operator/owner role-assignment endpoint. Unused write privileges the request-path roles held on the user table were revoked outright. No behavior change for any existing flow; this is defense in depth, verified by CI invariants against the live catalog.
  • Guild role assignment (promoting a member to guild admin) is now enforced at the database layer too. The endpoint runs on the system engine, and the shared guild database role no longer holds write access to change a membership's role — so a guild member cannot be elevated except through the guild-admin endpoint. Self-leave is scoped to your own membership, and request-path membership creation is pinned to a plain member. No behavior change for any existing flow; verified by CI invariants.
  • Cross-guild access grants (the time-bound PAM / break-glass rows) can now only be written by the system-engine endpoints that already gate them by capability; the request-path database roles keep read access but no longer hold write access to the grants table. Defense in depth, verified by CI invariants.
  • The per-guild and platform Postgres role-name prefixes (GUILD_ROLE_PREFIX, PLATFORM_ROLE_PREFIX) are now validated to identifier-safe characters at startup, so a misconfigured prefix fails closed at boot rather than reaching role-name DDL. Defense in depth (these come from operator config, not user input).

Added

  • Member pickers no longer download the entire guild roster: new slim, searchable, paginated endpoints serve member typeaheads (guild-wide, per-initiative, and per-project — the last scoped to the project's assignable write-access members), each returning just id, name, avatar, and status for a bounded page of results instead of every member's full profile. The assignee pickers (task edit, inline composer, bulk edit) and the assignee filter now search server-side against the project's members, the user-reference property picker searches its initiative's members, and the project/task pages no longer prefetch the full membership — so opening a project with thousands of members no longer transfers megabytes of inline avatars to render a dropdown. The task detail now carries its author inline (so the "Created by …" chip needs no roster lookup) and the trash owner-reassign picker lists the eligible owners returned with the prompt, so both drop their full-roster fetch too. Event attendee pickers (create dialog and settings) now use the same initiative-scoped typeahead. Mention autocomplete is server-backed too: the document editor's @-mention no longer loads the whole embedded member list (it searches the initiative's members on demand), the mention-search endpoint is now paginated in the same envelope as the other member searches, and both the document and comment mention pickers render member avatars.
  • Multiple sign-in providers: the sign-in page now offers a button for every SSO provider the server has configured, not just one. Operators manage additional OIDC providers in Settings → Authentication — with presets for Google and Microsoft Entra, and a custom option for any OIDC identity provider (Keycloak, Authentik, Zitadel, …) — alongside the existing platform SSO form. Client secrets are write-only: set or replaced, never displayed.
  • Per-guild authentication: on platforms configured for per-guild auth, guild admins get an Authentication tab to manage the guild's own OIDC identity providers (presets, write-only client secrets, and the guild's callback URL for IdP registration) and to require that members reach the guild only with a session signed in through one of them. An unsatisfied session gets a sign-in dialog that returns to the page it was on, and completing it upgrades the session in place — satisfying one guild never un-satisfies another. Requirements bind everyone (members, admins, and platform support alike) and are enforced in the database's row security across every surface — guild pages, cross-guild "my" views, realtime sockets (re-checked for the life of the connection), and media/download tokens — while long-lived integration credentials (API keys, device tokens, automation) deliberately never satisfy them. To prevent lockouts, an admin can only require a provider their own session has signed in with, and a required provider can't be deleted until the requirement changes. Outside per-guild auth posture the surface is absent entirely. Each guild also gets a shareable sign-in page (/guild/{id}/login, linked with a copy button from the Authentication tab): signing in through the guild's IdP admits the user to the guild as a plain member — provisioning their account on first sign-in when the provider allows it, honoring the guild's member capacity — so a single-guild user's entire login experience can live at their guild.
  • Per-guild sign-in is now an operator entitlement. On per-guild-auth platforms the platform Guilds dashboard gains a per-guild toggle that turns a guild's Authentication surface on or off (the guild's own admins can't grant it themselves). Turning it off is non-destructive: the guild's providers are kept and existing members keep signing in through them — and any existing sign-in requirement stays enforced — it only closes the guild's auth-config surface and stops new accounts onboarding through the guild's IdP. The toggle appears only under per-guild auth posture.

Changed

  • The platform single sign-on configuration now lives on its provider-registry entry — the same registry that backs additional and per-guild providers — instead of a parallel copy in app settings kept in sync behind the scenes. The settings page, login, and background sync all read one record now; the migration folds any existing configuration in automatically and the settings screen is unchanged. OIDC_* environment values still pre-fill the provider on first boot only.
  • Accounts created through single sign-on no longer carry an unusable placeholder password — they store no password at all, and password login for such an account is simply refused until one is explicitly set. The legacy per-user OIDC columns (superseded last release by the per-provider identity links) are dropped; the migration re-copies any not-yet-migrated data first, so upgrades that skipped a release lose nothing.
  • Login posture (platform-wide vs per-guild sign-in) is now a deploy-time setting (AUTH_SCOPE), read once at startup, rather than a runtime toggle in platform settings. The Authentication settings page shows the active posture as a read-only badge; the "coming soon" per-guild radio and its endpoint are gone. Posture is infra-agnostic — nothing about a specific host or vendor is baked in.
  • The sidebar and the initiatives landing page no longer download every document (and, on the landing page, every project) just to show per-initiative count badges. New grouped-counts endpoints return the per-initiative totals in one query, honoring the same visibility rules as the lists — so the badges stay accurate while large guilds stop transferring their whole corpus on every page. The sidebar's queue and counter-group badges use the same endpoints now too, replacing capped list fetches that silently undercounted past 100 items and dragged each item's full sharing state along.
  • The "new document" and wikilink dialogs no longer download every document in the guild to populate their template picker. Both pickers are now searchable typeaheads backed by the server: templates are filtered in SQL (by template flag and document type) and searched by title across the whole guild, so opening the dialog fetches a bounded page instead of the entire document corpus. Picking a template for a whiteboard or spreadsheet no longer lists text-document templates. The documents list gained the same filters for callers that need them.
  • The guild projects list no longer loads every visible project's full object graph just to filter and paginate it in Python. The archived/template filters, ordering (per-user manual order), and pagination now run in SQL, so a page fetches only the rows it returns and the reported total is exact rather than truncated. A search param (name substring, matching the "my projects" list) and an opt-in slim projection (id, name, icon, initiative, and your permission level — without documents, grants, tags, or the nested initiative) let project pickers and similar list-only callers fetch a bounded, lightweight page.
  • Task pickers no longer download full task rows just to show a title list. A new slim task typeahead (id + title, searched by title in SQL and scoped to an initiative or the whole guild) backs the queue item's linked-task picker and the command palette's task search, so each keystroke fetches a bounded, lightweight page instead of every matching task's assignees, status, tags, properties, and comment counts.
  • Sidebar rows use their full width: an initiative, project, or tool row's name and count now span the whole row until you hover it, at which point the settings/"+" button slides in and the name shrinks to make room (rather than the button permanently reserving space or overlapping the text). The reveal animation is skipped for users who prefer reduced motion.
  • Export menus in tool headers now group their formats under a "Backup" heading (the importable JSON envelope) and a "Report" heading (PDF, CSV, Excel, Markdown, and other renderings), so it's clear which download can be re-imported.
  • Calendar pages now load events and task markers in a single request instead of two. New calendar-entries endpoints (per-guild and cross-guild "my calendar") return the union of calendar events and in-window task start/due markers over the visible date range, each leg still gated by the same per-resource access rules as the standalone lists. The Events page and My Calendar consume the aggregate through one query; My Calendar now also windows its tasks to the viewport and shows every in-window task rather than only the first page.

Fixed

  • Signing in through single sign-on no longer sends the app into a request storm: the sign-in callback finished, updated the session, and then re-ran itself off its own update, re-fetching the current user, the guild list, and access grants dozens of times before settling. The callback is now consumed exactly once, and the guild list no longer reloads every time the current user is refreshed.
  • Comment, document-summary, and guild-list error messages now route through the shared error-message helper: the user sees a localized message (and rate-limit errors are surfaced as such) instead of an untranslated backend error code.
  • A database created or restored in a Postgres cluster where the platform "admin" → "operator" role rename had already run no longer loses its platform-staff row-security coverage: a repair migration finishes the rename by re-binding the affected policies (access-grant queue, platform user list/management) to the operator role and removing the leftover one. Without it, operators and owners saw only their own rows in the access-grant queue and the platform user list on such databases.
  • The sidebar "Edit tag" dialog is no longer visually broken — the name field now fills the row and the color picker sits beside it, instead of the color picker taking the full width and collapsing the name field to a sliver.
  • On mobile, opening the three-dot menu next to an initiative or project in the sidebar no longer dismisses the sidebar drawer.
  • Removed redundant spacing between icons and labels across buttons throughout the app; the button's built-in gap now handles it consistently.
  • The "My Tasks" page no longer returns a 500 error when filtered by a custom property. The cross-guild task views load property definitions per guild schema now, instead of querying a table that isn't visible on that request's connection.
  • The dashboard's "Upcoming tasks" list no longer sorts urgent tasks last. It sorted by a hand-rolled priority map that omitted urgent (and invented unused critical/none keys), so every urgent task fell into the fallback bucket and sorted after lower-priority ones. Priority ordering now flows from a single source of truth in lib/sorting.ts, derived from the backend TaskPriority enum, that every priority-list UI shares — so it can't drift again.
  • The "My Documents" page's data fetching now routes through the shared API client wrapper like its sibling "My Projects"/"My Calendar" views, instead of a hand-rolled fetcher that bypassed it — so native (Capacitor) base-URL rewriting and request handling apply consistently.

Downloads

Android App

No new app build this release — installed apps update automatically over the air on next launch.

Docker Image

docker pull morelitea/initiative:0.58.0

Or use latest tag. View on Docker Hub.