# Type Sharing Strategy This document explains how types are shared between the frontend and backend in the Mosaic Stack monorepo. ## Overview All types that are used by both frontend and backend live in the `@mosaic/shared` package. This ensures: - **Type safety** across the entire stack - **Single source of truth** for data structures - **Automatic type updates** when the API changes - **Reduced duplication** and maintenance burden ## Package Structure ``` packages/shared/ ├── src/ │ ├── types/ │ │ ├── index.ts # Main export file │ │ ├── enums.ts # Shared enums (TaskStatus, etc.) │ │ ├── database.types.ts # Database entity types │ │ └── auth.types.ts # Authentication types (NEW) │ ├── utils/ │ └── constants.ts └── package.json ``` ## Authentication Types ### Shared Types (`@mosaic/shared`) These types are used by **both** frontend and backend: #### `AuthUser` The authenticated user object that's safe to expose to clients. ```typescript interface AuthUser { readonly id: string; email: string; name: string; image?: string; emailVerified?: boolean; } ``` #### `AuthSession` Session data returned after successful authentication. ```typescript interface AuthSession { user: AuthUser; session: { id: string; token: string; expiresAt: Date; }; } ``` #### `Session`, `Account` Full database entity types for sessions and OAuth accounts. #### `LoginRequest`, `LoginResponse` Request/response payloads for authentication endpoints. #### `OAuthProvider` Supported OAuth providers: `"authentik" | "google" | "github"` #### `OAuthCallbackParams` Query parameters from OAuth callback redirects. ### Backend-Only Types Types that are only used by the backend stay in `apps/api/src/auth/types/`: #### `BetterAuthRequest` Internal type for BetterAuth handler compatibility (extends web standard `Request`). **Why backend-only?** This is an implementation detail of how NestJS integrates with BetterAuth. The frontend doesn't need to know about it. ## Usage Examples ### In the Backend (API) ```typescript // apps/api/src/auth/auth.controller.ts import { AuthUser } from "@mosaic/shared"; @Get("profile") @UseGuards(AuthGuard) getProfile(@CurrentUser() user: AuthUser) { return { id: user.id, email: user.email, name: user.name, }; } ``` ### In the Frontend (Web) ```typescript // apps/web/app/components/UserProfile.tsx import type { AuthUser } from "@mosaic/shared"; export function UserProfile({ user }: { user: AuthUser }) { return (

{user.name}

{user.email}

{user.emailVerified && Verified}
); } ``` ### API Response Types ```typescript // Both FE and BE can use this import type { ApiResponse, AuthSession } from "@mosaic/shared"; // Backend returns this const response: ApiResponse = { success: true, data: { user: { id: "...", email: "...", name: "..." }, session: { id: "...", token: "...", expiresAt: new Date() }, }, }; // Frontend consumes this async function login(email: string, password: string) { const response = await fetch("/api/auth/login", { method: "POST", body: JSON.stringify({ email, password }), }); const data: ApiResponse = await response.json(); if (data.success) { // TypeScript knows data.data exists and is AuthSession saveSession(data.data); } } ``` ## Database Types The `@mosaic/shared` package also exports database entity types that match the Prisma schema: - `User` - Full user entity (includes all fields from DB) - `Workspace`, `Task`, `Event`, `Project` - Other entities - Enums: `TaskStatus`, `TaskPriority`, `ProjectStatus`, etc. ### Key Difference: `User` vs `AuthUser` | Type | Purpose | Fields | Used By | |------|---------|--------|---------| | `User` | Full database entity | All DB fields including sensitive data | Backend internal logic | | `AuthUser` | Safe client-exposed subset | Only public fields (no preferences, etc.) | API responses, Frontend | **Example:** ```typescript // Backend internal logic import { User } from "@mosaic/shared"; async function updateUserPreferences(userId: string, prefs: User["preferences"]) { // Has access to all fields including preferences } // API response import { AuthUser } from "@mosaic/shared"; function sanitizeUser(user: User): AuthUser { return { id: user.id, email: user.email, name: user.name, image: user.image, emailVerified: user.emailVerified, }; // Preferences and other sensitive fields are excluded } ``` ## Adding New Shared Types When adding new types that should be shared: 1. **Determine if it should be shared:** - ✅ API request/response payloads - ✅ Database entity shapes - ✅ Business domain types - ✅ Enums and constants - ❌ Backend-only implementation details - ❌ Frontend-only UI component props 2. **Add to the appropriate file:** - Database entities → `database.types.ts` - Auth-related → `auth.types.ts` - Enums → `enums.ts` - General API types → `index.ts` 3. **Export from `index.ts`:** ```typescript export * from "./your-new-types"; ``` 4. **Build the shared package:** ```bash cd packages/shared pnpm build ``` 5. **Use in your apps:** ```typescript import { YourType } from "@mosaic/shared"; ``` ## Type Versioning Since this is a monorepo, all packages use the same version of `@mosaic/shared`. When you: 1. **Change a shared type** - Both FE and BE automatically get the update 2. **Add a new field** - TypeScript will show errors where the field is missing 3. **Remove a field** - TypeScript will show errors where the field is still used This ensures the frontend and backend never drift out of sync. ## Benefits ### Type Safety ```typescript // If the backend changes AuthUser.name to AuthUser.displayName, // the frontend will get TypeScript errors everywhere AuthUser is used. // You'll fix all uses before deploying. ``` ### Auto-Complete ```typescript // Frontend developers get full autocomplete for API types const user: AuthUser = await fetchUser(); user. // <-- IDE shows: id, email, name, image, emailVerified ``` ### Refactoring ```typescript // Rename a field? TypeScript finds all usages across FE and BE // No need to grep or search manually ``` ### Documentation ```typescript // The types ARE the documentation // Frontend developers see exactly what the API returns ``` ## Current Shared Types ### Authentication (`auth.types.ts`) - `AuthUser` - Authenticated user info - `AuthSession` - Session data - `Session` - Full session entity - `Account` - OAuth account entity - `LoginRequest`, `LoginResponse` - `OAuthProvider`, `OAuthCallbackParams` ### Database Entities (`database.types.ts`) - `User` - Full user entity - `Workspace`, `WorkspaceMember` - `Task`, `Event`, `Project` - `ActivityLog`, `MemoryEmbedding` ### Enums (`enums.ts`) - `TaskStatus`, `TaskPriority` - `ProjectStatus` - `WorkspaceMemberRole` - `ActivityAction`, `EntityType` ### API Utilities (`index.ts`) - `ApiResponse` - Standard response wrapper - `PaginatedResponse` - Paginated data - `HealthStatus` - Health check format --- **Remember:** If a type is used by both frontend and backend, it belongs in `@mosaic/shared`. If it's only used by one side, keep it local to that application.