# 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.