Compare commits

...

2 Commits

Author SHA1 Message Date
73e768a0ad refactor: remove all JWT-related code and references
JWT was never used - auth uses X-User-Id header. Removes jwt.ts utility,
jsonwebtoken dependency, stubbed refresh/logout endpoints, and updates
all docs (PUML diagrams, api-routes, tex, CLAUDE.md) accordingly.
2026-02-09 20:02:05 +01:00
cb32bd23ca docs: add .env.example files for client and server 2026-02-09 19:57:55 +01:00
14 changed files with 46 additions and 179 deletions

View File

@@ -48,7 +48,7 @@ npm run start -w @calchat/server # Run compiled server (port 3000)
| | MongoDB | Database | | | MongoDB | Database |
| | Mongoose | ODM | | | Mongoose | ODM |
| | GPT (OpenAI) | AI/LLM for chat | | | GPT (OpenAI) | AI/LLM for chat |
| | X-User-Id Header | Authentication (simple, no JWT yet) | | | X-User-Id Header | Authentication |
| | pino / pino-http | Structured logging | | | pino / pino-http | Structured logging |
| | react-native-logs | Client-side logging | | | react-native-logs | Client-side logging |
| | tsdav | CalDAV client library | | | tsdav | CalDAV client library |
@@ -235,7 +235,7 @@ CardBase
src/ src/
├── app.ts # Entry point, DI setup, Express config ├── app.ts # Entry point, DI setup, Express config
├── controllers/ # Request handlers + middleware (per architecture diagram) ├── controllers/ # Request handlers + middleware (per architecture diagram)
│ ├── AuthController.ts # login(), register(), refresh(), logout() │ ├── AuthController.ts # login(), register()
│ ├── ChatController.ts # sendMessage(), confirmEvent() + CalDAV push, rejectEvent(), getConversations(), getConversation(), updateProposalEvent() │ ├── ChatController.ts # sendMessage(), confirmEvent() + CalDAV push, rejectEvent(), getConversations(), getConversation(), updateProposalEvent()
│ ├── EventController.ts # create(), getById(), getAll(), getByDateRange(), update(), delete() - pushes/deletes to CalDAV on mutations │ ├── EventController.ts # create(), getById(), getAll(), getByDateRange(), update(), delete() - pushes/deletes to CalDAV on mutations
│ ├── CaldavController.ts # saveConfig(), loadConfig(), deleteConfig(), pullEvents(), pushEvents(), pushEvent() │ ├── CaldavController.ts # saveConfig(), loadConfig(), deleteConfig(), pullEvents(), pushEvents(), pushEvent()
@@ -285,7 +285,6 @@ src/
│ ├── toolDefinitions.ts # TOOL_DEFINITIONS - provider-agnostic tool specs │ ├── toolDefinitions.ts # TOOL_DEFINITIONS - provider-agnostic tool specs
│ └── toolExecutor.ts # executeToolCall() - handles getDay, proposeCreate/Update/Delete, searchEvents, getEventsInRange │ └── toolExecutor.ts # executeToolCall() - handles getDay, proposeCreate/Update/Delete, searchEvents, getEventsInRange
├── utils/ ├── utils/
│ ├── jwt.ts # signToken(), verifyToken() - NOT USED YET (no JWT)
│ ├── password.ts # hash(), compare() using bcrypt │ ├── password.ts # hash(), compare() using bcrypt
│ ├── eventFormatters.ts # getWeeksOverview(), getMonthOverview() - formatted event listings │ ├── eventFormatters.ts # getWeeksOverview(), getMonthOverview() - formatted event listings
│ └── recurrenceExpander.ts # expandRecurringEvents() - expand recurring events into occurrences │ └── recurrenceExpander.ts # expandRecurringEvents() - expand recurring events into occurrences
@@ -296,8 +295,6 @@ src/
**API Endpoints:** **API Endpoints:**
- `POST /api/auth/login` - User login - `POST /api/auth/login` - User login
- `POST /api/auth/register` - User registration - `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` - Get all events (protected)
- `GET /api/events/range` - Get events by date range (protected) - `GET /api/events/range` - Get events by date range (protected)
- `GET /api/events/:id` - Get single event (protected) - `GET /api/events/:id` - Get single event (protected)
@@ -536,8 +533,6 @@ docker compose up -d # Start Radicale CalDAV server
### Environment Variables ### Environment Variables
Server requires `.env` file in `apps/server/`: 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 MONGODB_URI=mongodb://root:mongoose@localhost:27017/calchat?authSource=admin
OPENAI_API_KEY=sk-proj-... OPENAI_API_KEY=sk-proj-...
USE_TEST_RESPONSES=false # true = static test responses, false = real GPT AI USE_TEST_RESPONSES=false # true = static test responses, false = real GPT AI
@@ -585,10 +580,6 @@ NODE_ENV=development # development = pretty logs, production = JSON
- `EventService`: Extended with searchByTitle(), findByCaldavUUID() - `EventService`: Extended with searchByTitle(), findByCaldavUUID()
- `utils/eventFormatters`: Refactored to use EventService instead of EventRepository - `utils/eventFormatters`: Refactored to use EventService instead of EventRepository
- CORS configured to allow X-User-Id header - CORS configured to allow X-User-Id header
- **Stubbed (TODO):**
- `AuthController`: refresh(), logout()
- `AuthService`: refreshToken()
- JWT authentication (currently using simple X-User-Id header)
**Shared:** **Shared:**
- Types, DTOs, constants (Day, Month with German translations), ExpandedEvent type, CaldavConfig, CaldavSyncStatus defined and exported - Types, DTOs, constants (Day, Month with German translations), ExpandedEvent type, CaldavConfig, CaldavSyncStatus defined and exported

