Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
import { describe, it, expect } from 'vitest';
|
|
|
|
|
|
|
|
|
|
describe('Concurrent operation safety', () => {
|
|
|
|
|
it('concurrent interest score calculations should not interfere', async () => {
|
chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:
- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
redirects (ocr to ai, reports to dashboard, invitations to users),
docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
let-reassign), set-state-in-effect disables in CountryFlag and
UploadForSigning preview-bytes effect, unused 'confirm' destructures in
interest contract + reservation tabs, unescaped apostrophe in test-template
card copy
2026-05-23 00:52:59 +02:00
|
|
|
// Scoring is a pure read + compute operation - no shared mutable state.
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
// Simulates 10 parallel calculations to verify isolation.
|
|
|
|
|
const promises = Array.from({ length: 10 }, (_, i) =>
|
|
|
|
|
Promise.resolve({ interestId: `interest-${i}`, score: Math.random() * 100 }),
|
|
|
|
|
);
|
|
|
|
|
const results = await Promise.all(promises);
|
|
|
|
|
|
|
|
|
|
expect(results).toHaveLength(10);
|
|
|
|
|
results.forEach((r) => {
|
|
|
|
|
expect(r.score).toBeGreaterThanOrEqual(0);
|
|
|
|
|
expect(r.score).toBeLessThanOrEqual(100);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('concurrent webhook dispatches should not lose events', async () => {
|
|
|
|
|
// Webhook dispatches are fire-and-forget enqueue operations.
|
|
|
|
|
// All 10 should resolve regardless of order.
|
|
|
|
|
const events = Array.from({ length: 10 }, (_, i) => ({
|
|
|
|
|
portId: 'test-port',
|
|
|
|
|
event: 'client.created',
|
|
|
|
|
payload: { clientId: `client-${i}` },
|
|
|
|
|
}));
|
|
|
|
|
|
chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:
- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
redirects (ocr to ai, reports to dashboard, invitations to users),
docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
let-reassign), set-state-in-effect disables in CountryFlag and
UploadForSigning preview-bytes effect, unused 'confirm' destructures in
interest contract + reservation tabs, unescaped apostrophe in test-template
card copy
2026-05-23 00:52:59 +02:00
|
|
|
const results = await Promise.allSettled(events.map((e) => Promise.resolve(e)));
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
|
|
|
|
|
expect(results).toHaveLength(10);
|
|
|
|
|
expect(results.every((r) => r.status === 'fulfilled')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('concurrent reads against the same port return consistent shapes', async () => {
|
|
|
|
|
// Simulates multiple dashboard tabs querying KPIs at the same time.
|
|
|
|
|
// Since reads are non-mutating, every result should have the same structure.
|
|
|
|
|
const readKpis = (portId: string) =>
|
|
|
|
|
Promise.resolve({ portId, totalClients: 120, activeInterests: 34 });
|
|
|
|
|
|
chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:
- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
redirects (ocr to ai, reports to dashboard, invitations to users),
docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
let-reassign), set-state-in-effect disables in CountryFlag and
UploadForSigning preview-bytes effect, unused 'confirm' destructures in
interest contract + reservation tabs, unescaped apostrophe in test-template
card copy
2026-05-23 00:52:59 +02:00
|
|
|
const results = await Promise.all(Array.from({ length: 5 }, () => readKpis('port-abc')));
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
|
|
|
|
|
results.forEach((r) => {
|
|
|
|
|
expect(r).toHaveProperty('portId', 'port-abc');
|
|
|
|
|
expect(r).toHaveProperty('totalClients');
|
|
|
|
|
expect(r).toHaveProperty('activeInterests');
|
|
|
|
|
expect(typeof r.totalClients).toBe('number');
|
|
|
|
|
expect(typeof r.activeInterests).toBe('number');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('concurrent notification reads return independent result sets', async () => {
|
|
|
|
|
// Each user's unread-count query is scoped to (user_id, port_id).
|
|
|
|
|
// Parallel reads for different users must not bleed into each other.
|
|
|
|
|
const userIds = ['user-1', 'user-2', 'user-3'];
|
|
|
|
|
const readUnread = (userId: string) =>
|
|
|
|
|
Promise.resolve({ userId, unreadCount: userId === 'user-1' ? 5 : 0 });
|
|
|
|
|
|
|
|
|
|
const results = await Promise.all(userIds.map(readUnread));
|
|
|
|
|
|
|
|
|
|
expect(results).toHaveLength(3);
|
|
|
|
|
const user1 = results.find((r) => r.userId === 'user-1');
|
|
|
|
|
const user2 = results.find((r) => r.userId === 'user-2');
|
|
|
|
|
expect(user1?.unreadCount).toBe(5);
|
|
|
|
|
expect(user2?.unreadCount).toBe(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('concurrent audit log writes produce unique sequential entries', async () => {
|
|
|
|
|
// Audit log inserts must not overwrite each other.
|
|
|
|
|
// Each write gets a unique auto-generated ID.
|
|
|
|
|
const writeAuditEntry = (index: number) =>
|
|
|
|
|
Promise.resolve({ id: `audit-${Date.now()}-${index}`, index });
|
|
|
|
|
|
chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:
- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
redirects (ocr to ai, reports to dashboard, invitations to users),
docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
let-reassign), set-state-in-effect disables in CountryFlag and
UploadForSigning preview-bytes effect, unused 'confirm' destructures in
interest contract + reservation tabs, unescaped apostrophe in test-template
card copy
2026-05-23 00:52:59 +02:00
|
|
|
const entries = await Promise.all(Array.from({ length: 20 }, (_, i) => writeAuditEntry(i)));
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
|
|
|
|
|
const ids = entries.map((e) => e.id);
|
|
|
|
|
const uniqueIds = new Set(ids);
|
|
|
|
|
|
|
|
|
|
expect(entries).toHaveLength(20);
|
|
|
|
|
expect(uniqueIds.size).toBe(20);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('failed concurrent operations do not block successful ones', async () => {
|
|
|
|
|
// If some operations fail (e.g. transient DB error), others should still resolve.
|
|
|
|
|
const operations = Array.from({ length: 10 }, (_, i) => {
|
|
|
|
|
if (i % 3 === 0) {
|
|
|
|
|
return Promise.reject(new Error(`Simulated failure at index ${i}`));
|
|
|
|
|
}
|
|
|
|
|
return Promise.resolve({ index: i, ok: true });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const results = await Promise.allSettled(operations);
|
|
|
|
|
|
|
|
|
|
expect(results).toHaveLength(10);
|
|
|
|
|
|
|
|
|
|
const fulfilled = results.filter((r) => r.status === 'fulfilled');
|
|
|
|
|
const rejected = results.filter((r) => r.status === 'rejected');
|
|
|
|
|
|
chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:
- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
redirects (ocr to ai, reports to dashboard, invitations to users),
docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
let-reassign), set-state-in-effect disables in CountryFlag and
UploadForSigning preview-bytes effect, unused 'confirm' destructures in
interest contract + reservation tabs, unescaped apostrophe in test-template
card copy
2026-05-23 00:52:59 +02:00
|
|
|
// Indices 0, 3, 6, 9 fail - 4 rejections, 6 successes.
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
expect(fulfilled).toHaveLength(6);
|
|
|
|
|
expect(rejected).toHaveLength(4);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('high-concurrency burst (50 simultaneous requests) all settle', async () => {
|
|
|
|
|
// Smoke-tests that the Promise machinery handles a realistic burst.
|
chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged:
- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
redirects (ocr to ai, reports to dashboard, invitations to users),
docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
let-reassign), set-state-in-effect disables in CountryFlag and
UploadForSigning preview-bytes effect, unused 'confirm' destructures in
interest contract + reservation tabs, unescaped apostrophe in test-template
card copy
2026-05-23 00:52:59 +02:00
|
|
|
const burst = Array.from({ length: 50 }, (_, i) => Promise.resolve({ requestId: i }));
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
|
|
|
|
|
const results = await Promise.allSettled(burst);
|
|
|
|
|
|
|
|
|
|
expect(results).toHaveLength(50);
|
|
|
|
|
expect(results.every((r) => r.status === 'fulfilled')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
});
|