Initial commit: Port Nimara CRM (Layers 0-4)
Some checks failed
Build & Push Docker Images / build-and-push (push) Has been cancelled
Build & Push Docker Images / deploy (push) Has been cancelled
Build & Push Docker Images / lint (push) Has been cancelled

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>
This commit is contained in:
2026-03-26 11:52:51 +01:00
commit 67d7e6e3d5
572 changed files with 86496 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
import { env } from '@/lib/env';
import { logger } from '@/lib/logger';
const BASE_URL = env.DOCUMENSO_API_URL;
const API_KEY = env.DOCUMENSO_API_KEY;
async function documensoFetch(path: string, options?: RequestInit): Promise<unknown> {
const res = await fetch(`${BASE_URL}${path}`, {
...options,
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
...options?.headers,
},
});
if (!res.ok) {
const err = await res.text();
logger.error({ path, status: res.status, err }, 'Documenso API error');
throw new Error(`Documenso API error: ${res.status}`);
}
return res.json();
}
export interface DocumensoRecipient {
name: string;
email: string;
role: string;
signingOrder: number;
}
export interface DocumensoDocument {
id: string;
status: string;
recipients: Array<{
id: string;
name: string;
email: string;
role: string;
signingOrder: number;
status: string;
signingUrl?: string;
embeddedUrl?: string;
}>;
}
export async function createDocument(
title: string,
pdfBase64: string,
recipients: DocumensoRecipient[],
): Promise<DocumensoDocument> {
return documensoFetch('/api/v1/documents', {
method: 'POST',
body: JSON.stringify({ title, document: pdfBase64, recipients }),
}) as Promise<DocumensoDocument>;
}
export async function sendDocument(docId: string): Promise<DocumensoDocument> {
return documensoFetch(`/api/v1/documents/${docId}/send`, {
method: 'POST',
}) as Promise<DocumensoDocument>;
}
export async function getDocument(docId: string): Promise<DocumensoDocument> {
return documensoFetch(`/api/v1/documents/${docId}`) as Promise<DocumensoDocument>;
}
export async function sendReminder(docId: string, signerId: string): Promise<void> {
await documensoFetch(`/api/v1/documents/${docId}/recipients/${signerId}/remind`, {
method: 'POST',
});
}
export async function downloadSignedPdf(docId: string): Promise<Buffer> {
const res = await fetch(`${BASE_URL}/api/v1/documents/${docId}/download`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!res.ok) {
const err = await res.text();
logger.error({ docId, status: res.status, err }, 'Documenso download error');
throw new Error(`Documenso download error: ${res.status}`);
}
const arrayBuffer = await res.arrayBuffer();
return Buffer.from(arrayBuffer);
}