8
apps/client/.env.example Normal file
View File

@@ -0,0 +1,8 @@
# Base URL of the CalChat API server
# Must include the /api path suffix
# Use your local network IP for mobile device testing, or localhost for emulator/web
# Examples:
# http://192.168.178.22:3001/api (local network, for physical device)
# http://localhost:3001/api (emulator or web)
# https://calchat.example.com/api (production)
EXPO_PUBLIC_API_URL=http://localhost:3001/api

28
apps/server/.env.example Normal file
View File

@@ -0,0 +1,28 @@
# OpenAI API key for GPT-based chat assistant
# Required for AI chat functionality
OPENAI_API_KEY=sk-proj-your-key-here
# Port the server listens on
# Default: 3000
PORT=3000
# MongoDB connection URI
# Default: mongodb://localhost:27017/calchat
# The Docker Compose setup uses root:mongoose credentials with authSource=admin
MONGODB_URI=mongodb://root:mongoose@localhost:27017/calchat?authSource=admin
# Use static test responses instead of real GPT calls
# Values: true | false
# Default: false
USE_TEST_RESPONSES=false
# Log level for pino logger
# Values: debug | info | warn | error | fatal
# Default: debug (development), info (production)
LOG_LEVEL=debug
# Node environment
# Values: development | production
# development = pretty-printed logs, production = JSON logs
# Default: development
NODE_ENV=development

View File

@@ -14,7 +14,6 @@
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"express": "^5.2.1", "express": "^5.2.1",
"ical.js": "^2.2.1", "ical.js": "^2.2.1",
"jsonwebtoken": "^9.0.3",
"mongoose": "^9.1.1", "mongoose": "^9.1.1",
"openai": "^6.15.0", "openai": "^6.15.0",
"pino": "^10.1.1", "pino": "^10.1.1",
@@ -27,7 +26,6 @@
"@types/express": "^5.0.6", "@types/express": "^5.0.6",
"@types/ical": "^0.8.3", "@types/ical": "^0.8.3",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"jest": "^30.2.0", "jest": "^30.2.0",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",

View File

@@ -22,11 +22,4 @@ export class AuthController {
} }
} }
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");
}
} }

View File

@@ -6,8 +6,6 @@ export function createAuthRoutes(authController: AuthController): Router {
router.post("/login", (req, res) => authController.login(req, res)); router.post("/login", (req, res) => authController.login(req, res));
router.post("/register", (req, res) => authController.register(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; return router;
} }

View File

@@ -1,6 +1,5 @@
import { User, CreateUserDTO, LoginDTO, AuthResponse } from "@calchat/shared"; import { CreateUserDTO, LoginDTO, AuthResponse } from "@calchat/shared";
import { UserRepository } from "./interfaces"; import { UserRepository } from "./interfaces";
import * as jwt from "../utils/jwt";
import * as password from "../utils/password"; import * as password from "../utils/password";
export class AuthService { export class AuthService {
@@ -46,11 +45,4 @@ export class AuthService {
return { user, accessToken: "" }; return { user, accessToken: "" };
} }
async refreshToken(refreshToken: string): Promise<AuthResponse> {
throw new Error("Not implemented");
}
async logout(userId: string): Promise<void> {
throw new Error("Not implemented");
}
} }

