feat(company-memberships): service + validators + tests

Adds company-membership service with six operations (add, update, end,
setPrimary, listByCompany, listByClient), the corresponding Zod
validators, three socket events, and a unit-test suite covering the
portId-scoping rules, the unique_cm_exact conflict path, and the atomic
setPrimary transaction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Ciaccio
2026-04-24 12:07:58 +02:00
parent 037f2544e8
commit 15a79e7990
5 changed files with 816 additions and 0 deletions

View File

@@ -7,6 +7,7 @@ import { createWebhookSchema, updateWebhookSchema } from '@/lib/validators/webho
import { createFieldSchema, updateFieldSchema } from '@/lib/validators/custom-fields';
import { createYachtSchema, transferOwnershipSchema } from '@/lib/validators/yachts';
import { createCompanySchema } from '@/lib/validators/companies';
import { addMembershipSchema } from '@/lib/validators/company-memberships';
// ─── Client schemas ───────────────────────────────────────────────────────────
@@ -454,3 +455,31 @@ describe('createCompanySchema', () => {
expect(result.success).toBe(true);
});
});
// ─── Company membership schemas ──────────────────────────────────────────────
describe('addMembershipSchema', () => {
const validInput = {
clientId: 'client-uuid-1',
role: 'director' as const,
startDate: '2026-01-01',
};
it('rejects missing clientId', () => {
const result = addMembershipSchema.safeParse({
role: 'director',
startDate: '2026-01-01',
});
expect(result.success).toBe(false);
});
it('rejects invalid role', () => {
const result = addMembershipSchema.safeParse({ ...validInput, role: 'janitor' });
expect(result.success).toBe(false);
});
it('accepts minimal valid input', () => {
const result = addMembershipSchema.safeParse(validInput);
expect(result.success).toBe(true);
});
});