d1736c5991
continuous-integration/drone/push Build is passing
- Implemented comprehensive audit logging for Tasks, Users, Settings, Goals, Labels, AI Chat, and Rewards. - Added Admin UI for MCP Server settings and Audit Logs. - Created docker-compose-production.yml with Traefik configuration. - Fixed backend bugs (missing storage methods, route closure). - Added Audit Logging Guidelines.
69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
import { IStorage } from "./storage";
|
|
import { User, InsertXpEvent } from "@shared/schema";
|
|
import { getLevelFromXP } from "@shared/gamification";
|
|
|
|
// Constants for XP Actions
|
|
export const XP_RULES = {
|
|
CREATE_TASK: 10,
|
|
CREATE_SUBTASK: 5,
|
|
UPDATE_TASK: 2, // Small amount for tweaking/updating
|
|
COMPLETE_TASK: 50,
|
|
COMPLETE_TASK_LATE: 20, // Reduced for overdue
|
|
AI_ACTION: 5, // For using AI features
|
|
LOGIN_STREAK: 100
|
|
};
|
|
|
|
export class GamificationService {
|
|
private storage: IStorage;
|
|
|
|
constructor(storage: IStorage) {
|
|
this.storage = storage;
|
|
}
|
|
|
|
async awardXP(userId: string, source: string, amount?: number, description?: string): Promise<{ user: User, levelUp: boolean, oldLevel: number, newLevel: number }> {
|
|
const user = await this.storage.getUser(userId);
|
|
if (!user) throw new Error("User not found");
|
|
|
|
const xpAmount = amount || this.getXPForSource(source);
|
|
const newTotalXP = (user.xp || 0) + xpAmount;
|
|
|
|
// Check for level up
|
|
const oldLevel = getLevelFromXP(user.xp || 0);
|
|
const newLevel = getLevelFromXP(newTotalXP);
|
|
const levelUp = newLevel > oldLevel;
|
|
|
|
// Update User
|
|
await this.storage.updateUserXP(userId, newTotalXP);
|
|
|
|
// Log Event
|
|
await this.storage.logXpEvent({
|
|
userId,
|
|
amount: xpAmount,
|
|
source,
|
|
});
|
|
|
|
// If Level Up, we could log a special event or notification here?
|
|
|
|
const updatedUser = await this.storage.getUser(userId);
|
|
return {
|
|
user: updatedUser!,
|
|
levelUp,
|
|
oldLevel,
|
|
newLevel
|
|
};
|
|
}
|
|
|
|
private getXPForSource(source: string): number {
|
|
switch (source) {
|
|
case 'create_task': return XP_RULES.CREATE_TASK;
|
|
case 'create_subtask': return XP_RULES.CREATE_SUBTASK;
|
|
case 'update_task': return XP_RULES.UPDATE_TASK;
|
|
case 'complete_task': return XP_RULES.COMPLETE_TASK;
|
|
case 'complete_task_late': return XP_RULES.COMPLETE_TASK_LATE;
|
|
case 'ai_action': return XP_RULES.AI_ACTION;
|
|
case 'daily_streak': return XP_RULES.LOGIN_STREAK;
|
|
default: return 0;
|
|
}
|
|
}
|
|
}
|