feat: implement user authentication with login and register
- Add login screen with email/username support - Add register screen with email validation - Implement AuthStore with expo-secure-store (native) / localStorage (web) - Add X-User-Id header authentication (simple auth without JWT) - Rename displayName to userName across codebase - Add findByUserName() to UserRepository - Check for existing email AND username on registration - Add AuthButton component with shadow effect - Add logout button to Header - Add hash-password.js utility script for manual password resets - Update CORS to allow X-User-Id header
This commit is contained in:
57
CLAUDE.md
57
CLAUDE.md
@@ -46,7 +46,7 @@ npm run start -w @caldav/server # Run compiled server (port 3000)
|
||||
| | MongoDB | Database |
|
||||
| | Mongoose | ODM |
|
||||
| | GPT (OpenAI) | AI/LLM for chat |
|
||||
| | JWT | Authentication |
|
||||
| | X-User-Id Header | Authentication (simple, no JWT yet) |
|
||||
| | pino / pino-http | Structured logging |
|
||||
| | react-native-logs | Client-side logging |
|
||||
| Planned | iCalendar | Event export/import |
|
||||
@@ -79,7 +79,8 @@ src/
|
||||
│ └── [id].tsx # Note editor for event (dynamic route)
|
||||
├── components/
|
||||
│ ├── BaseBackground.tsx # Common screen wrapper
|
||||
│ ├── Header.tsx # Header component
|
||||
│ ├── Header.tsx # Header component with logout button
|
||||
│ ├── AuthButton.tsx # Reusable button for auth screens (with shadow)
|
||||
│ ├── 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
|
||||
@@ -90,13 +91,14 @@ src/
|
||||
│ └── logger.ts # react-native-logs config (apiLogger, storeLogger)
|
||||
├── services/
|
||||
│ ├── index.ts # Re-exports all services
|
||||
│ ├── ApiClient.ts # HTTP client with request logging (get, post, put, delete)
|
||||
│ ├── AuthService.ts # login(), register(), logout(), refresh()
|
||||
│ ├── ApiClient.ts # HTTP client with X-User-Id header injection, request logging
|
||||
│ ├── AuthService.ts # login(), register(), logout() - calls API and updates AuthStore
|
||||
│ ├── 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()
|
||||
├── AuthStore.ts # user, isAuthenticated, isLoading, login(), logout(), loadStoredUser()
|
||||
│ # Uses expo-secure-store (native) / localStorage (web)
|
||||
├── ChatStore.ts # messages[], addMessage(), addMessages(), updateMessage(), clearMessages(), chatMessageToMessageData()
|
||||
└── EventsStore.ts # events[], setEvents(), addEvent(), updateEvent(), deleteEvent()
|
||||
```
|
||||
@@ -112,7 +114,7 @@ src/
|
||||
│ ├── AuthController.ts # login(), register(), refresh(), logout()
|
||||
│ ├── ChatController.ts # sendMessage(), confirmEvent(), rejectEvent(), getConversations(), getConversation()
|
||||
│ ├── EventController.ts # create(), getById(), getAll(), getByDateRange(), update(), delete()
|
||||
│ ├── AuthMiddleware.ts # authenticate() - JWT validation
|
||||
│ ├── AuthMiddleware.ts # authenticate() - X-User-Id header validation
|
||||
│ └── LoggingMiddleware.ts # httpLogger - pino-http request logging
|
||||
├── logging/
|
||||
│ ├── index.ts # Re-exports
|
||||
@@ -126,7 +128,7 @@ src/
|
||||
├── services/ # Business logic
|
||||
│ ├── interfaces/ # DB-agnostic interfaces (for dependency injection)
|
||||
│ │ ├── AIProvider.ts # processMessage()
|
||||
│ │ ├── UserRepository.ts # + CreateUserData (server-internal DTO)
|
||||
│ │ ├── UserRepository.ts # findById, findByEmail, findByUserName, create + CreateUserData
|
||||
│ │ ├── EventRepository.ts
|
||||
│ │ └── ChatRepository.ts
|
||||
│ ├── AuthService.ts
|
||||
@@ -140,7 +142,7 @@ src/
|
||||
│ │ ├── UserModel.ts
|
||||
│ │ ├── EventModel.ts
|
||||
│ │ └── ChatModel.ts
|
||||
│ ├── MongoUserRepository.ts
|
||||
│ ├── MongoUserRepository.ts # findById, findByEmail, findByUserName, create
|
||||
│ ├── MongoEventRepository.ts
|
||||
│ └── MongoChatRepository.ts
|
||||
├── ai/
|
||||
@@ -152,11 +154,13 @@ src/
|
||||
│ ├── systemPrompt.ts # buildSystemPrompt() - German calendar assistant prompt
|
||||
│ ├── toolDefinitions.ts # TOOL_DEFINITIONS - provider-agnostic tool specs
|
||||
│ └── toolExecutor.ts # executeToolCall() - handles getDay, proposeCreate/Update/Delete, searchEvents
|
||||
└── utils/
|
||||
├── jwt.ts # signToken(), verifyToken()
|
||||
├── password.ts # hash(), compare()
|
||||
├── eventFormatters.ts # getWeeksOverview(), getMonthOverview() - formatted event listings
|
||||
└── recurrenceExpander.ts # expandRecurringEvents() - expand recurring events into occurrences
|
||||
├── utils/
|
||||
│ ├── jwt.ts # signToken(), verifyToken() - NOT USED YET (no JWT)
|
||||
│ ├── password.ts # hash(), compare() using bcrypt
|
||||
│ ├── eventFormatters.ts # getWeeksOverview(), getMonthOverview() - formatted event listings
|
||||
│ └── recurrenceExpander.ts # expandRecurringEvents() - expand recurring events into occurrences
|
||||
└── scripts/
|
||||
└── hash-password.js # Utility to hash passwords for manual DB updates
|
||||
```
|
||||
|
||||
**API Endpoints:**
|
||||
@@ -198,12 +202,14 @@ src/
|
||||
```
|
||||
|
||||
**Key Types:**
|
||||
- `User`: id, email, displayName, passwordHash?, createdAt?, updatedAt?
|
||||
- `User`: id, email, userName, 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?, respondedAction?
|
||||
- `ProposedEventChange`: action ('create' | 'update' | 'delete'), eventId?, event?, updates?
|
||||
- `Conversation`: id, userId, createdAt?, updatedAt? (messages loaded separately via lazy loading)
|
||||
- `CreateUserDTO`: email, userName, password (for registration)
|
||||
- `LoginDTO`: identifier (email OR userName), password
|
||||
- `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)
|
||||
@@ -318,10 +324,11 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
**Backend:**
|
||||
- **Implemented:**
|
||||
- `AuthController`: login(), register() with error handling
|
||||
- `AuthService`: login(), register() with password validation
|
||||
- `MongoUserRepository`: findByEmail(), create()
|
||||
- `AuthService`: login() supports email OR userName, register() checks for existing email AND userName
|
||||
- `AuthMiddleware`: Validates X-User-Id header for protected routes
|
||||
- `MongoUserRepository`: findById(), findByEmail(), findByUserName(), create()
|
||||
- `utils/password`: hash(), compare() using bcrypt
|
||||
- `utils/jwt`: signToken() (verifyToken() pending)
|
||||
- `scripts/hash-password.js`: Utility for manual password resets
|
||||
- `dotenv` integration for environment variables
|
||||
- `ChatController`: sendMessage(), confirmEvent(), rejectEvent()
|
||||
- `ChatService`: processMessage() with test responses (create, update, delete actions), confirmEvent() handles all CRUD actions
|
||||
@@ -338,14 +345,24 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- `ai/utils/`: Provider-agnostic shared utilities (systemPrompt, toolDefinitions, toolExecutor, eventFormatter)
|
||||
- `logging/`: Structured logging with pino, pino-http middleware, @Logged decorator
|
||||
- All repositories and GPTAdapter decorated with @Logged for automatic method logging
|
||||
- CORS configured to allow X-User-Id header
|
||||
- **Stubbed (TODO):**
|
||||
- `AuthMiddleware.authenticate()`: Currently uses fake user for testing
|
||||
- `AuthController`: refresh(), logout()
|
||||
- `AuthService`: refreshToken()
|
||||
- JWT authentication (currently using simple X-User-Id header)
|
||||
|
||||
**Shared:** Types, DTOs, constants (Day, Month with German translations), ExpandedEvent type, and date utilities defined and exported.
|
||||
|
||||
**Frontend:**
|
||||
- **Authentication fully implemented:**
|
||||
- `AuthStore`: Manages user state with expo-secure-store (native) / localStorage (web)
|
||||
- `AuthService`: login(), register(), logout() - calls backend API
|
||||
- `ApiClient`: Automatically injects X-User-Id header for authenticated requests
|
||||
- Login screen: Supports email OR userName login
|
||||
- Register screen: Email validation, checks for existing email/userName
|
||||
- `AuthButton`: Reusable button component with shadow effect
|
||||
- `Header`: Contains logout button on all screens
|
||||
- `index.tsx`: Auth redirect - checks stored user on app start
|
||||
- Tab navigation (Chat, Calendar) implemented with basic UI
|
||||
- Calendar screen fully functional:
|
||||
- Month navigation with grid display and Ionicons (chevron-back/forward)
|
||||
@@ -362,7 +379,6 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- 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 with request/response logging
|
||||
- `EventService`: getAll(), getById(), getByDateRange(), create(), update(), delete() - fully implemented
|
||||
- `ChatService`: sendMessage(), confirmEvent(), rejectEvent(), getConversations(), getConversation() - fully implemented with cursor pagination
|
||||
- `EventCardBase`: Shared base component with event layout (header, date/time/recurring icons, description) - used by both EventCard and ProposedEventCard
|
||||
@@ -371,8 +387,7 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- `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(), addMessages(), updateMessage(), clearMessages() - loads from server on mount and persists across tab switches
|
||||
- Auth screens (Login, Register), Event Detail, and Note screens exist as skeletons
|
||||
- AuthStore defined with `throw new Error('Not implemented')`
|
||||
- Event Detail and Note screens exist as skeletons
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user