Feat/invites#227
Open
IamKirbki wants to merge 48 commits into
Open
Conversation
- Introduced ProjectInviteListResponse model for listing project invites. - Added ListProjectInvitesParams for pagination support in listing invites. - Implemented RevokeProjectInvite, ListProjectInvites, AcceptProjectInvite, and GetInviteDetails methods in the Client interface. - Created corresponding request and response parsing functions for project invite operations. - Enhanced AdminsStore with HardDeleteProjectAdmin method for direct deletion of project admins. - Expanded InvitesStore with methods to handle project invites: GetInviteByToken, AcceptProjectInvite, RevokeProjectInvite, and ListProjectInvites. - Updated database migration to enforce unique constraint on invite tokens.
- Added a new "Invites" section in the settings menu with a UserPlus icon. - Enhanced user search functionality in the ListDetail component. - Updated OrganizationEventRuleEdit to improve accessibility with better aria-labels. - Modified the InviteController to support filtering project invites by status, role, and expiration dates. - Updated OpenAPI resources to include new query parameters for invite management. - Refactored invite handling in the management store to support new filtering options. - Changed database table references from "invites" to "project_invites" for clarity. - Implemented revoke project invite functionality with proper middleware handling.
Co-authored-by: Copilot <copilot@github.com>
…rchy logic Co-authored-by: Copilot <copilot@github.com>
…rtain contexts Co-authored-by: Copilot <copilot@github.com>
…okens - Updated API paths to accept a combined token and nonce pair for invite acceptance and revocation. - Modified ProjectInvite interface to include nonce. - Implemented nonce generation and encryption in the invite creation process. - Adjusted database schema to store nonce alongside the invite token. - Enhanced invite handling logic to support nonce verification during acceptance and revocation. - Updated frontend components to handle the new token-nonce structure. - Added necessary environment configurations for invite secret key. Co-authored-by: Copilot <copilot@github.com>
…ment for project admins
…e token generation failure
- Changed API endpoint parameter from `tokenNouncePair` to `token` for clarity. - Updated the `ProjectPushProviderPlatform` enum to replace `email` with `mail`. - Refactored `AcceptInvite` component to handle new token structure and improved error handling. - Removed unused `mashTokenNonce` function and simplified token concatenation logic. - Updated database migrations to reflect changes in project provider platform naming. - Adjusted related functions and interfaces to ensure consistency with new naming conventions. - Removed email platform support from various components and validations. Co-authored-by: Copilot <copilot@github.com>
Add store-level tests asserting ListUserSchedules / ListOrganizationSchedules report has_pending_events=true while events are unfired and flip to false once all events are marked fired. Guards the badge-stays-lit-forever regression that this branch fixes.
- Regenerate console management OpenAPI bindings after the inbox open->read rename (read_at, /read paths) - Update inbox-detail-table console consumer to the read terminology so it typechecks against the regenerated types; fixes prettier formatting - Restore oapi.ListStateDraft/ListStateReady constants in lists_test.go - Use *int16 (ptr.To) for InboxMessage.Priority in consumer test - Fix client inbox spec tests: /inbox/read path and required identifier
- SMS template data: align textTemplateDataSchema and TextTemplateData to
the API shape ({ body }); fix SMS preview reading data.text -> data.body
- Enable mode: "onChange" on NewCampaign and ProjectOnboardingDomain forms
so formState.isValid updates and the submit button isn't stuck disabled
- optionalPhoneSchema: accept "" so an InlineEdit phone can be cleared
- Trim names/IDs in list, journey, and device form schemas to reject
whitespace-only input
- Users.createUser: optional-chain optional fields to avoid a TypeError
when only some identity fields are provided
- EmailContentPreview: drop render-phase setCompiledHtml("") (effect already
clears it) and return null instead of undefined for non-email templates
- searchTimeoutRef: initialize empty instead of scheduling a throwaway timer
Replace the hand-rolled SHA-256/HMAC implementation with crypto/sha256 + crypto/hmac. The "stdlib panics under WASM" rationale does not hold for the current TinyGo wasi toolchain (verified: stdlib sha256/hmac produce correct known-answer values under tinygo 0.40.1 + wasmtime), and the Mailgun provider already relies on stdlib crypto. This removes ~130 lines of unaudited custom crypto from the SES request signer. Also set Spec.Webhook to false: WebhookHandler is a no-op stub that drops all events (SNS parsing is unimplemented), so advertising webhook support would register an endpoint that silently discards every delivery/bounce event.
The unused linter now flags it since the consumer test package compiles again (it was masked by the prior inbox_test.go compile error).
Amazon SES and Mailgun declared Platforms: [PlatformEmail], but Spec.Platforms is the push-platform list. On provider creation, autoAssignPushProvider upserts the provider as the default push provider for every platform it lists, bypassing the validPlatforms allowlist (ios/android/web only). This wrote an invalid "email" row into project_push_providers for what are email-channel providers. Email providers are identified by Channels: [ChannelEmail] (as resend already does); they have no push platform. Drop the Platforms declaration from both and remove the now-unused PlatformEmail constant, reverting channel.go to its prior state.
Route due inbox messages through the inbox process pipeline (with a stable Msg-Id for idempotent re-injection) instead of emitting an analytics event, and gate dispatch on IsDue() so future-scheduled messages published immediately by the client/campaign paths wait for the scheduler. Also guard generic email/SMS composition against an empty recipient.
Move the destructive 'DROP TABLE campaign_sends' out of the inbox-table creation migration into its own migration with a down migration that recreates the table structure (its final post-broadcast_id, composite-PK shape). The inbox migration's down is now a clean inverse. Also correct the ScanDue* comments: FOR UPDATE SKIP LOCKED is not run in a held transaction, so idempotency actually comes from the scheduler's stable Msg-Id and the sent_at guard, not the row lock.
Backend - Fix UnarchiveList: drop the GetList pre-check that filtered deleted_at IS NULL, which made every restore return 404; rely on the store returning sql.ErrNoRows on zero rows affected. - Fix UnarchiveCampaign handler: add the missing generic error branch so non-ErrNoRows DB errors no longer fall through to a false 204. - Make UnarchiveJourney store return sql.ErrNoRows on zero rows affected, matching the list/campaign stores, and simplify the handler. - Change the list filter semantics from "include deleted (both)" to "archived only" so the archived view can paginate server-side with a correct total_count. Renamed the store/controller param to archivedOnly and updated the include_deleted OAPI parameter description accordingly. Frontend - Replace the client-side limit:100 + .filter() archived view with real server-side offset pagination in the Lists, Campaigns and Journeys views (dedicated archivedOffset, prev/next, footer shown in both views, offset reset on toggle/search/unarchive). Tests - Add store tests covering the archived-only filter and the unarchive happy path plus ErrNoRows on already-active and non-existent rows, for lists, campaigns and journeys.
fix: add has_pending_events field to user and organization schedules
…-components-and-provider-crud fix: enhance components with error handling and improve rate limit logic
…lidation # Conflicts: # console/src/views/settings/IntegrationSetup.tsx # console/src/views/users/ListCreateForm.tsx
Normalize arbitrary timezone formats (GMT+2, EST, UTC+05:30, etc) to canonical IANA strings during CSV import. Includes timezone resolver, tests, and timezone selection UI improvements.
…lidation # Conflicts: # console/src/views/users/Users.tsx
Feat/frontend form validation
# Conflicts: # internal/http/controllers/v1/client/oapi/resources_gen.go # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/wasm/test/provider.wasm
Add inbox messaging system for organizations and users
…s-provider # Conflicts: # go.mod # go.sum # internal/http/controllers/v1/client/oapi/resources_gen.go # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/wasm/test/action.wasm # internal/wasm/test/provider.wasm
…-files # Conflicts: # go.mod # go.sum # internal/http/controllers/v1/client/oapi/resources_gen.go # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/store/journey/journeys_test.go
Feat: Added new email providers
feat: enhance journey, campaign, and list management with unarchive f…
# Conflicts: # console/package-lock.json # console/pnpm-lock.yaml # console/src/views/broadcast/CreateBroadcastDialog.tsx # console/src/views/settings/IntegrationSetup.tsx # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/rbac/model.go # internal/wasm/test/action.wasm # internal/wasm/test/provider.wasm
jeroenrinzema
previously approved these changes
Jun 16, 2026
jeroenrinzema
left a comment
Contributor
There was a problem hiding this comment.
Reviewed and approved. Resolved conflicts with main: merged RBAC invites+inbox resources, took main's react-hook-form rate_limit handling in IntegrationSetup/CreateBroadcastDialog, regenerated oapi (v2.7.0), kept main's lockfiles (frozen-lockfile verified), took main's wasm. go build + tsc + eslint + rbac tests green.
Rework project invites to resolve by the invitee's IdP-verified email
instead of an encrypted token, and fix five bugs reported on the PR.
Bug fixes:
- migration: project_id NOT NULL CASCADE; inviter_admin_id is now
nullable with ON DELETE SET NULL so deleting an inviting admin no
longer violates the constraint
- ListProjectInvites: expires_before/after comparisons were inverted and
cast to ::date (dropping the time); fixed and switched to ::timestamptz
- accept compares emails case-insensitively (strings.EqualFold) and
stores invitee email lowercased
- replace uuid.MustParse(actor.ID) with checked uuid.Parse; create now
returns 201, revoke 204, accept 200 + the project summary
- remove BackfillProjectTuples from the accept hot path; OpenFGA tuples
are written after the DB commit to avoid orphaned grants
Flow:
- delete AES-GCM token/nonce machinery and the public invite endpoint
- add GET /api/invites/mine and POST /api/invites/{inviteID}/accept,
authorized by email match rather than project RBAC
- same-org / new-email guard on create (reject inviting an email that
belongs to another organization until admin-org M2M lands)
- console: replace the token AcceptInvite page with a /invites inbox;
revoke by id; drop the dead INVITES_SECRET_KEY config
deb2ff7 to
a6724fc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: project invite system + auth and project scoping improvements
(closes: #218 #220)
This adds a full project invite flow and updates auth and project scoping.
Project invite system (enterprise)
Full invite flow behind a
//go:build enterpriseguard. OSS builds return 404 on all invite endpoints.project_invitestable with AES-256-GCM encrypted token storage, nonce column, expiry, and revoke/accept timestamps/invites/:tokenpage handles unauthenticated users, wrong account detection, and auto-accept after Clerk registration via?autoAccept=1skipAuthRedirectProject listing scoped to admin membership
ListProjectsnow queries viaproject_adminsjoin instead of org-wide scan.GetProjectaccepts an optionaladminIDto populate the real role, removing the hardcoded"admin"return.Auth: dual JWT support
WithJWTnow supports RS256 (Clerk/JWKS) and HS256 (basic auth) simultaneously via amultiKeyfuncdispatcher, configured viaAUTH_JWKS_URL.Closes #218
Closes #220