feat(invites): implement invite-based self-service registration backend
- V45 migration: invite_tokens + invite_token_group_ids tables
- InviteToken entity with @ElementCollection group IDs
- InviteService: code generation, validation, redemption (pessimistic lock prevents TOCTOU), revoke, list
- RateLimitInterceptor (Caffeine-backed, 10 req/min per IP) registered via WebMvcConfigurer
- AuthController: GET /api/auth/invite/{code} + POST /api/auth/register (both public)
- InviteController: GET/POST/DELETE /api/invites (ADMIN_USER permission)
- SecurityConfig: permitAll for new public auth endpoints
- ErrorCode: INVITE_NOT_FOUND, INVITE_EXHAUSTED, INVITE_REVOKED, INVITE_EXPIRED
- 36 new tests (InviteServiceTest, AuthControllerTest, InviteControllerTest)
Closes #269
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE invite_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
code VARCHAR(10) UNIQUE NOT NULL,
|
||||
label VARCHAR(255),
|
||||
max_uses INTEGER,
|
||||
use_count INTEGER NOT NULL DEFAULT 0,
|
||||
prefill_first_name VARCHAR(255),
|
||||
prefill_last_name VARCHAR(255),
|
||||
prefill_email VARCHAR(255),
|
||||
expires_at TIMESTAMP,
|
||||
created_by UUID NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
revoked BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_invite_tokens_code ON invite_tokens(code);
|
||||
|
||||
CREATE TABLE invite_token_group_ids (
|
||||
invite_token_id UUID NOT NULL REFERENCES invite_tokens(id),
|
||||
group_id UUID NOT NULL,
|
||||
PRIMARY KEY (invite_token_id, group_id)
|
||||
);
|
||||
Reference in New Issue
Block a user