feat(auth): invite links for several people, invite by email, registration with approval or email domains
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m20s

- Invites: link /?invite=CODE, copy link, send by email, max uses with counter
- Registration modes closed | approval | domain | domain+approval | open, waiting list with approve/reject
- REGISTRATION_MODE / REGISTRATION_DOMAINS lock the admin setting; ALLOW_REGISTRATION=true is honoured

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-31 13:43:54 +01:00
1 parent db5c5cde9b
commit af77b9e809
24 files changed
+1077 -142

No files matched your search

+13 -3
View File
@@ -271,12 +271,13 @@ export const api = {
password: string,
displayName: string,
inviteCode?: string
): Promise<{ token: string; user: User }> {
const res = await request<{ token: string; user: User }>('/api/v1/auth/register', {
): Promise<{ token?: string; user?: User; pending?: boolean; message?: string }> {
const res = await request<{ token?: string; user?: User; pending?: boolean; message?: string }>('/api/v1/auth/register', {
method: 'POST',
body: JSON.stringify({ email, password, displayName, inviteCode: inviteCode || '' }),
});
setToken(res.token);
// Waiting for approval: no session yet
if (res.token) setToken(res.token);
return res;
},
@@ -1121,6 +1122,7 @@ export const api = {
email?: string;
role: string;
organizationId?: string;
maxUses?: number;
}): Promise<UserInvite> {
return request<UserInvite>('/api/v1/admin/invites', {
method: 'POST',
@@ -1128,6 +1130,14 @@ export const api = {
});
},
async adminSendInvite(id: string, email: string): Promise<UserInvite> {
return request<UserInvite>(`/api/v1/admin/invites/${id}/send`, { method: 'POST', body: JSON.stringify({ email }) });
},
async adminApproveUser(id: string): Promise<User> {
return request<User>(`/api/v1/admin/users/${id}/approve`, { method: 'POST' });
},
async adminDeleteInvite(id: string): Promise<void> {
await request(`/api/v1/admin/invites/${id}`, { method: 'DELETE' });
},