- Implement full CRUD in MongoEventRepository (findById, findByUserId, findByDateRange, update, delete) - Extend ChatService to handle create/update/delete actions with dynamic test responses - Add recurrenceExpander utility using rrule library for RRULE parsing - Add eventFormatters utility for German-localized week/month overviews - Add German translations for days and months in shared Constants - Update client ChatService to support all event actions (action, eventId, updates params)
311 lines
13 KiB
Markdown
311 lines
13 KiB
Markdown
# 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 managing calendar events through a chat interface with an AI chatbot. 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 |
|
|
| | Zustand | State management |
|
|
| | FlashList | High-performance lists |
|
|
| 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)
|
|
|
|
```
|
|
src/
|
|
├── app/ # Expo-Router file-based routing
|
|
│ ├── _layout.tsx # Root Stack layout
|
|
│ ├── index.tsx # Entry redirect
|
|
│ ├── login.tsx # Login screen
|
|
│ ├── register.tsx # Registration screen
|
|
│ ├── (tabs)/ # Tab navigation group
|
|
│ │ ├── _layout.tsx # Tab bar configuration
|
|
│ │ ├── chat.tsx # Chat screen (AI conversation)
|
|
│ │ └── calendar.tsx # Calendar overview
|
|
│ ├── event/
|
|
│ │ └── [id].tsx # Event detail screen (dynamic route)
|
|
│ └── note/
|
|
│ └── [id].tsx # Note editor for event (dynamic route)
|
|
├── components/
|
|
│ ├── BaseBackground.tsx # Common screen wrapper
|
|
│ ├── Header.tsx # Header component
|
|
│ ├── EventCard.tsx # Event card for calendar display
|
|
│ ├── EventConfirmDialog.tsx # AI-proposed event confirmation modal
|
|
│ └── ProposedEventCard.tsx # Inline event proposal with confirm/reject buttons
|
|
├── Themes.tsx # Centralized color/theme definitions
|
|
├── services/
|
|
│ ├── index.ts # Re-exports all services
|
|
│ ├── ApiClient.ts # HTTP client (get, post, put, delete)
|
|
│ ├── AuthService.ts # login(), register(), logout(), refresh()
|
|
│ ├── EventService.ts # getAll(), getById(), getByDateRange(), create(), update(), delete()
|
|
│ └── ChatService.ts # sendMessage(), confirmEvent(), rejectEvent(), getConversations(), getConversation()
|
|
└── stores/ # Zustand state management
|
|
├── index.ts # Re-exports all stores
|
|
├── AuthStore.ts # user, token, isAuthenticated, login(), logout(), setToken()
|
|
└── EventsStore.ts # events[], setEvents(), addEvent(), updateEvent(), deleteEvent()
|
|
```
|
|
|
|
**Routing:** Tab-based navigation with Chat and Calendar as main screens. Auth screens (login, register) outside tabs. Dynamic routes for event detail and note editing.
|
|
|
|
### 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
|
|
│ │ ├── types.ts # Shared types (IdVirtual interface)
|
|
│ │ ├── 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()
|
|
├── eventFormatters.ts # getWeeksOverview(), getMonthOverview() - formatted event listings
|
|
└── recurrenceExpander.ts # expandRecurringEvents() - expand recurring events into occurrences
|
|
```
|
|
|
|
**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
|
|
- `POST /api/ai/test` - AI test endpoint (development only)
|
|
|
|
### 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,
|
|
│ │ # ProposedEventChange, EventAction
|
|
│ └── Constants.ts # DAYS, MONTHS, Day, Month, DAY_INDEX, DAY_INDEX_TO_DAY,
|
|
│ # DAY_TO_GERMAN, DAY_TO_GERMAN_SHORT, MONTH_TO_GERMAN
|
|
└── utils/
|
|
├── index.ts
|
|
└── dateHelpers.ts # getDay() - get date for specific weekday relative to today
|
|
```
|
|
|
|
**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, proposedChange?
|
|
- `ProposedEventChange`: action ('create' | 'update' | 'delete'), eventId?, event?, updates?
|
|
- `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)
|
|
- `Day`: "Monday" | "Tuesday" | ... | "Sunday"
|
|
- `Month`: "January" | "February" | ... | "December"
|
|
|
|
### 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
|
|
|
|
### Mongoose Model Pattern
|
|
|
|
All Mongoose models use a consistent pattern for TypeScript-safe `id` virtuals:
|
|
|
|
```typescript
|
|
import { IdVirtual } from './types';
|
|
|
|
const Schema = new Schema<Doc, Model<Doc, {}, {}, IdVirtual>, {}, {}, IdVirtual>(
|
|
{ /* fields */ },
|
|
{
|
|
virtuals: {
|
|
id: {
|
|
get() { return this._id.toString(); }
|
|
}
|
|
},
|
|
toJSON: {
|
|
virtuals: true,
|
|
transform: (_, ret) => {
|
|
delete ret._id;
|
|
delete ret.__v;
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
```
|
|
|
|
Repositories use `doc.toJSON() as unknown as Type` casting (required because Mongoose's TypeScript types don't reflect virtual fields in toJSON output).
|
|
|
|
## 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
|
|
|
|
## Development Environment
|
|
|
|
### MongoDB (Docker)
|
|
```bash
|
|
cd apps/server/docker/mongo
|
|
docker compose up -d # Start MongoDB + Mongo Express
|
|
docker compose down # Stop services
|
|
```
|
|
- MongoDB: `localhost:27017` (root/mongoose)
|
|
- Mongo Express UI: `localhost:8083` (admin/admin)
|
|
|
|
### Environment Variables
|
|
Server requires `.env` file in `apps/server/`:
|
|
```
|
|
JWT_SECRET=your-secret-key
|
|
JWT_EXPIRES_IN=1h
|
|
MONGODB_URI=mongodb://root:mongoose@localhost:27017/calchat?authSource=admin
|
|
```
|
|
|
|
## Current Implementation Status
|
|
|
|
**Backend:**
|
|
- **Implemented:**
|
|
- `AuthController`: login(), register() with error handling
|
|
- `AuthService`: login(), register() with password validation
|
|
- `MongoUserRepository`: findByEmail(), create()
|
|
- `utils/password`: hash(), compare() using bcrypt
|
|
- `utils/jwt`: signToken() (verifyToken() pending)
|
|
- `dotenv` integration for environment variables
|
|
- `ChatController`: sendMessage(), confirmEvent(), rejectEvent()
|
|
- `ChatService`: processMessage() with test responses (create, update, delete actions), confirmEvent() handles all CRUD actions
|
|
- `MongoEventRepository`: Full CRUD implemented (findById, findByUserId, findByDateRange, create, update, delete)
|
|
- `utils/eventFormatters`: getWeeksOverview(), getMonthOverview() with German localization
|
|
- `utils/recurrenceExpander`: expandRecurringEvents() using rrule library for RRULE parsing
|
|
- **Stubbed (TODO):**
|
|
- `AuthMiddleware.authenticate()`: Currently uses fake user for testing
|
|
- `AuthController`: refresh(), logout()
|
|
- `AuthService`: refreshToken()
|
|
- `ChatController`: getConversations(), getConversation()
|
|
- `MongoChatRepository`: Database persistence for chat
|
|
- **Not started:**
|
|
- `EventController`, `EventService`
|
|
- `ClaudeAdapter` (AI integration - currently using test responses)
|
|
|
|
**Shared:** Types, DTOs, constants (Day, Month with German translations), and date utilities defined and exported.
|
|
|
|
**Frontend:**
|
|
- Tab navigation (Chat, Calendar) implemented with basic UI
|
|
- Calendar screen has month navigation and grid display (partially functional)
|
|
- Chat screen functional with FlashList, message sending, and event confirm/reject
|
|
- `ApiClient`: get(), post() implemented
|
|
- `ChatService`: sendMessage(), confirmEvent(convId, msgId, action, event?, eventId?, updates?), rejectEvent() - supports create/update/delete actions
|
|
- `ProposedEventCard`: Displays proposed events (title, date, description, recurring indicator) with confirm/reject buttons
|
|
- `Themes.tsx`: Centralized color definitions including button colors
|
|
- Auth screens (Login, Register), Event Detail, and Note screens exist as skeletons
|
|
- Zustand stores (AuthStore, EventsStore) defined with `throw new Error('Not implemented')`
|
|
- Components (EventCard, EventConfirmDialog) exist as skeletons
|
|
|
|
## Documentation
|
|
|
|
Detailed architecture diagrams are in `docs/`:
|
|
- `api-routes.md` - API endpoint overview (German)
|
|
- `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
|