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:
@@ -8,12 +8,19 @@
|
||||
"start": "node dist/app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.71.2",
|
||||
"@caldav/shared": "*",
|
||||
"express": "^5.2.1"
|
||||
"bcrypt": "^6.0.0",
|
||||
"express": "^5.2.1",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"mongoose": "^9.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@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 port = 3000;
|
||||
const port = process.env.PORT || 3000;
|
||||
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/caldav';
|
||||
|
||||
app.get('/', (req: Request, res: Response) => {
|
||||
res.send('Hello World!');
|
||||
// Middleware
|
||||
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, () => {
|
||||
console.log(`Example app listening on port ${port}`);
|
||||
});
|
||||
// Start server
|
||||
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');
|
||||
}
|
||||
Reference in New Issue
Block a user