implement event persistence and improve Mongoose TypeScript patterns

- Add event persistence: confirmed events are now saved to MongoDB
- Refactor Mongoose models to use virtuals for id field with IdVirtual interface
- Update repositories to use toJSON() with consistent type casting
- Add more test responses for chat (doctor, birthday, gym, etc.)
- Show event description in ProposedEventCard
- Change mongo-express port to 8083
- Update CLAUDE.md with Mongoose model pattern documentation
This commit is contained in:
2026-01-04 11:52:05 +01:00
parent c33508a227
commit 9fecf94c7d
13 changed files with 240 additions and 48 deletions

View File

@@ -124,6 +124,7 @@ src/
│ ├── index.ts # Re-exports from ./mongo
│ └── mongo/ # MongoDB implementation
│ ├── models/ # Mongoose schemas
│ │ ├── types.ts # Shared types (IdVirtual interface)
│ │ ├── UserModel.ts
│ │ ├── EventModel.ts
│ │ └── ChatModel.ts
@@ -193,6 +194,35 @@ The repository pattern allows swapping databases:
- **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
@@ -218,7 +248,7 @@ docker compose up -d # Start MongoDB + Mongo Express
docker compose down # Stop services
```
- MongoDB: `localhost:27017` (root/mongoose)
- Mongo Express UI: `localhost:8081` (admin/admin)
- Mongo Express UI: `localhost:8083` (admin/admin)
### Environment Variables
Server requires `.env` file in `apps/server/`:
@@ -239,16 +269,16 @@ MONGODB_URI=mongodb://root:mongoose@localhost:27017/calchat?authSource=admin
- `utils/jwt`: signToken() (verifyToken() pending)
- `dotenv` integration for environment variables
- `ChatController`: sendMessage(), confirmEvent(), rejectEvent()
- `ChatService`: processMessage() with test responses, confirmEvent(), rejectEvent()
- `ChatService`: processMessage() with test responses, confirmEvent() saves events to DB, rejectEvent()
- **Stubbed (TODO):**
- `AuthMiddleware.authenticate()`: Currently uses fake user for testing
- `AuthController`: refresh(), logout()
- `AuthService`: refreshToken()
- `ChatController`: getConversations(), getConversation()
- `MongoChatRepository`: Database persistence for chat
- All Event functionality
- `MongoEventRepository`: Only create() implemented, rest stubbed
- **Not started:**
- `EventController`, `EventService`, `MongoEventRepository`
- `EventController`, `EventService`
- `ClaudeAdapter` (AI integration - currently using test responses)
**Shared:** Types, DTOs, constants (Day, Month), and date utilities defined and exported.
@@ -258,8 +288,8 @@ MONGODB_URI=mongodb://root:mongoose@localhost:27017/calchat?authSource=admin
- 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(), rejectEvent() implemented
- `ProposedEventCard`: Displays proposed events with confirm/reject buttons, theming support
- `ChatService`: sendMessage(), confirmEvent(convId, msgId, event), rejectEvent() - confirmEvent sends CreateEventDTO in body
- `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')`