implement backend skeleton with MongoDB and Claude AI integration
- Add controllers (Auth, Chat, Event) with placeholder implementations - Add services (Auth, Chat, Event) with business logic interfaces - Add repositories with MongoDB/Mongoose models (User, Event, Chat) - Add middleware for JWT authentication - Add Claude AI adapter implementing AIProvider interface - Add utility modules for JWT and password handling - Add shared types and DTOs for User, CalendarEvent, ChatMessage - Configure routes with proper endpoint structure - Update app.ts with dependency injection setup - Add required dependencies: mongoose, bcrypt, jsonwebtoken, @anthropic-ai/sdk
This commit is contained in:
187
CLAUDE.md
Normal file
187
CLAUDE.md
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
**CalChat** is a calendar mobile app with AI support. The core concept is creating calendar events through a chat interface with an AI chatbot (Claude). Users can add, edit, and delete events via natural language conversation.
|
||||||
|
|
||||||
|
This is a fullstack TypeScript monorepo with npm workspaces.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Root (monorepo)
|
||||||
|
```bash
|
||||||
|
npm install # Install all dependencies for all workspaces
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client (apps/client) - Expo React Native app
|
||||||
|
```bash
|
||||||
|
npm run start -w @caldav/client # Start Expo dev server
|
||||||
|
npm run android -w @caldav/client # Start on Android
|
||||||
|
npm run ios -w @caldav/client # Start on iOS
|
||||||
|
npm run web -w @caldav/client # Start web version
|
||||||
|
npm run lint -w @caldav/client # Run ESLint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Server (apps/server) - Express.js backend
|
||||||
|
```bash
|
||||||
|
npm run dev -w @caldav/server # Start dev server with hot reload (tsx watch)
|
||||||
|
npm run build -w @caldav/server # Compile TypeScript
|
||||||
|
npm run start -w @caldav/server # Run compiled server (port 3000)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Technology Stack
|
||||||
|
|
||||||
|
| Area | Technology | Purpose |
|
||||||
|
|------|------------|---------|
|
||||||
|
| Frontend | React Native | Mobile UI Framework |
|
||||||
|
| | Expo | Development platform |
|
||||||
|
| | Expo-Router | File-based routing |
|
||||||
|
| | NativeWind | Tailwind CSS for React Native |
|
||||||
|
| Backend | Express.js | Web framework |
|
||||||
|
| | MongoDB | Database |
|
||||||
|
| | Mongoose | ODM |
|
||||||
|
| | Claude (Anthropic) | AI/LLM for chat |
|
||||||
|
| | JWT | Authentication |
|
||||||
|
| Planned | iCalendar | Event export/import |
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Workspace Structure
|
||||||
|
```
|
||||||
|
apps/client - @caldav/client - Expo React Native app
|
||||||
|
apps/server - @caldav/server - Express.js backend
|
||||||
|
packages/shared - @caldav/shared - Shared TypeScript types and models
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend Architecture (apps/client)
|
||||||
|
|
||||||
|
**Screens** (`src/app/`): Login, Register, Calendar, Chat, Event Detail, Notes - file-based routing via Expo-Router
|
||||||
|
|
||||||
|
**Services**: API Client for HTTP requests, plus AuthService, EventService, ChatService for domain logic
|
||||||
|
|
||||||
|
**Components**: Reusable UI (EventCard, ChatBubble, EventConfirmDialog, MonthSelector)
|
||||||
|
|
||||||
|
**Stores**: AuthStore (user + token), EventsStore (calendar events)
|
||||||
|
|
||||||
|
### Backend Architecture (apps/server)
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── app.ts # Entry point, DI setup, Express config
|
||||||
|
├── controllers/ # Request handlers
|
||||||
|
│ ├── AuthController.ts # login(), register(), refresh(), logout()
|
||||||
|
│ ├── ChatController.ts # sendMessage(), confirmEvent(), rejectEvent(), getConversations(), getConversation()
|
||||||
|
│ └── EventController.ts # create(), getById(), getAll(), getByDateRange(), update(), delete()
|
||||||
|
├── middleware/
|
||||||
|
│ └── AuthMiddleware.ts # authenticate() - JWT validation
|
||||||
|
├── routes/ # API endpoint definitions
|
||||||
|
│ ├── index.ts # Combines all routes under /api
|
||||||
|
│ ├── auth.routes.ts # /api/auth/*
|
||||||
|
│ ├── chat.routes.ts # /api/chat/* (protected)
|
||||||
|
│ └── event.routes.ts # /api/events/* (protected)
|
||||||
|
├── services/ # Business logic
|
||||||
|
│ ├── interfaces/ # DB-agnostic interfaces (for dependency injection)
|
||||||
|
│ │ ├── AIProvider.ts # processMessage()
|
||||||
|
│ │ ├── UserRepository.ts # + CreateUserData (server-internal DTO)
|
||||||
|
│ │ ├── EventRepository.ts
|
||||||
|
│ │ └── ChatRepository.ts
|
||||||
|
│ ├── AuthService.ts
|
||||||
|
│ ├── ChatService.ts
|
||||||
|
│ └── EventService.ts
|
||||||
|
├── repositories/ # Data access (DB-specific implementations)
|
||||||
|
│ ├── index.ts # Re-exports from ./mongo
|
||||||
|
│ └── mongo/ # MongoDB implementation
|
||||||
|
│ ├── models/ # Mongoose schemas
|
||||||
|
│ │ ├── UserModel.ts
|
||||||
|
│ │ ├── EventModel.ts
|
||||||
|
│ │ └── ChatModel.ts
|
||||||
|
│ ├── MongoUserRepository.ts
|
||||||
|
│ ├── MongoEventRepository.ts
|
||||||
|
│ └── MongoChatRepository.ts
|
||||||
|
├── ai/
|
||||||
|
│ └── ClaudeAdapter.ts # Implements AIProvider
|
||||||
|
└── utils/
|
||||||
|
├── jwt.ts # signToken(), verifyToken()
|
||||||
|
└── password.ts # hash(), compare()
|
||||||
|
```
|
||||||
|
|
||||||
|
**API Endpoints:**
|
||||||
|
- `POST /api/auth/login` - User login
|
||||||
|
- `POST /api/auth/register` - User registration
|
||||||
|
- `POST /api/auth/refresh` - Refresh JWT token
|
||||||
|
- `POST /api/auth/logout` - User logout
|
||||||
|
- `GET /api/events` - Get all events (protected)
|
||||||
|
- `GET /api/events/range` - Get events by date range (protected)
|
||||||
|
- `GET /api/events/:id` - Get single event (protected)
|
||||||
|
- `POST /api/events` - Create event (protected)
|
||||||
|
- `PUT /api/events/:id` - Update event (protected)
|
||||||
|
- `DELETE /api/events/:id` - Delete event (protected)
|
||||||
|
- `POST /api/chat/message` - Send message to AI (protected)
|
||||||
|
- `POST /api/chat/confirm/:conversationId/:messageId` - Confirm proposed event (protected)
|
||||||
|
- `POST /api/chat/reject/:conversationId/:messageId` - Reject proposed event (protected)
|
||||||
|
- `GET /api/chat/conversations` - Get all conversations (protected)
|
||||||
|
- `GET /api/chat/conversations/:id` - Get messages of a conversation with cursor-based pagination (protected)
|
||||||
|
- `GET /health` - Health check
|
||||||
|
|
||||||
|
### Shared Package (packages/shared)
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── index.ts
|
||||||
|
└── models/
|
||||||
|
├── index.ts
|
||||||
|
├── User.ts # User, CreateUserDTO, LoginDTO, AuthResponse
|
||||||
|
├── CalendarEvent.ts # CalendarEvent, CreateEventDTO, UpdateEventDTO
|
||||||
|
└── ChatMessage.ts # ChatMessage, Conversation, SendMessageDTO, CreateMessageDTO,
|
||||||
|
# GetMessagesOptions, ChatResponse, ConversationSummary
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Types:**
|
||||||
|
- `User`: id, email, displayName, passwordHash?, createdAt?, updatedAt?
|
||||||
|
- `CalendarEvent`: id, userId, title, description?, startTime, endTime, note?, isRecurring?, recurrenceRule?
|
||||||
|
- `ChatMessage`: id, conversationId, sender ('user' | 'assistant'), content, proposedEvent?
|
||||||
|
- `Conversation`: id, userId, createdAt?, updatedAt? (messages loaded separately via lazy loading)
|
||||||
|
- `CreateEventDTO`: Used for creating events AND for AI-proposed events
|
||||||
|
- `GetMessagesOptions`: Cursor-based pagination with `before?: string` and `limit?: number`
|
||||||
|
- `ConversationSummary`: id, lastMessage?, createdAt? (for conversation list)
|
||||||
|
|
||||||
|
### Database Abstraction
|
||||||
|
|
||||||
|
The repository pattern allows swapping databases:
|
||||||
|
- **Interfaces** (`services/interfaces/`) are DB-agnostic
|
||||||
|
- **Implementations** (`repositories/mongo/`) are DB-specific
|
||||||
|
- To add MySQL: create `repositories/mysql/` with TypeORM entities
|
||||||
|
|
||||||
|
## MVP Feature Scope
|
||||||
|
|
||||||
|
### Must-Have
|
||||||
|
- Chat interface with AI assistant (text input) for event management
|
||||||
|
- Calendar overview
|
||||||
|
- Manual event CRUD (without AI)
|
||||||
|
- View completed events
|
||||||
|
- Simple reminders
|
||||||
|
- One note per event
|
||||||
|
- Recurring events
|
||||||
|
|
||||||
|
### Nice-to-Have
|
||||||
|
- iCalendar import/export
|
||||||
|
- Multiple calendars
|
||||||
|
- CalDAV synchronization with external services
|
||||||
|
|
||||||
|
## Current Implementation Status
|
||||||
|
|
||||||
|
**Backend:** Skeleton complete - all files exist with `throw new Error('Not implemented')` placeholders. Ready for step-by-step implementation.
|
||||||
|
|
||||||
|
**Shared:** Types and DTOs defined and exported.
|
||||||
|
|
||||||
|
**Frontend:** Calendar screen partially implemented, Chat screen exists but not connected to backend.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Detailed architecture diagrams are in `docs/`:
|
||||||
|
- `technisches_brainstorm.tex` - Technical concept document (German)
|
||||||
|
- `architecture-class-diagram.puml` - Backend class diagram
|
||||||
|
- `frontend-class-diagram.puml` - Frontend class diagram
|
||||||
|
- `component-diagram.puml` - System component overview
|
||||||
@@ -8,12 +8,19 @@
|
|||||||
"start": "node dist/app.js"
|
"start": "node dist/app.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@anthropic-ai/sdk": "^0.71.2",
|
||||||
"@caldav/shared": "*",
|
"@caldav/shared": "*",
|
||||||
"express": "^5.2.1"
|
"bcrypt": "^6.0.0",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"mongoose": "^9.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"tsx": "^4.21.0"
|
"tsx": "^4.21.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
apps/server/src/ai/ClaudeAdapter.ts
Normal file
18
apps/server/src/ai/ClaudeAdapter.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import Anthropic from '@anthropic-ai/sdk';
|
||||||
|
import { AIProvider, AIContext, AIResponse } from '../services/interfaces';
|
||||||
|
|
||||||
|
export class ClaudeAdapter implements AIProvider {
|
||||||
|
private client: Anthropic;
|
||||||
|
private model: string;
|
||||||
|
|
||||||
|
constructor(apiKey?: string, model: string = 'claude-3-haiku-20240307') {
|
||||||
|
this.client = new Anthropic({
|
||||||
|
apiKey: apiKey || process.env.ANTHROPIC_API_KEY,
|
||||||
|
});
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
async processMessage(message: string, context: AIContext): Promise<AIResponse> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
1
apps/server/src/ai/index.ts
Normal file
1
apps/server/src/ai/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ClaudeAdapter';
|
||||||
@@ -1,12 +1,64 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express from 'express';
|
||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
|
import { createRoutes } from './routes';
|
||||||
|
import { AuthController, ChatController, EventController } from './controllers';
|
||||||
|
import { AuthService, ChatService, EventService } from './services';
|
||||||
|
import { MongoUserRepository, MongoEventRepository, MongoChatRepository } from './repositories';
|
||||||
|
import { ClaudeAdapter } from './ai';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = process.env.PORT || 3000;
|
||||||
|
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/caldav';
|
||||||
|
|
||||||
app.get('/', (req: Request, res: Response) => {
|
// Middleware
|
||||||
res.send('Hello World!');
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Initialize repositories
|
||||||
|
const userRepo = new MongoUserRepository();
|
||||||
|
const eventRepo = new MongoEventRepository();
|
||||||
|
const chatRepo = new MongoChatRepository();
|
||||||
|
|
||||||
|
// Initialize AI provider
|
||||||
|
const aiProvider = new ClaudeAdapter();
|
||||||
|
|
||||||
|
// Initialize services
|
||||||
|
const authService = new AuthService(userRepo);
|
||||||
|
const chatService = new ChatService(chatRepo, eventRepo, aiProvider);
|
||||||
|
const eventService = new EventService(eventRepo);
|
||||||
|
|
||||||
|
// Initialize controllers
|
||||||
|
const authController = new AuthController(authService);
|
||||||
|
const chatController = new ChatController(chatService);
|
||||||
|
const eventController = new EventController(eventService);
|
||||||
|
|
||||||
|
// Setup routes
|
||||||
|
app.use('/api', createRoutes({
|
||||||
|
authController,
|
||||||
|
chatController,
|
||||||
|
eventController,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Health check
|
||||||
|
app.get('/health', (_, res) => {
|
||||||
|
res.json({ status: 'ok' });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
// Start server
|
||||||
console.log(`Example app listening on port ${port}`);
|
async function start() {
|
||||||
});
|
try {
|
||||||
|
await mongoose.connect(mongoUri);
|
||||||
|
console.log('Connected to MongoDB');
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server running on port ${port}`);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to start server:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start();
|
||||||
|
|
||||||
|
export default app;
|
||||||
|
|||||||
22
apps/server/src/controllers/AuthController.ts
Normal file
22
apps/server/src/controllers/AuthController.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { Request, Response } from 'express';
|
||||||
|
import { AuthService } from '../services';
|
||||||
|
|
||||||
|
export class AuthController {
|
||||||
|
constructor(private authService: AuthService) {}
|
||||||
|
|
||||||
|
async login(req: Request, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async register(req: Request, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async refresh(req: Request, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout(req: Request, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
27
apps/server/src/controllers/ChatController.ts
Normal file
27
apps/server/src/controllers/ChatController.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Response } from 'express';
|
||||||
|
import { ChatService } from '../services';
|
||||||
|
import { AuthenticatedRequest } from '../middleware';
|
||||||
|
|
||||||
|
export class ChatController {
|
||||||
|
constructor(private chatService: ChatService) {}
|
||||||
|
|
||||||
|
async sendMessage(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async confirmEvent(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async rejectEvent(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getConversations(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getConversation(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
apps/server/src/controllers/EventController.ts
Normal file
31
apps/server/src/controllers/EventController.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Response } from 'express';
|
||||||
|
import { EventService } from '../services';
|
||||||
|
import { AuthenticatedRequest } from '../middleware';
|
||||||
|
|
||||||
|
export class EventController {
|
||||||
|
constructor(private eventService: EventService) {}
|
||||||
|
|
||||||
|
async create(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getById(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAll(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getByDateRange(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
3
apps/server/src/controllers/index.ts
Normal file
3
apps/server/src/controllers/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './AuthController';
|
||||||
|
export * from './ChatController';
|
||||||
|
export * from './EventController';
|
||||||
10
apps/server/src/middleware/AuthMiddleware.ts
Normal file
10
apps/server/src/middleware/AuthMiddleware.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
import { verifyToken, TokenPayload } from '../utils/jwt';
|
||||||
|
|
||||||
|
export interface AuthenticatedRequest extends Request {
|
||||||
|
user?: TokenPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function authenticate(req: AuthenticatedRequest, res: Response, next: NextFunction): void {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
1
apps/server/src/middleware/index.ts
Normal file
1
apps/server/src/middleware/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './AuthMiddleware';
|
||||||
1
apps/server/src/repositories/index.ts
Normal file
1
apps/server/src/repositories/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './mongo';
|
||||||
23
apps/server/src/repositories/mongo/MongoChatRepository.ts
Normal file
23
apps/server/src/repositories/mongo/MongoChatRepository.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { ChatMessage, Conversation, CreateMessageDTO, GetMessagesOptions } from '@caldav/shared';
|
||||||
|
import { ChatRepository } from '../../services/interfaces';
|
||||||
|
import { ChatMessageModel, ConversationModel } from './models';
|
||||||
|
|
||||||
|
export class MongoChatRepository implements ChatRepository {
|
||||||
|
// Conversations
|
||||||
|
async getConversationsByUser(userId: string): Promise<Conversation[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async createConversation(userId: string): Promise<Conversation> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messages (cursor-based pagination)
|
||||||
|
async getMessages(conversationId: string, options?: GetMessagesOptions): Promise<ChatMessage[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async createMessage(conversationId: string, message: CreateMessageDTO): Promise<ChatMessage> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
29
apps/server/src/repositories/mongo/MongoEventRepository.ts
Normal file
29
apps/server/src/repositories/mongo/MongoEventRepository.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from '@caldav/shared';
|
||||||
|
import { EventRepository } from '../../services/interfaces';
|
||||||
|
import { EventModel } from './models';
|
||||||
|
|
||||||
|
export class MongoEventRepository implements EventRepository {
|
||||||
|
async findById(id: string): Promise<CalendarEvent | null> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByUserId(userId: string): Promise<CalendarEvent[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByDateRange(userId: string, startDate: Date, endDate: Date): Promise<CalendarEvent[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(userId: string, data: CreateEventDTO): Promise<CalendarEvent> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, data: UpdateEventDTO): Promise<CalendarEvent | null> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string): Promise<boolean> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
17
apps/server/src/repositories/mongo/MongoUserRepository.ts
Normal file
17
apps/server/src/repositories/mongo/MongoUserRepository.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { User } from '@caldav/shared';
|
||||||
|
import { UserRepository, CreateUserData } from '../../services/interfaces';
|
||||||
|
import { UserModel } from './models';
|
||||||
|
|
||||||
|
export class MongoUserRepository implements UserRepository {
|
||||||
|
async findById(id: string): Promise<User | null> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByEmail(email: string): Promise<User | null> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(data: CreateUserData): Promise<User> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
3
apps/server/src/repositories/mongo/index.ts
Normal file
3
apps/server/src/repositories/mongo/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './MongoUserRepository';
|
||||||
|
export * from './MongoEventRepository';
|
||||||
|
export * from './MongoChatRepository';
|
||||||
74
apps/server/src/repositories/mongo/models/ChatModel.ts
Normal file
74
apps/server/src/repositories/mongo/models/ChatModel.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import mongoose, { Schema, Document } from 'mongoose';
|
||||||
|
import { ChatMessage, Conversation, CreateEventDTO } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface ChatMessageDocument extends Omit<ChatMessage, 'id'>, Document {}
|
||||||
|
export interface ConversationDocument extends Omit<Conversation, 'id'>, Document {}
|
||||||
|
|
||||||
|
const ProposedEventSchema = new Schema<CreateEventDTO>(
|
||||||
|
{
|
||||||
|
title: { type: String, required: true },
|
||||||
|
description: { type: String },
|
||||||
|
startTime: { type: Date, required: true },
|
||||||
|
endTime: { type: Date, required: true },
|
||||||
|
note: { type: String },
|
||||||
|
isRecurring: { type: Boolean },
|
||||||
|
recurrenceRule: { type: String },
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const ChatMessageSchema = new Schema<ChatMessageDocument>(
|
||||||
|
{
|
||||||
|
conversationId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
type: String,
|
||||||
|
enum: ['user', 'assistant'],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
proposedEvent: {
|
||||||
|
type: ProposedEventSchema,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
toJSON: {
|
||||||
|
transform: (_, ret: Record<string, unknown>) => {
|
||||||
|
ret.id = String(ret._id);
|
||||||
|
delete ret._id;
|
||||||
|
delete ret.__v;
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const ConversationSchema = new Schema<ConversationDocument>(
|
||||||
|
{
|
||||||
|
userId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
toJSON: {
|
||||||
|
transform: (_, ret: Record<string, unknown>) => {
|
||||||
|
ret.id = String(ret._id);
|
||||||
|
delete ret._id;
|
||||||
|
delete ret.__v;
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ChatMessageModel = mongoose.model<ChatMessageDocument>('ChatMessage', ChatMessageSchema);
|
||||||
|
export const ConversationModel = mongoose.model<ConversationDocument>('Conversation', ConversationSchema);
|
||||||
56
apps/server/src/repositories/mongo/models/EventModel.ts
Normal file
56
apps/server/src/repositories/mongo/models/EventModel.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import mongoose, { Schema, Document } from 'mongoose';
|
||||||
|
import { CalendarEvent } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface EventDocument extends Omit<CalendarEvent, 'id'>, Document {}
|
||||||
|
|
||||||
|
const EventSchema = new Schema<EventDocument>(
|
||||||
|
{
|
||||||
|
userId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
startTime: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
endTime: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
isRecurring: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
recurrenceRule: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
toJSON: {
|
||||||
|
transform: (_, ret: Record<string, unknown>) => {
|
||||||
|
ret.id = String(ret._id);
|
||||||
|
delete ret._id;
|
||||||
|
delete ret.__v;
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
EventSchema.index({ userId: 1, startTime: 1, endTime: 1 });
|
||||||
|
|
||||||
|
export const EventModel = mongoose.model<EventDocument>('Event', EventSchema);
|
||||||
39
apps/server/src/repositories/mongo/models/UserModel.ts
Normal file
39
apps/server/src/repositories/mongo/models/UserModel.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import mongoose, { Schema, Document } from 'mongoose';
|
||||||
|
import { User } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface UserDocument extends Omit<User, 'id'>, Document {}
|
||||||
|
|
||||||
|
const UserSchema = new Schema<UserDocument>(
|
||||||
|
{
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
lowercase: true,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
passwordHash: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
toJSON: {
|
||||||
|
transform: (_, ret: Record<string, unknown>) => {
|
||||||
|
ret.id = String(ret._id);
|
||||||
|
delete ret._id;
|
||||||
|
delete ret.__v;
|
||||||
|
delete ret.passwordHash;
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const UserModel = mongoose.model<UserDocument>('User', UserSchema);
|
||||||
3
apps/server/src/repositories/mongo/models/index.ts
Normal file
3
apps/server/src/repositories/mongo/models/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './UserModel';
|
||||||
|
export * from './EventModel';
|
||||||
|
export * from './ChatModel';
|
||||||
13
apps/server/src/routes/auth.routes.ts
Normal file
13
apps/server/src/routes/auth.routes.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { AuthController } from '../controllers';
|
||||||
|
|
||||||
|
export function createAuthRoutes(authController: AuthController): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.post('/login', (req, res) => authController.login(req, res));
|
||||||
|
router.post('/register', (req, res) => authController.register(req, res));
|
||||||
|
router.post('/refresh', (req, res) => authController.refresh(req, res));
|
||||||
|
router.post('/logout', (req, res) => authController.logout(req, res));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
17
apps/server/src/routes/chat.routes.ts
Normal file
17
apps/server/src/routes/chat.routes.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { ChatController } from '../controllers';
|
||||||
|
import { authenticate } from '../middleware';
|
||||||
|
|
||||||
|
export function createChatRoutes(chatController: ChatController): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.use(authenticate);
|
||||||
|
|
||||||
|
router.post('/message', (req, res) => chatController.sendMessage(req, res));
|
||||||
|
router.post('/confirm/:conversationId/:messageId', (req, res) => chatController.confirmEvent(req, res));
|
||||||
|
router.post('/reject/:conversationId/:messageId', (req, res) => chatController.rejectEvent(req, res));
|
||||||
|
router.get('/conversations', (req, res) => chatController.getConversations(req, res));
|
||||||
|
router.get('/conversations/:id', (req, res) => chatController.getConversation(req, res));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
18
apps/server/src/routes/event.routes.ts
Normal file
18
apps/server/src/routes/event.routes.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { EventController } from '../controllers';
|
||||||
|
import { authenticate } from '../middleware';
|
||||||
|
|
||||||
|
export function createEventRoutes(eventController: EventController): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.use(authenticate);
|
||||||
|
|
||||||
|
router.post('/', (req, res) => eventController.create(req, res));
|
||||||
|
router.get('/', (req, res) => eventController.getAll(req, res));
|
||||||
|
router.get('/range', (req, res) => eventController.getByDateRange(req, res));
|
||||||
|
router.get('/:id', (req, res) => eventController.getById(req, res));
|
||||||
|
router.put('/:id', (req, res) => eventController.update(req, res));
|
||||||
|
router.delete('/:id', (req, res) => eventController.delete(req, res));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
25
apps/server/src/routes/index.ts
Normal file
25
apps/server/src/routes/index.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { createAuthRoutes } from './auth.routes';
|
||||||
|
import { createChatRoutes } from './chat.routes';
|
||||||
|
import { createEventRoutes } from './event.routes';
|
||||||
|
import { AuthController, ChatController, EventController } from '../controllers';
|
||||||
|
|
||||||
|
export interface Controllers {
|
||||||
|
authController: AuthController;
|
||||||
|
chatController: ChatController;
|
||||||
|
eventController: EventController;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRoutes(controllers: Controllers): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.use('/auth', createAuthRoutes(controllers.authController));
|
||||||
|
router.use('/chat', createChatRoutes(controllers.chatController));
|
||||||
|
router.use('/events', createEventRoutes(controllers.eventController));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
export * from './auth.routes';
|
||||||
|
export * from './chat.routes';
|
||||||
|
export * from './event.routes';
|
||||||
24
apps/server/src/services/AuthService.ts
Normal file
24
apps/server/src/services/AuthService.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { User, CreateUserDTO, LoginDTO, AuthResponse } from '@caldav/shared';
|
||||||
|
import { UserRepository } from './interfaces';
|
||||||
|
import * as jwt from '../utils/jwt';
|
||||||
|
import * as password from '../utils/password';
|
||||||
|
|
||||||
|
export class AuthService {
|
||||||
|
constructor(private userRepo: UserRepository) {}
|
||||||
|
|
||||||
|
async login(data: LoginDTO): Promise<AuthResponse> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async register(data: CreateUserDTO): Promise<AuthResponse> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async refreshToken(refreshToken: string): Promise<AuthResponse> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout(userId: string): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
30
apps/server/src/services/ChatService.ts
Normal file
30
apps/server/src/services/ChatService.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { ChatMessage, ChatResponse, SendMessageDTO, CalendarEvent, ConversationSummary, GetMessagesOptions } from '@caldav/shared';
|
||||||
|
import { ChatRepository, EventRepository, AIProvider } from './interfaces';
|
||||||
|
|
||||||
|
export class ChatService {
|
||||||
|
constructor(
|
||||||
|
private chatRepo: ChatRepository,
|
||||||
|
private eventRepo: EventRepository,
|
||||||
|
private aiProvider: AIProvider
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async processMessage(userId: string, data: SendMessageDTO): Promise<ChatResponse> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async confirmEvent(userId: string, conversationId: string, messageId: string): Promise<CalendarEvent> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async rejectEvent(conversationId: string, messageId: string): Promise<void> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getConversations(userId: string): Promise<ConversationSummary[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getConversation(userId: string, conversationId: string, options?: GetMessagesOptions): Promise<ChatMessage[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
30
apps/server/src/services/EventService.ts
Normal file
30
apps/server/src/services/EventService.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from '@caldav/shared';
|
||||||
|
import { EventRepository } from './interfaces';
|
||||||
|
|
||||||
|
export class EventService {
|
||||||
|
constructor(private eventRepo: EventRepository) {}
|
||||||
|
|
||||||
|
async create(userId: string, data: CreateEventDTO): Promise<CalendarEvent> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getById(id: string, userId: string): Promise<CalendarEvent | null> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAll(userId: string): Promise<CalendarEvent[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getByDateRange(userId: string, startDate: Date, endDate: Date): Promise<CalendarEvent[]> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, userId: string, data: UpdateEventDTO): Promise<CalendarEvent | null> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string, userId: string): Promise<boolean> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
||||||
4
apps/server/src/services/index.ts
Normal file
4
apps/server/src/services/index.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export * from './AuthService';
|
||||||
|
export * from './ChatService';
|
||||||
|
export * from './EventService';
|
||||||
|
export * from './interfaces';
|
||||||
16
apps/server/src/services/interfaces/AIProvider.ts
Normal file
16
apps/server/src/services/interfaces/AIProvider.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { CalendarEvent, ChatMessage, CreateEventDTO } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface AIContext {
|
||||||
|
userId: string;
|
||||||
|
conversationHistory: ChatMessage[];
|
||||||
|
existingEvents: CalendarEvent[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AIResponse {
|
||||||
|
content: string;
|
||||||
|
proposedEvent?: CreateEventDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AIProvider {
|
||||||
|
processMessage(message: string, context: AIContext): Promise<AIResponse>;
|
||||||
|
}
|
||||||
11
apps/server/src/services/interfaces/ChatRepository.ts
Normal file
11
apps/server/src/services/interfaces/ChatRepository.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { ChatMessage, Conversation, CreateMessageDTO, GetMessagesOptions } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface ChatRepository {
|
||||||
|
// Conversations
|
||||||
|
getConversationsByUser(userId: string): Promise<Conversation[]>;
|
||||||
|
createConversation(userId: string): Promise<Conversation>;
|
||||||
|
|
||||||
|
// Messages (cursor-based pagination)
|
||||||
|
getMessages(conversationId: string, options?: GetMessagesOptions): Promise<ChatMessage[]>;
|
||||||
|
createMessage(conversationId: string, message: CreateMessageDTO): Promise<ChatMessage>;
|
||||||
|
}
|
||||||
10
apps/server/src/services/interfaces/EventRepository.ts
Normal file
10
apps/server/src/services/interfaces/EventRepository.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface EventRepository {
|
||||||
|
findById(id: string): Promise<CalendarEvent | null>;
|
||||||
|
findByUserId(userId: string): Promise<CalendarEvent[]>;
|
||||||
|
findByDateRange(userId: string, startDate: Date, endDate: Date): Promise<CalendarEvent[]>;
|
||||||
|
create(userId: string, data: CreateEventDTO): Promise<CalendarEvent>;
|
||||||
|
update(id: string, data: UpdateEventDTO): Promise<CalendarEvent | null>;
|
||||||
|
delete(id: string): Promise<boolean>;
|
||||||
|
}
|
||||||
13
apps/server/src/services/interfaces/UserRepository.ts
Normal file
13
apps/server/src/services/interfaces/UserRepository.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { User } from '@caldav/shared';
|
||||||
|
|
||||||
|
export interface CreateUserData {
|
||||||
|
email: string;
|
||||||
|
displayName: string;
|
||||||
|
passwordHash: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserRepository {
|
||||||
|
findById(id: string): Promise<User | null>;
|
||||||
|
findByEmail(email: string): Promise<User | null>;
|
||||||
|
create(data: CreateUserData): Promise<User>;
|
||||||
|
}
|
||||||
4
apps/server/src/services/interfaces/index.ts
Normal file
4
apps/server/src/services/interfaces/index.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export * from './AIProvider';
|
||||||
|
export * from './UserRepository';
|
||||||
|
export * from './EventRepository';
|
||||||
|
export * from './ChatRepository';
|
||||||
2
apps/server/src/utils/index.ts
Normal file
2
apps/server/src/utils/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './jwt';
|
||||||
|
export * from './password';
|
||||||
26
apps/server/src/utils/jwt.ts
Normal file
26
apps/server/src/utils/jwt.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
export interface TokenPayload {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JWTConfig {
|
||||||
|
secret: string;
|
||||||
|
expiresIn: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
|
||||||
|
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '1h';
|
||||||
|
|
||||||
|
export function signToken(payload: TokenPayload): string {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyToken(token: string): TokenPayload {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeToken(token: string): TokenPayload | null {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
11
apps/server/src/utils/password.ts
Normal file
11
apps/server/src/utils/password.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import bcrypt from 'bcrypt';
|
||||||
|
|
||||||
|
const SALT_ROUNDS = 10;
|
||||||
|
|
||||||
|
export async function hash(password: string): Promise<string> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function compare(password: string, hash: string): Promise<boolean> {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
BIN
docs/Backend Klassendiagramm.png
Normal file
BIN
docs/Backend Klassendiagramm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/Frontend Klassendiagramm.png
Normal file
BIN
docs/Frontend Klassendiagramm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/System Komponenten.png
Normal file
BIN
docs/System Komponenten.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
@@ -38,7 +38,7 @@ package "Controller Layer" #ADD8E6 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
package "Service Layer" #90EE90 {
|
package "Service Layer" #90EE90 {
|
||||||
package "Interfaces" {
|
package "Data Access Interfaces" {
|
||||||
interface AIProvider {
|
interface AIProvider {
|
||||||
' +processMessage()
|
' +processMessage()
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ package "AI Layer" #FFA07A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
package "Data Access Layer" #FFD700 {
|
package "Data Access Implementations" #FFD700 {
|
||||||
class MongoUserRepository implements UserRepository {
|
class MongoUserRepository implements UserRepository {
|
||||||
' -model: UserModel
|
' -model: UserModel
|
||||||
}
|
}
|
||||||
|
|||||||
419
package-lock.json
generated
419
package-lock.json
generated
@@ -60,13 +60,20 @@
|
|||||||
"name": "@caldav/server",
|
"name": "@caldav/server",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@anthropic-ai/sdk": "^0.71.2",
|
||||||
"@caldav/shared": "*",
|
"@caldav/shared": "*",
|
||||||
"express": "^5.2.1"
|
"bcrypt": "^6.0.0",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"jsonwebtoken": "^9.0.3",
|
||||||
|
"mongoose": "^9.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"tsx": "^4.21.0"
|
"tsx": "^4.21.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@0no-co/graphql.web": {
|
"node_modules/@0no-co/graphql.web": {
|
||||||
@@ -95,6 +102,26 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@anthropic-ai/sdk": {
|
||||||
|
"version": "0.71.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz",
|
||||||
|
"integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"json-schema-to-ts": "^3.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"anthropic-ai-sdk": "bin/cli"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"zod": "^3.25.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"zod": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.27.1",
|
"version": "7.27.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
||||||
@@ -3239,6 +3266,15 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mongodb-js/saslprep": {
|
||||||
|
"version": "1.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.4.tgz",
|
||||||
|
"integrity": "sha512-p7X/ytJDIdwUfFL/CLOhKgdfJe1Fa8uw9seJYvdOmnP9JBWGWHW69HkOixXS6Wy9yvGf1MbhcS6lVmrhy4jm2g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sparse-bitfield": "^3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "0.2.12",
|
"version": "0.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||||
@@ -3935,6 +3971,16 @@
|
|||||||
"@babel/types": "^7.28.2"
|
"@babel/types": "^7.28.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/bcrypt": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/body-parser": {
|
"node_modules/@types/body-parser": {
|
||||||
"version": "1.19.6",
|
"version": "1.19.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
||||||
@@ -4048,6 +4094,24 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jsonwebtoken": {
|
||||||
|
"version": "9.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
|
||||||
|
"integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/ms": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/ms": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.10.1",
|
"version": "24.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
||||||
@@ -4108,6 +4172,21 @@
|
|||||||
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
|
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/webidl-conversions": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/whatwg-url": {
|
||||||
|
"version": "13.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz",
|
||||||
|
"integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/webidl-conversions": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/yargs": {
|
"node_modules/@types/yargs": {
|
||||||
"version": "17.0.35",
|
"version": "17.0.35",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz",
|
||||||
@@ -5342,6 +5421,20 @@
|
|||||||
"baseline-browser-mapping": "dist/cli.js"
|
"baseline-browser-mapping": "dist/cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bcrypt": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-addon-api": "^8.3.0",
|
||||||
|
"node-gyp-build": "^4.8.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/better-opn": {
|
"node_modules/better-opn": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz",
|
||||||
@@ -5513,6 +5606,15 @@
|
|||||||
"node-int64": "^0.4.0"
|
"node-int64": "^0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bson": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bson/-/bson-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-Kwc6Wh4lQ5OmkqqKhYGKIuELXl+EPYSCObVE6bWsp1T/cGkOCBN0I8wF/T44BiuhHyNi1mmKVPXk60d41xZ7kw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/buffer": {
|
"node_modules/buffer": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
@@ -5537,6 +5639,12 @@
|
|||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.1.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-equal-constant-time": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
@@ -6365,6 +6473,15 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@@ -9449,6 +9566,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/json-schema-to-ts": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.18.3",
|
||||||
|
"ts-algebra": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/json-schema-traverse": {
|
"node_modules/json-schema-traverse": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
@@ -9475,6 +9605,40 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonwebtoken": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jws": "^4.0.1",
|
||||||
|
"lodash.includes": "^4.3.0",
|
||||||
|
"lodash.isboolean": "^3.0.3",
|
||||||
|
"lodash.isinteger": "^4.0.4",
|
||||||
|
"lodash.isnumber": "^3.0.3",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.isstring": "^4.0.1",
|
||||||
|
"lodash.once": "^4.0.0",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12",
|
||||||
|
"npm": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jsonwebtoken/node_modules/semver": {
|
||||||
|
"version": "7.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||||
|
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsx-ast-utils": {
|
"node_modules/jsx-ast-utils": {
|
||||||
"version": "3.3.5",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||||
@@ -9491,6 +9655,36 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jwa": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-equal-constant-time": "^1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jws": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jwa": "^2.0.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/kareem": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-RKhaOBSPN8L7y4yAgNhDT2602G5FD6QbOIISbjN9D6mjHPeqeg7K+EB5IGSU5o81/X2Gzm3ICnAvQW3x3OP8HA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@@ -9855,6 +10049,42 @@
|
|||||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
|
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.includes": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isboolean": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isinteger": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isnumber": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isstring": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@@ -9862,6 +10092,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.once": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.throttle": {
|
"node_modules/lodash.throttle": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||||
@@ -10011,6 +10247,12 @@
|
|||||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/memory-pager": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/merge-descriptors": {
|
"node_modules/merge-descriptors": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
||||||
@@ -10494,6 +10736,138 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mongodb": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@mongodb-js/saslprep": "^1.3.0",
|
||||||
|
"bson": "^7.0.0",
|
||||||
|
"mongodb-connection-string-url": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@aws-sdk/credential-providers": "^3.806.0",
|
||||||
|
"@mongodb-js/zstd": "^7.0.0",
|
||||||
|
"gcp-metadata": "^7.0.1",
|
||||||
|
"kerberos": "^7.0.0",
|
||||||
|
"mongodb-client-encryption": ">=7.0.0 <7.1.0",
|
||||||
|
"snappy": "^7.3.2",
|
||||||
|
"socks": "^2.8.6"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@aws-sdk/credential-providers": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@mongodb-js/zstd": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"gcp-metadata": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"kerberos": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mongodb-client-encryption": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"snappy": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"socks": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongodb-connection-string-url": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-irhhjRVLE20hbkRl4zpAYLnDMM+zIZnp0IDB9akAFFUZp/3XdOfwwddc7y6cNvF2WCEtfTYRwYbIfYa2kVY0og==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/whatwg-url": "^13.0.0",
|
||||||
|
"whatwg-url": "^14.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongodb-connection-string-url/node_modules/tr46": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongodb-connection-string-url/node_modules/whatwg-url": {
|
||||||
|
"version": "14.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
|
||||||
|
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "^5.1.0",
|
||||||
|
"webidl-conversions": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mongoose": {
|
||||||
|
"version": "9.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.1.1.tgz",
|
||||||
|
"integrity": "sha512-/CgKSAmjzgIj4o1FyWZIpQ2rmUQlhalwWd4l/Ht3XUVWscHRHev1TIwKz1ADNC5tHHyOQEaUDkEh0jI91c4Ydw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"kareem": "3.0.0",
|
||||||
|
"mongodb": "~7.0",
|
||||||
|
"mpath": "0.9.0",
|
||||||
|
"mquery": "6.0.0",
|
||||||
|
"ms": "2.1.3",
|
||||||
|
"sift": "17.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mongoose"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mpath": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mquery": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
@@ -10584,6 +10958,15 @@
|
|||||||
"integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==",
|
"integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || ^20 || >= 21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-fetch": {
|
"node_modules/node-fetch": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
@@ -10613,6 +10996,17 @@
|
|||||||
"node": ">= 6.13.0"
|
"node": ">= 6.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp-build": {
|
||||||
|
"version": "4.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||||
|
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "bin.js",
|
||||||
|
"node-gyp-build-optional": "optional.js",
|
||||||
|
"node-gyp-build-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-int64": {
|
"node_modules/node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
@@ -13224,6 +13618,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sift": {
|
||||||
|
"version": "17.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
|
||||||
|
"integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/signal-exit": {
|
"node_modules/signal-exit": {
|
||||||
"version": "3.0.7",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
@@ -13323,6 +13723,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sparse-bitfield": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"memory-pager": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/split-on-first": {
|
"node_modules/split-on-first": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||||
@@ -13907,6 +14316,12 @@
|
|||||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-algebra": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ts-api-utils": {
|
"node_modules/ts-api-utils": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
"name": "@caldav/shared",
|
"name": "@caldav/shared",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"main": "./src/index.ts",
|
||||||
|
"types": "./src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
".": "./src/index.ts",
|
||||||
"./*": "./src/*"
|
"./*": "./src/*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/shared/src/index.ts
Normal file
1
packages/shared/src/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './models';
|
||||||
33
packages/shared/src/models/CalendarEvent.ts
Normal file
33
packages/shared/src/models/CalendarEvent.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
export interface CalendarEvent {
|
||||||
|
id: string;
|
||||||
|
userId: string;
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
startTime: Date;
|
||||||
|
endTime: Date;
|
||||||
|
note?: string;
|
||||||
|
isRecurring?: boolean;
|
||||||
|
recurrenceRule?: string;
|
||||||
|
createdAt?: Date;
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateEventDTO {
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
startTime: Date;
|
||||||
|
endTime: Date;
|
||||||
|
note?: string;
|
||||||
|
isRecurring?: boolean;
|
||||||
|
recurrenceRule?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateEventDTO {
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
startTime?: Date;
|
||||||
|
endTime?: Date;
|
||||||
|
note?: string;
|
||||||
|
isRecurring?: boolean;
|
||||||
|
recurrenceRule?: string;
|
||||||
|
}
|
||||||
46
packages/shared/src/models/ChatMessage.ts
Normal file
46
packages/shared/src/models/ChatMessage.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { CreateEventDTO } from './CalendarEvent';
|
||||||
|
|
||||||
|
export type MessageSender = 'user' | 'assistant';
|
||||||
|
|
||||||
|
export interface ChatMessage {
|
||||||
|
id: string;
|
||||||
|
conversationId: string;
|
||||||
|
sender: MessageSender;
|
||||||
|
content: string;
|
||||||
|
proposedEvent?: CreateEventDTO;
|
||||||
|
createdAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Conversation {
|
||||||
|
id: string;
|
||||||
|
userId: string;
|
||||||
|
createdAt?: Date;
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SendMessageDTO {
|
||||||
|
conversationId?: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMessageDTO {
|
||||||
|
sender: MessageSender;
|
||||||
|
content: string;
|
||||||
|
proposedEvent?: CreateEventDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetMessagesOptions {
|
||||||
|
before?: string; // Message ID - load messages before this one
|
||||||
|
limit?: number; // Default: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChatResponse {
|
||||||
|
message: ChatMessage;
|
||||||
|
conversationId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConversationSummary {
|
||||||
|
id: string;
|
||||||
|
lastMessage?: ChatMessage;
|
||||||
|
createdAt?: Date;
|
||||||
|
}
|
||||||
25
packages/shared/src/models/User.ts
Normal file
25
packages/shared/src/models/User.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export interface User {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
displayName: string;
|
||||||
|
passwordHash?: string;
|
||||||
|
createdAt?: Date;
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateUserDTO {
|
||||||
|
email: string;
|
||||||
|
displayName: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginDTO {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthResponse {
|
||||||
|
user: Omit<User, 'passwordHash'>;
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken?: string;
|
||||||
|
}
|
||||||
3
packages/shared/src/models/index.ts
Normal file
3
packages/shared/src/models/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './User';
|
||||||
|
export * from './CalendarEvent';
|
||||||
|
export * from './ChatMessage';
|
||||||
Reference in New Issue
Block a user