Initial commit: Inner OS v1
Full-stack inner development operating system built on Next.js 16 + Prisma 7 + PostgreSQL + OpenAI + Clerk. Generates personalized daily mental training tasks, collects reflection, updates user state, and provides internal reward feedback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import type { RewardEventType } from "@/generated/prisma/client";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface RewardEvent {
|
||||
type: RewardEventType;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface RewardContext {
|
||||
isFirstSession: boolean;
|
||||
streakMilestone: boolean;
|
||||
streakDays: number;
|
||||
stageAdvanced: boolean;
|
||||
newStage: number;
|
||||
totalSessionsCompleted: number;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Reward messages
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const FIRST_SESSION_MESSAGES = [
|
||||
"Your first practice is complete. This is where the path begins — not with a destination, but with a single step.",
|
||||
"Day one. You didn't just think about it — you did it. That's the difference that makes all the difference.",
|
||||
"Welcome to your practice. The door is open now. Walk through it again tomorrow.",
|
||||
];
|
||||
|
||||
const STREAK_3_MESSAGES = [
|
||||
"Three days in a row. A pattern is forming. Your mind is starting to expect this — that's the habit taking root.",
|
||||
"Day three. The first two days were willpower. Today is the beginning of momentum.",
|
||||
];
|
||||
|
||||
const STREAK_7_MESSAGES = [
|
||||
"Seven days. A full week of showing up for yourself. Most people never make it this far. You did.",
|
||||
"One week of daily practice. Your brain is literally rewiring. Neuroplasticity isn't a metaphor — it's what's happening right now.",
|
||||
];
|
||||
|
||||
const STREAK_14_MESSAGES = [
|
||||
"Two weeks. Research says it takes 21 days to form a habit — you're two-thirds there, and it already feels different, doesn't it?",
|
||||
"Fourteen consecutive days. You're not 'trying to meditate' anymore. You're someone who practices. The identity has shifted.",
|
||||
];
|
||||
|
||||
const STREAK_30_MESSAGES = [
|
||||
"Thirty days. A month of daily practice. Whatever you were before you started — anxious, scattered, reactive — you're becoming someone else now. Someone who can watch their own mind and choose.",
|
||||
"One month. This isn't a streak anymore. It's a practice. It's part of who you are. The question is no longer 'will I practice today?' but 'when?'",
|
||||
];
|
||||
|
||||
const STAGE_UP_MESSAGES: Record<number, string[]> = {
|
||||
1: [
|
||||
"You've reached the Foundation stage. The basics are in place. Now we build depth — longer sessions, subtler awareness.",
|
||||
"Stage up: Foundation. You've moved from trying to training. The practice is becoming familiar territory.",
|
||||
],
|
||||
2: [
|
||||
"Growing stage reached. Your consistency is solid and your awareness is sharpening. This is where practice starts to change how you move through the world.",
|
||||
"Stage up: Growing. You're past the awkward beginner phase. Your sessions have texture and depth now.",
|
||||
],
|
||||
3: [
|
||||
"Established. Fifteen sessions and strong consistency. Your inner world is becoming legible to you. This is emotional literacy in action.",
|
||||
"Stage up: Established. Your practice has roots. What started as a daily exercise is becoming a way of being.",
|
||||
],
|
||||
4: [
|
||||
"Advanced. This is rare territory. Most people never develop this level of inner awareness. Your practice now informs everything you do.",
|
||||
"Stage up: Advanced. You're not just practicing awareness — you're living it. The boundary between 'practice' and 'life' is dissolving.",
|
||||
],
|
||||
};
|
||||
|
||||
const GENERIC_COMPLETION_MESSAGES = [
|
||||
"Done. You showed up, you practiced, you reflected. That's the whole game — and you're playing it.",
|
||||
"Practice complete. Notice how you feel right now compared to before. That shift is the point.",
|
||||
"Another session in the books. Not every practice will feel profound — but every practice counts.",
|
||||
"You did the work today. Not tomorrow, not 'when things calm down' — today. That's discipline, and discipline is self-love.",
|
||||
"Session finished. Your future self — the one with more clarity, more calm, more choice — thanks you.",
|
||||
];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Reward generation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function pick<T>(arr: T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
export function generateRewards(ctx: RewardContext): RewardEvent[] {
|
||||
const rewards: RewardEvent[] = [];
|
||||
|
||||
// First session — highest priority reward
|
||||
if (ctx.isFirstSession) {
|
||||
rewards.push({
|
||||
type: "first_session",
|
||||
message: pick(FIRST_SESSION_MESSAGES),
|
||||
});
|
||||
// Also give a daily completion reward
|
||||
rewards.push({
|
||||
type: "daily_completion",
|
||||
message: pick(GENERIC_COMPLETION_MESSAGES),
|
||||
});
|
||||
return rewards;
|
||||
}
|
||||
|
||||
// Always give daily completion
|
||||
rewards.push({
|
||||
type: "daily_completion",
|
||||
message: pick(GENERIC_COMPLETION_MESSAGES),
|
||||
});
|
||||
|
||||
// Streak milestones (only one per session, highest applicable)
|
||||
if (ctx.streakMilestone) {
|
||||
if (ctx.streakDays === 30) {
|
||||
rewards.push({ type: "streak_30", message: pick(STREAK_30_MESSAGES) });
|
||||
} else if (ctx.streakDays === 14) {
|
||||
rewards.push({ type: "streak_14", message: pick(STREAK_14_MESSAGES) });
|
||||
} else if (ctx.streakDays === 7) {
|
||||
rewards.push({ type: "streak_7", message: pick(STREAK_7_MESSAGES) });
|
||||
} else if (ctx.streakDays === 3) {
|
||||
rewards.push({ type: "streak_3", message: pick(STREAK_3_MESSAGES) });
|
||||
}
|
||||
}
|
||||
|
||||
// Stage advancement
|
||||
if (ctx.stageAdvanced && ctx.newStage > 0) {
|
||||
const messages = STAGE_UP_MESSAGES[ctx.newStage];
|
||||
if (messages) {
|
||||
rewards.push({ type: "stage_up", message: pick(messages) });
|
||||
}
|
||||
}
|
||||
|
||||
return rewards;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Persist rewards to database
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function persistRewards(
|
||||
userId: string,
|
||||
rewards: RewardEvent[],
|
||||
prisma: { rewardEvent: { create: (args: { data: any }) => Promise<any> } }
|
||||
): Promise<void> {
|
||||
await Promise.all(
|
||||
rewards.map((r) =>
|
||||
prisma.rewardEvent.create({
|
||||
data: {
|
||||
userId,
|
||||
type: r.type,
|
||||
message: r.message,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user