View File

@@ -1,2 +1 @@
export * from "./jwt";
export * from "./password"; export * from "./password";

View File

@@ -1,26 +0,0 @@
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");
}

View File

@@ -11,15 +11,13 @@ Base URL: `/api`
|--------|----------|--------------| |--------|----------|--------------|
| POST | `/auth/login` | User Login | | POST | `/auth/login` | User Login |
| POST | `/auth/register` | User Registrierung | | POST | `/auth/register` | User Registrierung |
| POST | `/auth/refresh` | JWT Token erneuern |
| POST | `/auth/logout` | User Logout |
--- ---
## Events ## Events
### Event Endpoints (`/api/events`) ### Event Endpoints (`/api/events`)
Alle Endpoints erfordern JWT-Authentifizierung. Alle Endpoints erfordern Authentifizierung (X-User-Id Header).
| Method | Endpoint | Beschreibung | | Method | Endpoint | Beschreibung |
|--------|----------|--------------| |--------|----------|--------------|
@@ -35,7 +33,7 @@ Alle Endpoints erfordern JWT-Authentifizierung.
## Chat ## Chat
### Chat Endpoints (`/api/chat`) ### Chat Endpoints (`/api/chat`)
Alle Endpoints erfordern JWT-Authentifizierung. Alle Endpoints erfordern Authentifizierung (X-User-Id Header).
| Method | Endpoint | Beschreibung | | Method | Endpoint | Beschreibung |
|--------|----------|--------------| |--------|----------|--------------|

View File

