# 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 │ ├── EventCardBase.tsx # Shared event card layout with icons (used by EventCard & ProposedEventCard) │ ├── EventCard.tsx # Calendar event card (uses EventCardBase + edit/delete buttons) │ ├── EventConfirmDialog.tsx # AI-proposed event confirmation modal │ └── ProposedEventCard.tsx # Chat event proposal (uses EventCardBase + 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() ├── ChatStore.ts # messages[], addMessage(), updateMessage(), clearMessages() └── 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, ExpandedEvent │ ├── 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? - `ExpandedEvent`: Extends CalendarEvent with occurrenceStart, occurrenceEnd (for recurring event instances) - `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, {}, {}, 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) - `EventController`: Full CRUD (create, getById, getAll, getByDateRange, update, delete) - `EventService`: Full CRUD with recurring event expansion via recurrenceExpander - `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:** - `ClaudeAdapter` (AI integration - currently using test responses) **Shared:** Types, DTOs, constants (Day, Month with German translations), ExpandedEvent type, and date utilities defined and exported. **Frontend:** - Tab navigation (Chat, Calendar) implemented with basic UI - Calendar screen fully functional: - Month navigation with grid display and Ionicons (chevron-back/forward) - MonthSelector dropdown with infinite scroll (dynamically loads months, lazy-loaded when modal opens, cleared on close for memory efficiency) - Events loaded from API via EventService.getByDateRange() - Orange dot indicator for days with events - Tap-to-open modal overlay showing EventCards for selected day - Supports events from adjacent months visible in grid - Uses `useFocusEffect` for automatic reload on tab focus - Chat screen functional with FlashList, message sending, and event confirm/reject - Messages persisted via ChatStore (survives tab switches) - KeyboardAvoidingView for proper keyboard handling (iOS padding, Android height) - Auto-scroll to end on new messages and keyboard show - keyboardDismissMode="interactive" and keyboardShouldPersistTaps="handled" - `ApiClient`: get(), post(), put(), delete() implemented - `EventService`: getAll(), getById(), getByDateRange(), create(), update(), delete() - fully implemented - `ChatService`: sendMessage(), confirmEvent(convId, msgId, action, event?, eventId?, updates?), rejectEvent() - supports create/update/delete actions - `EventCardBase`: Shared base component with event layout (header, date/time/recurring icons, description) - used by both EventCard and ProposedEventCard - `EventCard`: Uses EventCardBase + edit/delete buttons for calendar display - `ProposedEventCard`: Uses EventCardBase + confirm/reject buttons for chat proposals (supports create/update/delete actions) - `Themes.tsx`: Centralized color definitions including textPrimary, borderPrimary, eventIndicator, secondaryBg - `EventsStore`: Zustand store with setEvents(), addEvent(), updateEvent(), deleteEvent() - stores ExpandedEvent[] - `ChatStore`: Zustand store with addMessage(), updateMessage(), clearMessages() - persists messages across tab switches - Auth screens (Login, Register), Event Detail, and Note screens exist as skeletons - AuthStore defined with `throw new Error('Not implemented')` ## 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