tag:github.com,2008:https://github.com/sendrec/sendrec/releases Tags from sendrec 2026-03-19T16:10:31Z tag:github.com,2008:Repository/1149170768/v1.82.0 2026-03-19T18:14:55Z v1.82.0 <p>fix: remove invalid table alias from ListOwnerComments query (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/117">#117</a>)</p> <p>The query used `v.user_id` and `v.comment_mode` but the FROM clause <br />had no `v` alias, causing a PostgreSQL error that was caught as a <br />generic error and returned as 404. This broke the comments section <br />on VideoDetail for all users.</p> github-actions tag:github.com,2008:Repository/1149170768/v1.81.0 2026-03-10T21:20:04Z v1.81.0 <p>refactor: clean code phase 2 — file splits and DRY fixes (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/116">#116</a>)</p> <p>* refactor: extract plans.IsPaid helper, replace 5 inline checks</p> <p>* refactor: extract organization.IsAdminOrOwner, replace 7 inline checks</p> <p>* refactor: deduplicate token functions — export from auth, remove from sso</p> <p>* refactor: extract ValidateRetentionDays to shared validate package</p> <p>Add RetentionDays validator to the validate package and remove the <br />duplicate inline validRetentionDays map from organization.go. Also <br />add Password validator and corresponding tests in preparation for <br />deduplicating the three password validation blocks in auth.go.</p> <p>* refactor: extract ValidatePassword to shared validate package</p> <p>Replace the three duplicate password length checks in auth.go <br />(Register, ResetPassword, UpdateUser) with validate.Password calls, <br />and replace the inline validRetentionDays map with validate.RetentionDays.</p> <p>* refactor: extract recordViewAsync, deduplicate 3 identical goroutines</p> <p>* refactor: extract lookupVideoByShareToken, deduplicate 3 queries</p> <p>* fix: use httputil.WriteError in integration handler for consistent JSON errors</p> <p>* refactor: extract shared Video/Folder/Tag types to types/video.ts</p> <p>Creates web/src/types/video.ts with canonical Video, VideoTag, Folder, and <br />Tag interfaces. Removes duplicate inline declarations from VideoDetail.tsx and <br />Library.tsx. VideoDetail-only fields (document, documentStatus, <br />transcriptionLanguage, noiseReduction, playlists) are marked optional so <br />Library can safely use the same type without carrying unused fields.</p> <p>* refactor: extract formatDuration/formatDate/expiryLabel/copyToClipboard to shared utils</p> <p>Creates web/src/utils/format.ts with formatDuration, formatDate, formatChartDate, <br />and expiryLabel, and web/src/utils/clipboard.ts with copyToClipboard. Removes all <br />inline duplicate definitions from VideoDetail.tsx, Library.tsx, PlaylistDetail.tsx, <br />Playlists.tsx, Analytics.tsx, Recorder.tsx, and CameraRecorder.tsx, replacing them <br />with imports from the new shared modules.</p> <p>* refactor: extract useToast hook and Toast component, deduplicate 3 pages</p> <p>* refactor: extract ConfirmDialog component and shared type</p> <p>* refactor: extract useRecording hook, deduplicate Recorder and CameraRecorder</p> <p>* refactor: deduplicate billing handlers with parameterized entity helpers</p> <p>* refactor: extract shared playlist JS and loadPlaylistVideos helper</p> <p>* refactor: split VideoDetail into focused sub-components</p> <p>Extract SharingSection, TranscriptSection, and CommentsSection from <br />the 2088-line VideoDetail.tsx into a VideoDetail/ directory with an <br />index.tsx orchestrator and three focused sub-components.</p> <p>* refactor: split Settings into focused section components</p> <p>Break up the 1923-line Settings.tsx into Settings/ directory with <br />index.tsx orchestrator plus 7 section components and shared types.</p> <p>* refactor: split OrgSettings into focused section components</p> <p>Break up the 1237-line OrgSettings.tsx into OrgSettings/ directory <br />with index.tsx orchestrator plus 4 section components and shared types.</p> <p>* refactor: replace duplicated formatTime/formatTimestamp with shared formatDuration</p> <p>Remove 5 identical time-formatting functions from TrimModal, <br />FillerRemovalModal, SilenceRemovalModal, CommentsSection, and <br />TranscriptSection — all replaced with existing formatDuration from <br />utils/format.ts.</p> <p>* refactor: split SSO handler into protocol-specific files</p> <p>Split the 1124-line handler.go into handler.go (shared utilities, <br />identity/SCIM management), handler_oidc.go (OIDC flows), and <br />handler_saml.go (SAML flows).</p> <p>* refactor: split Analytics, PlaylistDetail, and Library into sub-components</p> <p>Analytics.tsx (920 lines) → Analytics/ with 8 files. <br />PlaylistDetail.tsx (960 lines) → PlaylistDetail/ with 3 files. <br />Library.tsx (893 lines) → Library/ with 3 files.</p> github-actions tag:github.com,2008:Repository/1149170768/v1.80.0 2026-03-07T05:38:22Z v1.80.0 <p>feat: growth quick wins — watch page CTA, GitHub star in welcome emai…</p> <p>…l, README Docker snippet, Railway template</p> github-actions tag:github.com,2008:Repository/1149170768/v1.79.0 2026-03-06T22:57:19Z v1.79.0 <p>Add SCIM 2.0 provisioning (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/114">#114</a>)</p> <p>* feat: add SCIM tokens migration and resource types</p> <p>Migration 000057 creates organization_scim_tokens table. <br />internal/scim/types.go defines SCIM 2.0 resource types.</p> <p>* feat: add SCIM bearer token auth middleware</p> <p>* feat: add SCIM token management endpoints</p> <p>* feat: add SCIM ServiceProviderConfig and Schemas endpoints</p> <p>* feat: add SCIM Create User endpoint</p> <p>* feat: add SCIM Get and List Users endpoints</p> <p>* feat: add SCIM Patch and Delete User endpoints</p> <p>* feat: register SCIM routes and token management endpoints</p> <p>* feat: add SCIM provisioning card to OrgSettings</p> <p>* fix: SCIM status field as numeric string, constant-time token comparison, emailVerified check</p> <p>* fix: handle unchecked error returns in SCIM package</p> <p>* Fix SCIM provisioning edge cases</p> <p>* Upgrade Go toolchain and polish SCIM guide</p> <p>* Update golangci-lint for Go 1.26</p> github-actions tag:github.com,2008:Repository/1149170768/v1.78.0 2026-03-06T20:30:08Z v1.78.0 <p>feat: add SAML 2.0 support for workspace SSO (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/113">#113</a>)</p> <p>* feat: add SAML columns to organization_sso_configs</p> <p>* feat: add crewjam/saml dependency</p> <p>* feat: add SAML metadata parsing</p> <p>* feat: implement SAMLProvider with AuthURL and Exchange</p> <p>* feat: extend SaveConfig to support SAML provider</p> <p>* feat: extend GetConfig to return SAML fields</p> <p>* feat: add SAML ACS callback and update InitiateOrgSSO for SAML</p> <p>* feat: add SP metadata endpoint for SAML</p> <p>* feat: register SAML ACS and SP metadata routes</p> <p>* feat: add SAML protocol toggle to SSO settings</p> <p>* fix: address code review issues in SAML implementation</p> <p>- Use SameSite=None; Secure for SAML state cookie (cross-origin POST) <br />- Add 1MB body size limit on metadata URL fetch <br />- Accept KeyDescriptors with unspecified use attribute (Azure AD compat) <br />- Scan nullable OIDC columns into pointer types in OrgCallback <br />- Add happy-path test for InitiateOrgSSO with SAML config <br />- Add test for unspecified KeyDescriptor use attribute</p> <p>* fix: surface crewjam/saml private error for SAML debugging</p> <p>* fix: track SAML AuthnRequest ID for InResponseTo validation</p> <p>crewjam/saml requires the AuthnRequest ID to validate the response's <br />InResponseTo attribute. Store the request ID alongside the state in the <br />sso_state cookie (state|requestID format) and pass it to ParseResponse.</p> <p>* feat: add OIDC and SAML setup guides to SSO settings</p> github-actions tag:github.com,2008:Repository/1149170768/v1.77.0 2026-03-06T18:02:35Z v1.77.0 <p>Add workspace E2E tests (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/111">#111</a>)</p> <p>* test: add workspace E2E tests for CRUD, viewer role, and video transfer</p> <p>Add 18 new Playwright E2E tests across 3 spec files: <br />- workspace.spec.ts: create, rename, settings, delete (5 tests) <br />- workspace-viewer.spec.ts: viewer permissions and role changes (8 tests) <br />- workspace-transfer.spec.ts: move videos between scopes (5 tests)</p> <p>Supporting changes: <br />- Add second test user for multi-user scenarios <br />- Add workspace API helpers (create, invite, accept, switch, upload) <br />- Add workspace tables to truncate list in global setup</p> <p>* ci: add workflow_dispatch trigger to CI workflow</p> <p>Allow manual triggering of CI including e2e tests on any branch. <br />Only users with repo write access can trigger workflow_dispatch.</p> <p>* fix: correct table names in e2e truncate list</p> <p>sso_configs → organization_sso_configs <br />social_identities → external_identities</p> <p>* fix: pass access token in workspace e2e API calls</p> <p>loginViaAPI stores the access token from the login response. <br />Workspace helpers and spec files pass it as Authorization header <br />on direct page.request calls (page navigation works via SPA <br />refresh flow, but direct API calls need the Bearer token).</p> <p>* fix: set e2e test user to pro plan to allow multiple workspaces</p> <p>Free plan limits to 1 workspace owned. E2e specs each create their <br />own workspace, so the test user needs pro to avoid 403 on the <br />second workspace creation.</p> <p>* fix: resolve e2e test failures for workspace specs</p> <p>- Extract invite token from API response instead of DB query <br /> (DB stores hash, not raw token) <br />- Use getByLabel for rename assertion instead of input[value] <br />- Scope transfer dialog selectors to dialog role to avoid <br /> strict mode violations from duplicate text matches <br />- Remove unused queryRows import from workspace helpers</p> <p>* fix: wait for settings page load before asserting workspace name and members</p> <p>* fix: set org context before navigating to settings in e2e tests</p> <p>OrgSettings page redirects to / when selectedOrgId doesn't match the <br />route orgId. Fresh Playwright pages have empty localStorage, so the <br />workspace was never "selected". Fix by setting localStorage before <br />navigating to settings. Also add Date.now() suffix to workspace names <br />to avoid duplicates when serial suites retry.</p> <p>* fix: use specific role selector in viewer members list test</p> <p>getByText('viewer') matched 5 elements (role dropdowns, invite dropdown). <br />Use getByLabel('Role for email') to target the specific user's role <br />dropdown and check its value instead.</p> <p>* fix: use member name for role selector aria-label in viewer test</p> <p>The role dropdown aria-label uses member.name || member.email, and the <br />test user has name "E2E Viewer User", so the label doesn't match email.</p> <p>* fix: scope dropdown assertions to .dropdown-menu in viewer tests</p> <p>getByText('Analytics') matched both nav link and dropdown action link. <br />Scope all dropdown assertions to the .dropdown-menu container.</p> <p>* fix: use member.id instead of member.userId in role change tests</p> <p>The members API returns { id, name, email, role, joinedAt }, not userId.</p> <p>* feat: hide write actions from viewers on VideoDetail page</p> <p>Viewers can still watch videos, view analytics, download, copy share <br />links, and read comments/transcripts. Hidden for viewers: edit title, <br />pin, delete, share settings, AI actions, editing, organize, CTA, and <br />delete comments.</p> <p>* fix: add RequireWriter to folder/tag/playlist routes, viewer tests, and UX fixes</p> <p>- Apply RequireWriter middleware to write routes for folders, tags, and playlists <br /> (security gap: viewers could mutate these resources via direct API calls) <br />- Add 8 VideoDetail viewer role unit tests verifying write actions are hidden <br />- Simplify TransferDialog disabled button logic <br />- Replace flaky waitForTimeout with meaningful assertions in E2E workspace helpers</p> <p>* fix: add type annotations to useOrganization mock to fix typecheck</p> <p>The mock's default null values caused TS to infer literal null types, <br />breaking the viewer test overrides that set string/object values.</p> <p>* docs: add workspace endpoints to OpenAPI spec</p> <p>Add 15 new endpoints: members (list, remove, update role), invites <br />(send, list, revoke, accept), org billing (get, checkout, cancel), <br />org SSO config (get, save, delete), and video transfer.</p> <p>Add 15 new schemas and update role enums to include viewer, <br />plan enums to include business.</p> alexneamtu tag:github.com,2008:Repository/1149170768/v1.76.0 2026-03-05T09:56:57Z v1.76.0 <p>feat: add data retention with auto-delete, pin exemption, and warning…</p> <p>… emails (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/109">#109</a>)</p> <p>* feat(retention): add migration for retention_days, pinned, retention_warned_at</p> <p>* feat(retention): add PUT /api/videos/{id}/pin toggle endpoint</p> <p>* feat(retention): add retentionDays to user profile GET/PUT</p> <p>- Add RetentionDays field to userResponse and updateUserRequest <br />- Include retention_days in GetUser SELECT query <br />- Add validation (0, 30, 60, 90, 180, 365) in UpdateUser handler <br />- Add 2 tests for valid and invalid retention_days updates</p> <p>* feat(retention): add retentionDays to org settings GET/PUT</p> <p>- Add RetentionDays field to orgListItem, orgDetailResponse, updateOrgRequest <br />- Include retention_days in List, Get, and Update SELECT queries <br />- Add validation (0, 30, 60, 90, 180, 365) and dynamic SET clause in Update <br />- Add 2 tests for valid and invalid retention_days updates</p> <p>* feat(retention): expose retentionDays in limits API</p> <p>Resolve effective retention for current context: org retention_days <br />for workspace videos, user retention_days for personal videos.</p> <p>* feat(retention): add SendRetentionWarning email method</p> <p>Listmonk transactional email for 7-day retention warning. <br />Bypasses allowlist. Template ID via LISTMONK_RETENTION_WARNING_TEMPLATE_ID.</p> <p>* feat(retention): add daily retention worker with warn + delete passes</p> <p>Daily ticker warns users 7 days before deletion, then soft-deletes <br />videos after grace period. Cleans up playlist_videos on delete.</p> <p>* feat(retention): add Data Retention dropdown to Settings and Workspace Settings</p> <p>Select from Off/30/60/90/180/365 days. Personal and workspace scopes. <br />Pinned videos excluded (noted in description).</p> <p>* feat(retention): add pin toggle on VideoDetail and pin indicator on Library</p> <p>Pin/Unpin button in video actions bar with filled/outline icon. <br />Pinned badge in metadata. Pin indicator overlay on library video cards.</p> <p>* docs: add retention and pin endpoints to OpenAPI spec</p> <p>Add PUT /videos/{id}/pin, retentionDays to user/org/limits responses, <br />pinned + retentionWarnedAt to video schema, org endpoints with retention.</p> <p>* fix: consistent card footer height and add pin shortcut in library</p> <p>Use flexbox on video cards so the Copy link footer aligns at the <br />bottom regardless of metadata height. Add Pin/Unpin option to the <br />three-dot menu on library video cards.</p> <p>* fix: include pinned field in video list API response</p> <p>Without this, the Library page couldn't show pin indicators and <br />VideoDetail lost pinned state on refresh.</p> <p>* fix: use share_token instead of share_id in retention worker query</p> <p>Column is share_token, not share_id.</p> github-actions tag:github.com,2008:Repository/1149170768/v1.75.0 2026-03-04T20:13:20Z v1.75.0 <p>fix: remove videos from playlists on delete (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/108">#108</a>)</p> <p>Videos are soft-deleted (status='deleted') so the ON DELETE CASCADE <br />on playlist_videos never fires. Explicitly delete playlist_videos <br />rows in both single and batch delete handlers.</p> github-actions tag:github.com,2008:Repository/1149170768/v1.74.0 2026-03-03T11:25:36Z v1.74.0 <p>feat: add Jira and GitHub integrations (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/107">#107</a>)</p> <p>* feat: add user_integrations migration (000050)</p> <p>Create user_integrations table to store per-user integration <br />configs (Jira, GitHub) with encrypted JSONB config column.</p> <p>* feat: add core integration types and AES-256-GCM encryption</p> <p>IssueCreator interface, request/response types, DeriveKey, <br />Encrypt, Decrypt, MaskToken — 4 passing tests.</p> <p>* feat: add GitHub and Jira issue creation clients</p> <p>GitHubClient: Bearer auth, POST /repos/{owner}/{repo}/issues, <br />markdown body with collapsible transcript. JiraClient: Basic <br />auth, POST /rest/api/3/issue, ADF body format. Both implement <br />IssueCreator interface — 10 passing tests total.</p> <p>* feat: add integration handler with CRUD and create-issue endpoints</p> <p>List, Save, Delete, Test, CreateIssue handlers with encrypted <br />token storage, config validation, and provider factory — 15 tests.</p> <p>* feat: wire integration routes into server</p> <p>Register integration CRUD under /api/settings/integrations and <br />create-issue under /api/videos/{id}/create-issue.</p> <p>* feat: add Integrations card to Settings and Create Issue to VideoDetail</p> <p>Settings: expandable GitHub/Jira config forms with save, test <br />connection, and disconnect. VideoDetail: Create Issue button <br />with dropdown for configured providers. 677 frontend tests pass.</p> <p>* docs: add integration endpoints to OpenAPI spec</p> <p>5 new endpoints: list/save/delete integrations, test connection, <br />create issue from video. Schemas for GitHub/Jira configs.</p> <p>* fix: address lint issues in integration package</p> <p>Check error returns for resp.Body.Close, io.Copy, and json <br />Encode/Decode. Lowercase error string per staticcheck ST1005.</p> <p>* fix: use org-aware video query in CreateIssue handler</p> <p>Apply the same organization_id filter used by other video <br />endpoints — personal videos require organization_id IS NULL, <br />org videos require matching organization_id.</p> <p>* fix: use transcript_json column in create-issue query</p> <p>The videos table has transcript_json (JSONB) not transcript (TEXT). <br />The non-existent column caused SQL errors returning 404.</p> <p>* fix: persist integration settings on page reload</p> <p>- Frontend: populate form fields from saved integration config on load <br />- Backend: detect masked token values and preserve existing encrypted <br /> tokens when re-saving without changing the token</p> <p>* fix: remove unused encryptTokenFields function</p> github-actions tag:github.com,2008:Repository/1149170768/v1.73.0 2026-03-02T17:21:29Z v1.73.0 <p>feat: add REGISTRATION_ENABLED env var to disable signups (<a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/pull/105">#105</a>)</p> <p>* feat: add REGISTRATION_ENABLED env var to disable signups</p> <p><span class="issue-keyword tooltipped tooltipped-se">Closes</span> <a class="issue-link js-issue-link" href="https://github.com/sendrec/sendrec/issues/104">#104</a>.</p> <p>- Backend: guard on Register handler returns 403 when disabled <br />- Health endpoint exposes registrationEnabled for frontend <br />- Frontend: Register redirects to /login, Login hides sign-up link <br />- Default: true (registration enabled), set to "false" to disable</p> <p>* refactor: move staging and preview deploys to Coolify Dockerfile builds</p> <p>- Staging: remove Docker Hub publish, Coolify builds from repo on deploy <br />- Preview: replace SSH + docker run with Coolify API (PATCH branch + deploy) <br />- Docker images now only published on production releases (v* tags)</p> <p>* refactor: dynamic Coolify preview apps per PR</p> <p>Replace single shared preview app with dynamic per-PR app creation. <br />Each PR gets its own Coolify app (sendrec-pr-{N}) with a unique URL <br />(pr-{N}.app.sendrec.eu). Apps are auto-deleted on PR close.</p> github-actions