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>
This commit is contained in:
65
src/types/api.ts
Normal file
65
src/types/api.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Common API response and utility types used across the CRM.
|
||||
*/
|
||||
|
||||
/** Generic wrapper for all API responses */
|
||||
export interface ApiResponse<T> {
|
||||
data: T;
|
||||
success: true;
|
||||
}
|
||||
|
||||
/** Wrapper for API error responses */
|
||||
export interface ApiErrorResponse {
|
||||
success: false;
|
||||
error: ApiError;
|
||||
}
|
||||
|
||||
/** Paginated list response */
|
||||
export interface PaginatedResponse<T> {
|
||||
data: T[];
|
||||
pagination: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
hasNextPage: boolean;
|
||||
hasPreviousPage: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/** Standard API error shape */
|
||||
export interface ApiError {
|
||||
code: string;
|
||||
message: string;
|
||||
field?: string;
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** Sort configuration for list queries */
|
||||
export interface SortConfig<T extends string = string> {
|
||||
field: T;
|
||||
direction: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
/** Filter configuration for list queries */
|
||||
export interface FilterConfig {
|
||||
field: string;
|
||||
operator: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'in' | 'notIn' | 'isNull' | 'isNotNull';
|
||||
value: string | number | boolean | string[] | number[] | null;
|
||||
}
|
||||
|
||||
/** Standard list query parameters */
|
||||
export interface ListQueryParams {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
sort?: SortConfig;
|
||||
filters?: FilterConfig[];
|
||||
search?: string;
|
||||
}
|
||||
|
||||
/** Standard mutation response */
|
||||
export interface MutationResponse {
|
||||
success: boolean;
|
||||
id?: string;
|
||||
message?: string;
|
||||
}
|
||||
56
src/types/auth.ts
Normal file
56
src/types/auth.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { RolePermissions, UserPreferences } from '@/lib/db/schema/users';
|
||||
import type { Port } from '@/lib/db/schema/ports';
|
||||
|
||||
/** Typed Better Auth user object */
|
||||
export interface AuthUser {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
image: string | null;
|
||||
emailVerified: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/** Typed Better Auth session object */
|
||||
export interface AuthSession {
|
||||
id: string;
|
||||
userId: string;
|
||||
token: string;
|
||||
expiresAt: Date;
|
||||
ipAddress: string | null;
|
||||
userAgent: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
user: AuthUser | null;
|
||||
}
|
||||
|
||||
/** Extended user profile (from user_profiles table) */
|
||||
export interface UserProfile {
|
||||
id: string;
|
||||
userId: string;
|
||||
displayName: string;
|
||||
avatarUrl: string | null;
|
||||
phone: string | null;
|
||||
isSuperAdmin: boolean;
|
||||
isActive: boolean;
|
||||
lastLoginAt: Date | null;
|
||||
preferences: UserPreferences;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/** Port context as seen by the authenticated user */
|
||||
export interface PortContext {
|
||||
port: Port;
|
||||
roleId: string;
|
||||
roleName: string;
|
||||
permissions: RolePermissions;
|
||||
}
|
||||
|
||||
/** Full authenticated user context (session + profile + port roles) */
|
||||
export interface AuthenticatedUser extends AuthUser {
|
||||
profile: UserProfile | null;
|
||||
portContexts: PortContext[];
|
||||
currentPortContext: PortContext | null;
|
||||
}
|
||||
61
src/types/domain.ts
Normal file
61
src/types/domain.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import type {
|
||||
PIPELINE_STAGES,
|
||||
BERTH_STATUSES,
|
||||
LEAD_CATEGORIES,
|
||||
DOCUMENT_TYPES,
|
||||
DOCUMENT_STATUSES,
|
||||
} from '@/lib/constants';
|
||||
|
||||
export type PipelineStage = (typeof PIPELINE_STAGES)[number];
|
||||
export type BerthStatus = (typeof BERTH_STATUSES)[number];
|
||||
export type LeadCategory = (typeof LEAD_CATEGORIES)[number];
|
||||
export type DocumentType = (typeof DOCUMENT_TYPES)[number];
|
||||
export type DocumentStatus = (typeof DOCUMENT_STATUSES)[number];
|
||||
|
||||
export interface Port {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
defaultCurrency: string;
|
||||
timezone: string;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
export interface Client {
|
||||
id: string;
|
||||
portId: string;
|
||||
fullName: string;
|
||||
companyName?: string | null;
|
||||
nationality?: string | null;
|
||||
source?: string | null;
|
||||
archivedAt?: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface Interest {
|
||||
id: string;
|
||||
portId: string;
|
||||
clientId: string;
|
||||
berthId?: string | null;
|
||||
pipelineStage: PipelineStage;
|
||||
leadCategory?: LeadCategory | null;
|
||||
source?: string | null;
|
||||
archivedAt?: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface Berth {
|
||||
id: string;
|
||||
portId: string;
|
||||
mooringNumber: string;
|
||||
area?: string | null;
|
||||
status: BerthStatus;
|
||||
lengthFt?: string | null;
|
||||
widthFt?: string | null;
|
||||
price?: string | null;
|
||||
priceCurrency: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
Reference in New Issue
Block a user