@@ -188,11 +188,6 @@ package "Models" #D3D3D3 {
} }
package "Utils" #DDA0DD { package "Utils" #DDA0DD {
class JWT {
' +signToken()
' +verifyToken()
}
class Password { class Password {
' +hash() ' +hash()
' +compare() ' +compare()
@@ -215,8 +210,6 @@ ChatController --> CaldavService
EventController --> EventService EventController --> EventService
EventController --> CaldavService EventController --> CaldavService
CaldavController --> CaldavService CaldavController --> CaldavService
AuthMiddleware --> JWT
' Service -> Interfaces (intern) ' Service -> Interfaces (intern)
AuthService --> UserRepository AuthService --> UserRepository
ChatService --> ChatRepository ChatService --> ChatRepository
@@ -227,7 +220,6 @@ CaldavService --> CaldavRepository
CaldavService --> EventService CaldavService --> EventService
' Auth uses Utils ' Auth uses Utils
AuthService --> JWT
AuthService --> Password AuthService --> Password
' Event/Chat uses Utils ' Event/Chat uses Utils

View File

@@ -77,7 +77,6 @@ package "apps/server (Express.js)" as ServerPkg #98FB98 {
} }
package "Utils" { package "Utils" {
[JWT] as JWTUtil
[Password] as PwdUtil [Password] as PwdUtil
[RecurrenceExpander] as RecExpander [RecurrenceExpander] as RecExpander
[EventFormatters] as EvtFormatters [EventFormatters] as EvtFormatters
@@ -154,9 +153,7 @@ GPT ..|> Interfaces
Repos ..|> Interfaces Repos ..|> Interfaces
' Backend: Service -> Utils ' Backend: Service -> Utils
AuthSvc --> JWTUtil
AuthSvc --> PwdUtil AuthSvc --> PwdUtil
Middleware --> JWTUtil
EventSvc --> RecExpander EventSvc --> RecExpander
ChatSvc --> EvtFormatters ChatSvc --> EvtFormatters

View File

@@ -66,7 +66,7 @@ Backend & Express.js & Web-App Framework \\
& MongoDB & Datenbank \\ & MongoDB & Datenbank \\
& Mongoose & ODM \\ & Mongoose & ODM \\
& Claude (Anthropic) & KI / LLM \\ & Claude (Anthropic) & KI / LLM \\
& JWT & Authentifizierung \\ & X-User-Id Header & Authentifizierung \\
\hline \hline
Geplant & iCalendar & Event-Export \\ Geplant & iCalendar & Event-Export \\
\hline \hline
@@ -112,8 +112,9 @@ Der wichtigste Teil der App ist die KI-Integration über \textbf{Claude}
(Anthropic). Dieses LLM verarbeitet natürlichsprachliche Eingaben der Nutzer und (Anthropic). Dieses LLM verarbeitet natürlichsprachliche Eingaben der Nutzer und
generiert daraus strukturierte Event-Vorschläge. generiert daraus strukturierte Event-Vorschläge.
Die Authentifizierung läuft über \textbf{JSON Web Tokens} (JWT). Der Vorteil: Die Authentifizierung erfolgt über einen \textbf{X-User-Id Header}, der bei
zustandslose Sessions, bei denen der Server keine Session-Daten speichern muss. jedem Request die User-ID mitschickt. Diese einfache Lösung reicht für den
aktuellen Entwicklungsstand aus.
Geplant ist außerdem die Unterstützung des \textbf{iCalendar}-Formats (ICAL) Geplant ist außerdem die Unterstützung des \textbf{iCalendar}-Formats (ICAL)
für den Export von Kalender-Events. für den Export von Kalender-Events.
@@ -157,7 +158,7 @@ Notiz-Feld) und ChatMessage.
Der Controller Layer bildet die Schnittstelle zwischen Frontend und Der Controller Layer bildet die Schnittstelle zwischen Frontend und
Backend-Logik. Die Routes definieren die API-Endpunkte, die Controller Backend-Logik. Die Routes definieren die API-Endpunkte, die Controller
verarbeiten die eingehenden Requests und reichen diese an die Services weiter. verarbeiten die eingehenden Requests und reichen diese an die Services weiter.
Eine Auth Middleware prüft bei geschützten Routen den JWT-Token. Eine Auth Middleware prüft bei geschützten Routen den X-User-Id Header.
\subsubsection{Service Layer} \subsubsection{Service Layer}

102
package-lock.json generated
View File

@@ -72,7 +72,6 @@
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"express": "^5.2.1", "express": "^5.2.1",
"ical.js": "^2.2.1", "ical.js": "^2.2.1",
"jsonwebtoken": "^9.0.3",
"mongoose": "^9.1.1", "mongoose": "^9.1.1",
"openai": "^6.15.0", "openai": "^6.15.0",
"pino": "^10.1.1", "pino": "^10.1.1",
@@ -85,7 +84,6 @@
"@types/express": "^5.0.6", "@types/express": "^5.0.6",
"@types/ical": "^0.8.3", "@types/ical": "^0.8.3",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"jest": "^30.2.0", "jest": "^30.2.0",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
@@ -4936,20 +4934,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/jsonwebtoken": {
"version": "9.0.10",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/ms": "*",
"@types/node": "*"
}
},
"node_modules/@types/ms": {
"version": "2.1.0",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.10.1", "version": "24.10.1",
"license": "MIT", "license": "MIT",
@@ -6076,10 +6060,6 @@
"ieee754": "^1.1.13" "ieee754": "^1.1.13"
} }
}, },
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"license": "BSD-3-Clause"
},
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"license": "MIT" "license": "MIT"
@@ -6844,13 +6824,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"license": "MIT" "license": "MIT"
@@ -13280,36 +13253,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/jsonwebtoken": {
"version": "9.0.3",
"license": "MIT",
"dependencies": {
"jws": "^4.0.1",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jsonwebtoken/node_modules/semver": {
"version": "7.7.3",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jsx-ast-utils": { "node_modules/jsx-ast-utils": {
"version": "3.3.5", "version": "3.3.5",
"dev": true, "dev": true,
@@ -13324,23 +13267,6 @@
"node": ">=4.0" "node": ">=4.0"
} }
}, },
"node_modules/jwa": {
"version": "2.0.1",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "4.0.1",
"license": "MIT",
"dependencies": {
"jwa": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kareem": { "node_modules/kareem": {
"version": "3.0.0", "version": "3.0.0",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -13502,30 +13428,6 @@
"version": "4.0.8", "version": "4.0.8",
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.includes": {
"version": "4.3.0",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"license": "MIT"
},
"node_modules/lodash.memoize": { "node_modules/lodash.memoize": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -13538,10 +13440,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.once": {
"version": "4.1.1",
"license": "MIT"
},
"node_modules/lodash.throttle": { "node_modules/lodash.throttle": {
"version": "4.1.1", "version": "4.1.1",
"license": "MIT" "license": "MIT"