diff --git a/apps/admin/data/fitai.db b/apps/admin/data/fitai.db
index 3bba925..c1d83da 100644
Binary files a/apps/admin/data/fitai.db and b/apps/admin/data/fitai.db differ
diff --git a/apps/admin/next-env.d.ts b/apps/admin/next-env.d.ts
index 9edff1c..c4b7818 100644
--- a/apps/admin/next-env.d.ts
+++ b/apps/admin/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/types/routes.d.ts";
+import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/apps/admin/src/app/api/users/gym/route.ts b/apps/admin/src/app/api/users/gym/route.ts
index 93efe00..478b81a 100644
--- a/apps/admin/src/app/api/users/gym/route.ts
+++ b/apps/admin/src/app/api/users/gym/route.ts
@@ -12,6 +12,7 @@ import { db, users as usersTable, eq, sql } from "@fitai/database";
export async function PATCH(req: Request) {
try {
const { userId } = await auth();
+ console.log("PATCH /api/users/gym auth userId:", userId);
if (!userId) return new NextResponse("Unauthorized", { status: 401 });
const body = await req.json().catch(() => null);
@@ -23,25 +24,32 @@ export async function PATCH(req: Request) {
}
const gymId = body.gymId === null ? null : String(body.gymId);
+ console.log("PATCH /api/users/gym parsed gymId from body:", gymId);
// Ensure user exists
+ console.log("PATCH /api/users/gym fetching user by id:", userId);
const user = await db
.select()
.from(usersTable)
.where(eq(usersTable.id, userId))
.get();
+ console.log("PATCH /api/users/gym fetched user:", user);
if (!user) return new NextResponse("User not found", { status: 404 });
// Validate gym when provided
if (gymId) {
+ console.log("PATCH /api/users/gym validating gym:", gymId);
const rows = await db.all(
sql`SELECT status FROM gyms WHERE id = ${gymId} LIMIT 1`,
);
+ console.log("PATCH /api/users/gym validation query result rows:", rows);
const gym = rows?.[0] as { status?: string } | undefined;
if (!gym) {
+ console.log("PATCH /api/users/gym validation: gym not found");
return NextResponse.json({ error: "Gym not found" }, { status: 404 });
}
if (gym.status !== "active") {
+ console.log("PATCH /api/users/gym validation: gym not active", gym);
return NextResponse.json(
{ error: "Gym is not active" },
{ status: 400 },
@@ -50,15 +58,21 @@ export async function PATCH(req: Request) {
}
// Update user's gym selection
+ console.log("PATCH /api/users/gym updating user gym_id:", {
+ userId,
+ gymId,
+ });
await db.run(
sql`UPDATE users SET gym_id = ${gymId ?? null}, updated_at = ${new Date()} WHERE id = ${userId}`,
);
+ console.log("PATCH /api/users/gym update completed");
const updated = await db
.select()
.from(usersTable)
.where(eq(usersTable.id, userId))
.get();
+ console.log("PATCH /api/users/gym returning updated user:", updated);
return NextResponse.json(updated);
} catch (error) {
console.error("PATCH /users/gym error:", error);
diff --git a/apps/admin/src/app/api/users/route.ts b/apps/admin/src/app/api/users/route.ts
index 28aac92..74b59c9 100644
--- a/apps/admin/src/app/api/users/route.ts
+++ b/apps/admin/src/app/api/users/route.ts
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { getDatabase } from "../../../lib/database/index";
import bcrypt from "bcryptjs";
import { auth, clerkClient } from "@clerk/nextjs/server";
+import { db as rawDb, sql } from "@fitai/database";
export async function GET(request: NextRequest) {
try {
@@ -11,9 +12,47 @@ export async function GET(request: NextRequest) {
let users = await db.getAllUsers();
+ // Hydrate gymId from raw DB to ensure consistency with writes
+ const rawUserRows = await rawDb.all(sql`SELECT id, gym_id FROM users`);
+ const gymById = new Map(
+ (rawUserRows || []).map((r: any) => [
+ r.id as string,
+ (r.gym_id as string | null) ?? null,
+ ]),
+ );
+
+ // Load gym names for mapping gymId -> gymName
+ const gymRows = await rawDb.all(sql`SELECT id, name FROM gyms`);
+ const gymNames = new Map(
+ (gymRows || [])
+ .filter((g: any) => !!g && typeof g.id === "string")
+ .map((g: any) => [
+ g.id as string,
+ (g.name as string) || (g.id as string),
+ ]),
+ );
+ console.log(
+ "GET /api/users: total users fetched from DB:",
+ Array.isArray(users) ? users.length : 0,
+ );
+
if (role) {
users = users.filter((user) => user.role === role);
}
+ console.log(
+ "GET /api/users: role filter:",
+ role,
+ "users after filter:",
+ Array.isArray(users) ? users.length : 0,
+ "sample:",
+ users && users[0]
+ ? {
+ id: users[0].id,
+ role: users[0].role,
+ gymId: (users as any)[0].gymId,
+ }
+ : null,
+ );
const usersWithClients = await Promise.all(
users.map(async (user) => {
@@ -58,6 +97,15 @@ export async function GET(request: NextRequest) {
return {
...userWithoutPassword,
+ // Override gymId from raw DB hydration to avoid undefined from Drizzle mapping
+ gymId: gymById.get(user.id) ?? (user as any).gymId ?? undefined,
+ // Provide gymName mapped from gyms table
+ gymName: (() => {
+ const gid =
+ gymById.get(user.id) ?? (user as any).gymId ?? undefined;
+ if (!gid) return null;
+ return gymNames.get(gid) ?? null;
+ })(),
client,
isCheckedIn,
checkInTime,
@@ -68,6 +116,18 @@ export async function GET(request: NextRequest) {
}),
);
+ console.log(
+ "GET /api/users: responding users count:",
+ Array.isArray(usersWithClients) ? usersWithClients.length : 0,
+ "sample:",
+ usersWithClients && usersWithClients[0]
+ ? {
+ id: usersWithClients[0].id,
+ role: usersWithClients[0].role,
+ gymId: (usersWithClients as any)[0].gymId,
+ }
+ : null,
+ );
return NextResponse.json({ users: usersWithClients });
} catch (error) {
console.error("Get users error:", error);
@@ -216,6 +276,15 @@ export async function PUT(request: NextRequest) {
const db = await getDatabase();
const body = await request.json();
const { id, email, firstName, lastName, role, phone, gymId } = body;
+ console.log("PUT /api/users received body:", {
+ id,
+ email,
+ firstName,
+ lastName,
+ role,
+ phone,
+ gymId,
+ });
if (!id) {
return NextResponse.json(
@@ -277,6 +346,11 @@ export async function PUT(request: NextRequest) {
try {
const client = await clerkClient();
const publicMetadata: Record = {};
+ console.log("PUT /api/users preparing Clerk metadata update:", {
+ targetUserId: id,
+ role,
+ gymId,
+ });
if (role) {
publicMetadata.role = role;
@@ -286,7 +360,20 @@ export async function PUT(request: NextRequest) {
}
if (Object.keys(publicMetadata).length > 0) {
- await client.users.updateUser(id, { publicMetadata });
+ console.log(
+ "PUT /api/users calling Clerk updateUser with metadata:",
+ publicMetadata,
+ );
+ const clerkResult = await client.users.updateUser(id, {
+ publicMetadata,
+ });
+ console.log("PUT /api/users Clerk updateUser result:", {
+ id: clerkResult.id,
+ role: clerkResult.publicMetadata?.role,
+ gymId: clerkResult.publicMetadata?.gymId,
+ });
+ } else {
+ console.log("PUT /api/users no Clerk metadata changes requested");
}
} catch (clerkErr: any) {
console.error("Clerk metadata update error:", clerkErr);
@@ -297,16 +384,43 @@ export async function PUT(request: NextRequest) {
}
// Update local DB for immediate UI feedback (webhook will also sync)
- await db.updateUser(id, {
+ console.log(
+ "PUT /api/users raw SQL updating local DB user gym_id and fields",
+ );
+ await rawDb.run(
+ sql`UPDATE users
+ SET email = ${email ?? existingUser.email},
+ first_name = ${firstName ?? existingUser.firstName},
+ last_name = ${lastName ?? existingUser.lastName},
+ role = ${role ?? existingUser.role},
+ phone = ${phone !== undefined && typeof phone === "string" ? phone : (existingUser.phone ?? null)},
+ gym_id = ${gymId !== undefined ? gymId : (existingUser.gymId ?? null)},
+ updated_at = ${Date.now()}
+ WHERE id = ${id}`,
+ );
+ // Read back the updated row to surface gym_id and confirm write
+ const updatedRow = await rawDb.get(
+ sql`SELECT id, email, first_name, last_name, role, phone, gym_id, created_at, updated_at FROM users WHERE id = ${id}`,
+ );
+ console.log("PUT /api/users raw DB row after update:", updatedRow);
+
+ const updatedUser = {
+ ...existingUser,
email: email ?? existingUser.email,
firstName: firstName ?? existingUser.firstName,
lastName: lastName ?? existingUser.lastName,
role: role ?? existingUser.role,
phone: phone !== undefined ? phone : existingUser.phone,
- gymId: gymId !== undefined ? gymId : existingUser.gymId,
- });
+ gymId:
+ updatedRow?.gym_id !== undefined
+ ? updatedRow.gym_id
+ : gymId !== undefined
+ ? gymId
+ : existingUser.gymId,
+ };
+ console.log("PUT /api/users responding with updated user:", updatedUser);
- return NextResponse.json({ success: true });
+ return NextResponse.json({ user: updatedUser });
} catch (error) {
console.error("Update user error:", error);
return NextResponse.json(
diff --git a/apps/admin/src/components/users/UserGrid.tsx b/apps/admin/src/components/users/UserGrid.tsx
index d3a23ca..d9bc6b3 100644
--- a/apps/admin/src/components/users/UserGrid.tsx
+++ b/apps/admin/src/components/users/UserGrid.tsx
@@ -30,6 +30,7 @@ interface User {
role: string;
phone?: string;
gymId?: string;
+ gymName?: string | null;
createdAt: Date;
isCheckedIn?: boolean;
checkInTime?: Date;
@@ -143,7 +144,9 @@ export function UserGrid({
minWidth: 160,
valueFormatter: (params: any) => {
const gymId = params.value;
- if (!gymId) return "None";
+ const gymName = params.data?.gymName;
+ if (!gymId && !gymName) return "None";
+ if (gymName) return gymName;
return gymNames[gymId] || gymId;
},
},
diff --git a/apps/admin/src/components/users/UserManagement.tsx b/apps/admin/src/components/users/UserManagement.tsx
index 6e2d519..bcab3ad 100644
--- a/apps/admin/src/components/users/UserManagement.tsx
+++ b/apps/admin/src/components/users/UserManagement.tsx
@@ -77,10 +77,33 @@ export function UserManagement() {
const fetchUsers = async () => {
setLoading(true);
try {
- const url = filter === "all" ? "/api/users" : `/api/users?role=${filter}`;
+ const ts = Date.now();
+ const url =
+ filter === "all"
+ ? `/api/users?ts=${ts}`
+ : `/api/users?role=${filter}&ts=${ts}`;
- const response = await fetch(url);
+ console.log("UserManagement.fetchUsers: fetching URL", url);
+ const response = await fetch(url, { cache: "no-store" });
+ console.log(
+ "UserManagement.fetchUsers: response.ok",
+ response.ok,
+ "status",
+ response.status,
+ );
const data = await response.json();
+ console.log(
+ "UserManagement.fetchUsers: received users count",
+ Array.isArray(data.users) ? data.users.length : 0,
+ "sample",
+ data.users && data.users[0]
+ ? {
+ id: data.users[0].id,
+ gymId: data.users[0].gymId,
+ role: data.users[0].role,
+ }
+ : null,
+ );
setUsers(data.users || []);
} catch (error) {
console.error("Failed to fetch users:", error);
@@ -178,20 +201,80 @@ export function UserManagement() {
try {
if (selectedUser) {
// Update existing user
- const response = await fetch("/api/admin/set-user-metadata", {
- method: "POST",
+ console.log(
+ "UserManagement.handleSaveEdit: sending PUT /api/users payload",
+ {
+ id: selectedUser.id,
+ email: editForm.email,
+ firstName: editForm.firstName,
+ lastName: editForm.lastName,
+ role: editForm.role,
+ phone: editForm.phone,
+ gymId: editForm.gymId === "" ? null : editForm.gymId,
+ },
+ );
+ const response = await fetch("/api/users", {
+ method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
- targetUserId: selectedUser.id,
+ id: selectedUser.id,
+ email: editForm.email,
+ firstName: editForm.firstName,
+ lastName: editForm.lastName,
role: editForm.role,
+ phone: editForm.phone,
gymId: editForm.gymId === "" ? null : editForm.gymId,
}),
});
+ console.log(
+ "UserManagement.handleSaveEdit: PUT /api/users response.ok",
+ response.ok,
+ "status",
+ response.status,
+ );
if (response.ok) {
+ // Optimistically update local state so grid reflects changes immediately
+ setUsers((prev) =>
+ prev.map((u) =>
+ u.id === selectedUser.id
+ ? {
+ ...u,
+ email: editForm.email,
+ firstName: editForm.firstName,
+ lastName: editForm.lastName,
+ role: editForm.role,
+ phone: editForm.phone || undefined,
+ gymId: editForm.gymId === "" ? undefined : editForm.gymId,
+ }
+ : u,
+ ),
+ );
+ setSelectedUser((prev) =>
+ prev
+ ? {
+ ...prev,
+ email: editForm.email,
+ firstName: editForm.firstName,
+ lastName: editForm.lastName,
+ role: editForm.role,
+ phone: editForm.phone || undefined,
+ gymId: editForm.gymId === "" ? undefined : editForm.gymId,
+ }
+ : prev,
+ );
setIsEditing(false);
setEditForm(null);
+ // Still re-fetch from server to ensure consistency
+ console.log(
+ "UserManagement.handleSaveEdit: re-fetching users after successful edit",
+ );
fetchUsers();
} else {
+ const errText = await response.text().catch(() => "");
+ console.error("UserManagement.handleSaveEdit: update failed", {
+ status: response.status,
+ body: errText,
+ });
alert("Error updating user");
}
} else {
diff --git a/apps/admin/src/lib/database/drizzle.ts b/apps/admin/src/lib/database/drizzle.ts
index 40ca1eb..38cfe0e 100644
--- a/apps/admin/src/lib/database/drizzle.ts
+++ b/apps/admin/src/lib/database/drizzle.ts
@@ -1,38 +1,58 @@
-
-import { IDatabase, User, Client, FitnessProfile, Attendance, Recommendation, FitnessGoal, DatabaseConfig } from './types'
-import { db as defaultDb, users, clients, fitnessProfiles, attendance, recommendations, fitnessGoals, eq, and, desc, sql } from '@fitai/database'
-import { InferSelectModel } from 'drizzle-orm'
+import {
+ IDatabase,
+ User,
+ Client,
+ FitnessProfile,
+ Attendance,
+ Recommendation,
+ FitnessGoal,
+ DatabaseConfig,
+} from "./types";
+import {
+ db as defaultDb,
+ users,
+ clients,
+ fitnessProfiles,
+ attendance,
+ recommendations,
+ fitnessGoals,
+ eq,
+ and,
+ desc,
+ sql,
+} from "@fitai/database";
+import { InferSelectModel } from "drizzle-orm";
export class DrizzleDatabase implements IDatabase {
- private config: DatabaseConfig
- private db: typeof defaultDb
+ private config: DatabaseConfig;
+ private db: typeof defaultDb;
- constructor(config: DatabaseConfig, db?: typeof defaultDb) {
- this.config = config
- this.db = db || defaultDb
+ constructor(config: DatabaseConfig, db?: typeof defaultDb) {
+ this.config = config;
+ this.db = db || defaultDb;
+ }
+
+ async connect(): Promise {
+ // Drizzle with better-sqlite3 connects synchronously on initialization
+ // We can just log here if needed
+ if (this.config.options?.logging) {
+ console.log("Drizzle database connected");
}
+ await this.createTables();
+ }
- async connect(): Promise {
- // Drizzle with better-sqlite3 connects synchronously on initialization
- // We can just log here if needed
- if (this.config.options?.logging) {
- console.log('Drizzle database connected')
- }
- await this.createTables()
+ async disconnect(): Promise {
+ // better-sqlite3 handle is managed by Drizzle, usually no explicit disconnect needed for connection pooling
+ // but we can close the underlying sqlite instance if we had access to it.
+ // For now, we'll assume it's handled.
+ if (this.config.options?.logging) {
+ console.log("Drizzle database disconnected");
}
+ }
- async disconnect(): Promise {
- // better-sqlite3 handle is managed by Drizzle, usually no explicit disconnect needed for connection pooling
- // but we can close the underlying sqlite instance if we had access to it.
- // For now, we'll assume it's handled.
- if (this.config.options?.logging) {
- console.log('Drizzle database disconnected')
- }
- }
-
- private async createTables(): Promise {
- // Users table
- await this.db.run(sql`
+ private async createTables(): Promise {
+ // Users table
+ await this.db.run(sql`
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
@@ -41,13 +61,19 @@ export class DrizzleDatabase implements IDatabase {
password TEXT,
phone TEXT,
role TEXT NOT NULL CHECK (role IN ('superAdmin', 'admin', 'trainer', 'client')),
+ gym_id TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)
- `)
+ `);
- // Clients table
- await this.db.run(sql`
+ // Migration: ensure gym_id column exists on users (for existing DBs)
+ const userCols = await this.db.all(sql`PRAGMA table_info('users')`);
+ if (!userCols.some((c: any) => c.name === "gym_id")) {
+ await this.db.run(sql`ALTER TABLE users ADD COLUMN gym_id TEXT`);
+ }
+ // Clients table
+ await this.db.run(sql`
CREATE TABLE IF NOT EXISTS clients (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
@@ -62,10 +88,10 @@ export class DrizzleDatabase implements IDatabase {
updated_at INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
)
- `)
+ `);
- // Fitness profiles table
- await this.db.run(sql`
+ // Fitness profiles table
+ await this.db.run(sql`
CREATE TABLE IF NOT EXISTS fitness_profiles (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL UNIQUE,
@@ -84,10 +110,10 @@ export class DrizzleDatabase implements IDatabase {
updated_at INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
)
- `)
+ `);
- // Attendance table
- await this.db.run(sql`
+ // Attendance table
+ await this.db.run(sql`
CREATE TABLE IF NOT EXISTS attendance (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
@@ -98,10 +124,10 @@ export class DrizzleDatabase implements IDatabase {
created_at INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
)
- `)
+ `);
- // Recommendations table
- await this.db.run(sql`
+ // Recommendations table
+ await this.db.run(sql`
CREATE TABLE IF NOT EXISTS recommendations (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
@@ -118,10 +144,10 @@ export class DrizzleDatabase implements IDatabase {
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
FOREIGN KEY (fitness_profile_id) REFERENCES fitness_profiles (id) ON DELETE CASCADE
)
- `)
+ `);
- // Fitness Goals table
- await this.db.run(sql`
+ // Fitness Goals table
+ await this.db.run(sql`
CREATE TABLE IF NOT EXISTS fitness_goals (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
@@ -144,412 +170,551 @@ export class DrizzleDatabase implements IDatabase {
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
FOREIGN KEY (fitness_profile_id) REFERENCES fitness_profiles (id) ON DELETE CASCADE
)
- `)
+ `);
+ }
+
+ // User operations
+ async createUser(
+ userData: Omit & { id?: string },
+ ): Promise {
+ const id = userData.id || Math.random().toString(36).substr(2, 9);
+ const now = new Date();
+
+ const newUser = {
+ ...userData,
+ id,
+ createdAt: now,
+ updatedAt: now,
+ };
+
+ await this.db.insert(users).values(newUser);
+ return newUser;
+ }
+
+ async getUserById(id: string): Promise {
+ const result = await this.db
+ .select()
+ .from(users)
+ .where(eq(users.id, id))
+ .get();
+ return result ? this.mapUser(result) : null;
+ }
+
+ async getUserByEmail(email: string): Promise {
+ const result = await this.db
+ .select()
+ .from(users)
+ .where(eq(users.email, email))
+ .get();
+ return result ? this.mapUser(result) : null;
+ }
+
+ async getAllUsers(): Promise {
+ const results = await this.db
+ .select()
+ .from(users)
+ .orderBy(desc(users.createdAt))
+ .all();
+ return results.map(this.mapUser);
+ }
+
+ async updateUser(id: string, updates: Partial): Promise {
+ const { id: _, ...updateData } = updates;
+ if (Object.keys(updateData).length === 0) return this.getUserById(id);
+
+ await this.db
+ .update(users)
+ .set({ ...updateData, updatedAt: new Date() })
+ .where(eq(users.id, id))
+ .run();
+
+ return this.getUserById(id);
+ }
+
+ async deleteUser(id: string): Promise {
+ const result = await this.db.delete(users).where(eq(users.id, id)).run();
+ return result.changes > 0;
+ }
+
+ async migrateUserId(oldId: string, newId: string): Promise {
+ await this.db
+ .update(users)
+ .set({ id: newId })
+ .where(eq(users.id, oldId))
+ .run();
+ }
+
+ // Client operations
+ async createClient(clientData: Omit): Promise {
+ const id = Math.random().toString(36).substr(2, 9);
+ const newClient = {
+ id,
+ ...clientData,
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ };
+
+ await this.db.insert(clients).values(newClient as any);
+ return this.mapClient(newClient);
+ }
+
+ async getClientById(id: string): Promise {
+ const result = await this.db
+ .select()
+ .from(clients)
+ .where(eq(clients.id, id))
+ .get();
+ return result ? this.mapClient(result) : null;
+ }
+
+ async getClientByUserId(userId: string): Promise {
+ const result = await this.db
+ .select()
+ .from(clients)
+ .where(eq(clients.userId, userId))
+ .get();
+ return result ? this.mapClient(result) : null;
+ }
+
+ async getAllClients(): Promise {
+ const results = await this.db
+ .select()
+ .from(clients)
+ .orderBy(desc(clients.joinDate))
+ .all();
+ return results.map(this.mapClient);
+ }
+
+ async updateClient(
+ id: string,
+ updates: Partial,
+ ): Promise {
+ const { id: _, ...updateData } = updates;
+ if (Object.keys(updateData).length === 0) return this.getClientById(id);
+
+ await this.db
+ .update(clients)
+ .set({ ...updateData, updatedAt: new Date() } as any)
+ .where(eq(clients.id, id))
+ .run();
+
+ return this.getClientById(id);
+ }
+
+ async deleteClient(id: string): Promise {
+ const result = await this.db
+ .delete(clients)
+ .where(eq(clients.id, id))
+ .run();
+ return result.changes > 0;
+ }
+
+ // Fitness Profile operations
+ async createFitnessProfile(
+ profileData: Omit,
+ ): Promise {
+ const now = new Date();
+ const id = Math.random().toString(36).substr(2, 9);
+ const newProfile = {
+ id,
+ ...profileData,
+ createdAt: now,
+ updatedAt: now,
+ };
+
+ await this.db.insert(fitnessProfiles).values(newProfile as any);
+ return { id, ...profileData, createdAt: now, updatedAt: now };
+ }
+
+ async getFitnessProfileByUserId(
+ userId: string,
+ ): Promise {
+ const result = await this.db
+ .select()
+ .from(fitnessProfiles)
+ .where(eq(fitnessProfiles.userId, userId))
+ .get();
+ return result ? this.mapFitnessProfile(result) : null;
+ }
+
+ async getAllFitnessProfiles(): Promise {
+ const results = await this.db
+ .select()
+ .from(fitnessProfiles)
+ .orderBy(desc(fitnessProfiles.createdAt))
+ .all();
+ return results.map(this.mapFitnessProfile);
+ }
+
+ async updateFitnessProfile(
+ userId: string,
+ updates: Partial,
+ ): Promise {
+ const { userId: _, ...updateData } = updates;
+ if (Object.keys(updateData).length === 0)
+ return this.getFitnessProfileByUserId(userId);
+
+ const dbUpdates = { ...updateData } as any;
+ if (updateData.fitnessGoals) {
+ dbUpdates.fitnessGoals = JSON.stringify(updateData.fitnessGoals);
}
- // User operations
- async createUser(userData: Omit & { id?: string }): Promise {
- const id = userData.id || Math.random().toString(36).substr(2, 9)
- const now = new Date()
+ await this.db
+ .update(fitnessProfiles)
+ .set({ ...dbUpdates, updatedAt: new Date() })
+ .where(eq(fitnessProfiles.userId, userId))
+ .run();
- const newUser = {
- ...userData,
- id,
- createdAt: now,
- updatedAt: now
- }
+ return this.getFitnessProfileByUserId(userId);
+ }
- await this.db.insert(users).values(newUser)
- return newUser
+ async deleteFitnessProfile(userId: string): Promise {
+ const result = await this.db
+ .delete(fitnessProfiles)
+ .where(eq(fitnessProfiles.userId, userId))
+ .run();
+ return result.changes > 0;
+ }
+
+ // Attendance operations
+ async checkIn(
+ userId: string,
+ type: "gym" | "class" | "personal_training",
+ notes?: string,
+ ): Promise {
+ const id = Math.random().toString(36).substr(2, 9);
+ const now = new Date();
+
+ const newAttendance = {
+ id,
+ userId,
+ checkInTime: now,
+ type,
+ notes,
+ createdAt: now,
+ };
+
+ await this.db.insert(attendance).values(newAttendance as any);
+
+ // Update client last visit
+ const client = await this.getClientByUserId(userId);
+ if (client) {
+ await this.updateClient(client.id, { lastVisit: now });
}
- async getUserById(id: string): Promise {
- const result = await this.db.select().from(users).where(eq(users.id, id)).get()
- return result ? this.mapUser(result) : null
+ return newAttendance;
+ }
+
+ async checkOut(attendanceId: string): Promise {
+ const now = new Date();
+ await this.db
+ .update(attendance)
+ .set({ checkOutTime: now })
+ .where(eq(attendance.id, attendanceId))
+ .run();
+
+ return this.getAttendanceById(attendanceId);
+ }
+
+ async getAttendanceById(id: string): Promise {
+ const result = await this.db
+ .select()
+ .from(attendance)
+ .where(eq(attendance.id, id))
+ .get();
+ return result ? this.mapAttendance(result) : null;
+ }
+
+ async getAttendanceHistory(userId: string): Promise {
+ const results = await this.db
+ .select()
+ .from(attendance)
+ .where(eq(attendance.userId, userId))
+ .orderBy(desc(attendance.checkInTime))
+ .all();
+ return results.map(this.mapAttendance);
+ }
+
+ async getAllAttendance(): Promise {
+ const results = await this.db
+ .select()
+ .from(attendance)
+ .orderBy(desc(attendance.checkInTime))
+ .all();
+ return results.map(this.mapAttendance);
+ }
+
+ async getActiveCheckIn(userId: string): Promise {
+ // Drizzle doesn't support IS NULL in where directly with simple syntax sometimes, but eq(col, null) works or isNull(col)
+ // We need to check how to filter for null checkOutTime.
+ // In Drizzle, we can filter in JS or use isNull operator if imported.
+ // Let's fetch recent and filter for now to be safe, or use raw sql if needed, but better to use Drizzle operators.
+ // Actually, we can just fetch all for user and filter in memory since it's unlikely to be huge for active checkins,
+ // but correct way is `isNull(attendance.checkOutTime)`.
+ // Since I didn't import `isNull`, I'll fetch recent history and find first active.
+
+ const history = await this.getAttendanceHistory(userId);
+ return history.find((a) => !a.checkOutTime) || null;
+ }
+
+ // Recommendation operations
+ async createRecommendation(
+ data: Omit,
+ ): Promise {
+ const now = new Date();
+ const newRec = {
+ ...data,
+ createdAt: now,
+ status: data.status || "pending",
+ };
+
+ await this.db.insert(recommendations).values(newRec as any);
+ return newRec as Recommendation;
+ }
+
+ async getRecommendationsByUserId(userId: string): Promise {
+ const results = await this.db
+ .select()
+ .from(recommendations)
+ .where(eq(recommendations.userId, userId))
+ .orderBy(desc(recommendations.createdAt))
+ .all();
+ return results.map(this.mapRecommendation);
+ }
+
+ async getAllRecommendations(): Promise {
+ const results = await this.db
+ .select()
+ .from(recommendations)
+ .orderBy(desc(recommendations.createdAt))
+ .all();
+ return results.map(this.mapRecommendation);
+ }
+
+ async updateRecommendation(
+ id: string,
+ updates: Partial,
+ ): Promise {
+ const { id: _, ...updateData } = updates;
+ if (Object.keys(updateData).length === 0)
+ return this.getRecommendationById(id);
+
+ await this.db
+ .update(recommendations)
+ .set(updateData as any)
+ .where(eq(recommendations.id, id))
+ .run();
+
+ return this.getRecommendationById(id);
+ }
+
+ async deleteRecommendation(id: string): Promise {
+ const result = await this.db
+ .delete(recommendations)
+ .where(eq(recommendations.id, id))
+ .run();
+ return result.changes > 0;
+ }
+
+ async getRecommendationById(id: string): Promise {
+ const result = await this.db
+ .select()
+ .from(recommendations)
+ .where(eq(recommendations.id, id))
+ .get();
+ return result ? this.mapRecommendation(result) : null;
+ }
+
+ // Fitness Goals operations
+ async createFitnessGoal(
+ goalData: Omit,
+ ): Promise {
+ const now = new Date();
+ const newGoal = {
+ ...goalData,
+ createdAt: now,
+ updatedAt: now,
+ };
+
+ await this.db.insert(fitnessGoals).values(newGoal as any);
+ return newGoal as FitnessGoal;
+ }
+
+ async getFitnessGoalById(id: string): Promise {
+ const result = await this.db
+ .select()
+ .from(fitnessGoals)
+ .where(eq(fitnessGoals.id, id))
+ .get();
+ return result ? this.mapFitnessGoal(result) : null;
+ }
+
+ async getFitnessGoalsByUserId(
+ userId: string,
+ status?: string,
+ ): Promise {
+ let query = this.db
+ .select()
+ .from(fitnessGoals)
+ .where(eq(fitnessGoals.userId, userId));
+
+ if (status) {
+ query = this.db
+ .select()
+ .from(fitnessGoals)
+ .where(
+ and(
+ eq(fitnessGoals.userId, userId),
+ eq(fitnessGoals.status, status as any),
+ ),
+ );
}
- async getUserByEmail(email: string): Promise {
- const result = await this.db.select().from(users).where(eq(users.email, email)).get()
- return result ? this.mapUser(result) : null
+ const results = await query.orderBy(desc(fitnessGoals.createdAt)).all();
+ return results.map(this.mapFitnessGoal);
+ }
+
+ async updateFitnessGoal(
+ id: string,
+ updates: Partial,
+ ): Promise {
+ const { id: _, ...updateData } = updates;
+ if (Object.keys(updateData).length === 0)
+ return this.getFitnessGoalById(id);
+
+ await this.db
+ .update(fitnessGoals)
+ .set({ ...updateData, updatedAt: new Date() } as any)
+ .where(eq(fitnessGoals.id, id))
+ .run();
+
+ return this.getFitnessGoalById(id);
+ }
+
+ async deleteFitnessGoal(id: string): Promise {
+ const result = await this.db
+ .delete(fitnessGoals)
+ .where(eq(fitnessGoals.id, id))
+ .run();
+ return result.changes > 0;
+ }
+
+ async updateGoalProgress(
+ id: string,
+ currentValue: number,
+ ): Promise {
+ const goal = await this.getFitnessGoalById(id);
+ if (!goal) return null;
+
+ let progress = goal.progress;
+ if (goal.targetValue && goal.targetValue > 0) {
+ progress = Math.min(100, (currentValue / goal.targetValue) * 100);
}
- async getAllUsers(): Promise {
- const results = await this.db.select().from(users).orderBy(desc(users.createdAt)).all()
- return results.map(this.mapUser)
- }
-
- async updateUser(id: string, updates: Partial): Promise {
- const { id: _, ...updateData } = updates
- if (Object.keys(updateData).length === 0) return this.getUserById(id)
-
- await this.db.update(users)
- .set({ ...updateData, updatedAt: new Date() })
- .where(eq(users.id, id))
- .run()
-
- return this.getUserById(id)
- }
-
- async deleteUser(id: string): Promise {
- const result = await this.db.delete(users).where(eq(users.id, id)).run()
- return result.changes > 0
- }
-
- async migrateUserId(oldId: string, newId: string): Promise {
- await this.db.update(users).set({ id: newId }).where(eq(users.id, oldId)).run()
- }
-
- // Client operations
- async createClient(clientData: Omit): Promise {
- const id = Math.random().toString(36).substr(2, 9)
- const newClient = {
- id,
- ...clientData,
- createdAt: new Date(),
- updatedAt: new Date()
- }
-
- await this.db.insert(clients).values(newClient as any)
- return this.mapClient(newClient)
- }
-
- async getClientById(id: string): Promise {
- const result = await this.db.select().from(clients).where(eq(clients.id, id)).get()
- return result ? this.mapClient(result) : null
- }
-
- async getClientByUserId(userId: string): Promise {
- const result = await this.db.select().from(clients).where(eq(clients.userId, userId)).get()
- return result ? this.mapClient(result) : null
- }
-
- async getAllClients(): Promise {
- const results = await this.db.select().from(clients).orderBy(desc(clients.joinDate)).all()
- return results.map(this.mapClient)
- }
-
- async updateClient(id: string, updates: Partial): Promise {
- const { id: _, ...updateData } = updates
- if (Object.keys(updateData).length === 0) return this.getClientById(id)
-
- await this.db.update(clients)
- .set({ ...updateData, updatedAt: new Date() } as any)
- .where(eq(clients.id, id))
- .run()
-
- return this.getClientById(id)
- }
-
- async deleteClient(id: string): Promise {
- const result = await this.db.delete(clients).where(eq(clients.id, id)).run()
- return result.changes > 0
- }
-
- // Fitness Profile operations
- async createFitnessProfile(profileData: Omit): Promise {
- const now = new Date()
- const id = Math.random().toString(36).substr(2, 9)
- const newProfile = {
- id,
- ...profileData,
- createdAt: now,
- updatedAt: now
- }
-
- await this.db.insert(fitnessProfiles).values(newProfile as any)
- return { id, ...profileData, createdAt: now, updatedAt: now }
- }
-
- async getFitnessProfileByUserId(userId: string): Promise {
- const result = await this.db.select().from(fitnessProfiles).where(eq(fitnessProfiles.userId, userId)).get()
- return result ? this.mapFitnessProfile(result) : null
- }
-
- async getAllFitnessProfiles(): Promise {
- const results = await this.db.select().from(fitnessProfiles).orderBy(desc(fitnessProfiles.createdAt)).all()
- return results.map(this.mapFitnessProfile)
- }
-
- async updateFitnessProfile(userId: string, updates: Partial): Promise {
- const { userId: _, ...updateData } = updates
- if (Object.keys(updateData).length === 0) return this.getFitnessProfileByUserId(userId)
-
- const dbUpdates = { ...updateData } as any
- if (updateData.fitnessGoals) {
- dbUpdates.fitnessGoals = JSON.stringify(updateData.fitnessGoals)
- }
-
- await this.db.update(fitnessProfiles)
- .set({ ...dbUpdates, updatedAt: new Date() })
- .where(eq(fitnessProfiles.userId, userId))
- .run()
-
- return this.getFitnessProfileByUserId(userId)
- }
-
- async deleteFitnessProfile(userId: string): Promise {
- const result = await this.db.delete(fitnessProfiles).where(eq(fitnessProfiles.userId, userId)).run()
- return result.changes > 0
- }
-
- // Attendance operations
- async checkIn(userId: string, type: "gym" | "class" | "personal_training", notes?: string): Promise {
- const id = Math.random().toString(36).substr(2, 9)
- const now = new Date()
-
- const newAttendance = {
- id,
- userId,
- checkInTime: now,
- type,
- notes,
- createdAt: now
- }
-
- await this.db.insert(attendance).values(newAttendance as any)
-
- // Update client last visit
- const client = await this.getClientByUserId(userId)
- if (client) {
- await this.updateClient(client.id, { lastVisit: now })
- }
-
- return newAttendance
- }
-
- async checkOut(attendanceId: string): Promise {
- const now = new Date()
- await this.db.update(attendance)
- .set({ checkOutTime: now })
- .where(eq(attendance.id, attendanceId))
- .run()
-
- return this.getAttendanceById(attendanceId)
- }
-
- async getAttendanceById(id: string): Promise {
- const result = await this.db.select().from(attendance).where(eq(attendance.id, id)).get()
- return result ? this.mapAttendance(result) : null
- }
-
- async getAttendanceHistory(userId: string): Promise {
- const results = await this.db.select().from(attendance)
- .where(eq(attendance.userId, userId))
- .orderBy(desc(attendance.checkInTime))
- .all()
- return results.map(this.mapAttendance)
- }
-
- async getAllAttendance(): Promise {
- const results = await this.db.select().from(attendance)
- .orderBy(desc(attendance.checkInTime))
- .all()
- return results.map(this.mapAttendance)
- }
-
- async getActiveCheckIn(userId: string): Promise {
- // Drizzle doesn't support IS NULL in where directly with simple syntax sometimes, but eq(col, null) works or isNull(col)
- // We need to check how to filter for null checkOutTime.
- // In Drizzle, we can filter in JS or use isNull operator if imported.
- // Let's fetch recent and filter for now to be safe, or use raw sql if needed, but better to use Drizzle operators.
- // Actually, we can just fetch all for user and filter in memory since it's unlikely to be huge for active checkins,
- // but correct way is `isNull(attendance.checkOutTime)`.
- // Since I didn't import `isNull`, I'll fetch recent history and find first active.
-
- const history = await this.getAttendanceHistory(userId)
- return history.find(a => !a.checkOutTime) || null
- }
-
- // Recommendation operations
- async createRecommendation(data: Omit): Promise {
- const now = new Date()
- const newRec = {
- ...data,
- createdAt: now,
- status: data.status || 'pending'
- }
-
- await this.db.insert(recommendations).values(newRec as any)
- return newRec as Recommendation
- }
-
- async getRecommendationsByUserId(userId: string): Promise {
- const results = await this.db.select().from(recommendations)
- .where(eq(recommendations.userId, userId))
- .orderBy(desc(recommendations.createdAt))
- .all()
- return results.map(this.mapRecommendation)
- }
-
- async getAllRecommendations(): Promise {
- const results = await this.db.select().from(recommendations)
- .orderBy(desc(recommendations.createdAt))
- .all()
- return results.map(this.mapRecommendation)
- }
-
- async updateRecommendation(id: string, updates: Partial): Promise {
- const { id: _, ...updateData } = updates
- if (Object.keys(updateData).length === 0) return this.getRecommendationById(id)
-
- await this.db.update(recommendations)
- .set(updateData as any)
- .where(eq(recommendations.id, id))
- .run()
-
- return this.getRecommendationById(id)
- }
-
- async deleteRecommendation(id: string): Promise {
- const result = await this.db.delete(recommendations).where(eq(recommendations.id, id)).run()
- return result.changes > 0
- }
-
- async getRecommendationById(id: string): Promise {
- const result = await this.db.select().from(recommendations).where(eq(recommendations.id, id)).get()
- return result ? this.mapRecommendation(result) : null
- }
-
- // Fitness Goals operations
- async createFitnessGoal(goalData: Omit): Promise {
- const now = new Date()
- const newGoal = {
- ...goalData,
- createdAt: now,
- updatedAt: now
- }
-
- await this.db.insert(fitnessGoals).values(newGoal as any)
- return newGoal as FitnessGoal
- }
-
- async getFitnessGoalById(id: string): Promise {
- const result = await this.db.select().from(fitnessGoals).where(eq(fitnessGoals.id, id)).get()
- return result ? this.mapFitnessGoal(result) : null
- }
-
- async getFitnessGoalsByUserId(userId: string, status?: string): Promise {
- let query = this.db.select().from(fitnessGoals).where(eq(fitnessGoals.userId, userId))
-
- if (status) {
- query = this.db.select().from(fitnessGoals).where(and(eq(fitnessGoals.userId, userId), eq(fitnessGoals.status, status as any)))
- }
-
- const results = await query.orderBy(desc(fitnessGoals.createdAt)).all()
- return results.map(this.mapFitnessGoal)
- }
-
- async updateFitnessGoal(id: string, updates: Partial): Promise {
- const { id: _, ...updateData } = updates
- if (Object.keys(updateData).length === 0) return this.getFitnessGoalById(id)
-
- await this.db.update(fitnessGoals)
- .set({ ...updateData, updatedAt: new Date() } as any)
- .where(eq(fitnessGoals.id, id))
- .run()
-
- return this.getFitnessGoalById(id)
- }
-
- async deleteFitnessGoal(id: string): Promise {
- const result = await this.db.delete(fitnessGoals).where(eq(fitnessGoals.id, id)).run()
- return result.changes > 0
- }
-
- async updateGoalProgress(id: string, currentValue: number): Promise {
- const goal = await this.getFitnessGoalById(id)
- if (!goal) return null
-
- let progress = goal.progress
- if (goal.targetValue && goal.targetValue > 0) {
- progress = Math.min(100, (currentValue / goal.targetValue) * 100)
- }
-
- await this.db.update(fitnessGoals)
- .set({ currentValue, progress, updatedAt: new Date() })
- .where(eq(fitnessGoals.id, id))
- .run()
-
- return this.getFitnessGoalById(id)
- }
-
- async completeGoal(id: string): Promise {
- const now = new Date()
- await this.db.update(fitnessGoals)
- .set({ status: 'completed', progress: 100, completedDate: now, updatedAt: now })
- .where(eq(fitnessGoals.id, id))
- .run()
-
- return this.getFitnessGoalById(id)
- }
-
- async getDashboardStats(): Promise<{ totalUsers: number; activeClients: number; totalRevenue: number; revenueGrowth: number }> {
- // Placeholder implementation as per original sqlite.ts (which didn't implement this either in the viewed snippet,
- // but interface requires it. I'll provide a basic implementation or mock).
- // The original sqlite.ts snippet ended before showing this method, but the interface has it.
- // I'll implement a basic count.
-
- const allUsers = await this.db.select().from(users).all()
- const activeClients = await this.db.select().from(clients).where(eq(clients.membershipStatus, 'active')).all()
-
- return {
- totalUsers: allUsers.length,
- activeClients: activeClients.length,
- totalRevenue: 0, // Not tracking payments yet
- revenueGrowth: 0
- }
- }
-
- // Mappers
- private mapUser(row: any): User {
- return {
- ...row,
- createdAt: new Date(row.createdAt),
- updatedAt: new Date(row.updatedAt)
- }
- }
-
- private mapClient(row: any): Client {
- return {
- ...row,
- joinDate: new Date(row.joinDate),
- lastVisit: row.lastVisit ? new Date(row.lastVisit) : undefined
- }
- }
-
- private mapFitnessProfile(row: any): FitnessProfile {
- return {
- ...row,
- createdAt: new Date(row.createdAt),
- updatedAt: new Date(row.updatedAt)
- }
- }
-
- private mapAttendance(row: any): Attendance {
- return {
- ...row,
- checkInTime: new Date(row.checkInTime),
- checkOutTime: row.checkOutTime ? new Date(row.checkOutTime) : undefined,
- createdAt: new Date(row.createdAt)
- }
- }
-
- private mapRecommendation(row: any): Recommendation {
- return {
- ...row,
- createdAt: new Date(row.createdAt),
- approvedAt: row.approvedAt ? new Date(row.approvedAt) : undefined
- }
- }
-
- private mapFitnessGoal(row: any): FitnessGoal {
- return {
- ...row,
- startDate: new Date(row.startDate),
- targetDate: row.targetDate ? new Date(row.targetDate) : undefined,
- completedDate: row.completedDate ? new Date(row.completedDate) : undefined,
- createdAt: new Date(row.createdAt),
- updatedAt: new Date(row.updatedAt)
- }
- }
+ await this.db
+ .update(fitnessGoals)
+ .set({ currentValue, progress, updatedAt: new Date() })
+ .where(eq(fitnessGoals.id, id))
+ .run();
+
+ return this.getFitnessGoalById(id);
+ }
+
+ async completeGoal(id: string): Promise {
+ const now = new Date();
+ await this.db
+ .update(fitnessGoals)
+ .set({
+ status: "completed",
+ progress: 100,
+ completedDate: now,
+ updatedAt: now,
+ })
+ .where(eq(fitnessGoals.id, id))
+ .run();
+
+ return this.getFitnessGoalById(id);
+ }
+
+ async getDashboardStats(): Promise<{
+ totalUsers: number;
+ activeClients: number;
+ totalRevenue: number;
+ revenueGrowth: number;
+ }> {
+ // Placeholder implementation as per original sqlite.ts (which didn't implement this either in the viewed snippet,
+ // but interface requires it. I'll provide a basic implementation or mock).
+ // The original sqlite.ts snippet ended before showing this method, but the interface has it.
+ // I'll implement a basic count.
+
+ const allUsers = await this.db.select().from(users).all();
+ const activeClients = await this.db
+ .select()
+ .from(clients)
+ .where(eq(clients.membershipStatus, "active"))
+ .all();
+
+ return {
+ totalUsers: allUsers.length,
+ activeClients: activeClients.length,
+ totalRevenue: 0, // Not tracking payments yet
+ revenueGrowth: 0,
+ };
+ }
+
+ // Mappers
+ private mapUser(row: any): User {
+ return {
+ ...row,
+ gymId: (row as any).gymId ?? (row as any).gym_id ?? undefined,
+ createdAt: new Date(row.createdAt),
+ updatedAt: new Date(row.updatedAt),
+ };
+ }
+
+ private mapClient(row: any): Client {
+ return {
+ ...row,
+ joinDate: new Date(row.joinDate),
+ lastVisit: row.lastVisit ? new Date(row.lastVisit) : undefined,
+ };
+ }
+
+ private mapFitnessProfile(row: any): FitnessProfile {
+ return {
+ ...row,
+ createdAt: new Date(row.createdAt),
+ updatedAt: new Date(row.updatedAt),
+ };
+ }
+
+ private mapAttendance(row: any): Attendance {
+ return {
+ ...row,
+ checkInTime: new Date(row.checkInTime),
+ checkOutTime: row.checkOutTime ? new Date(row.checkOutTime) : undefined,
+ createdAt: new Date(row.createdAt),
+ };
+ }
+
+ private mapRecommendation(row: any): Recommendation {
+ return {
+ ...row,
+ createdAt: new Date(row.createdAt),
+ approvedAt: row.approvedAt ? new Date(row.approvedAt) : undefined,
+ };
+ }
+
+ private mapFitnessGoal(row: any): FitnessGoal {
+ return {
+ ...row,
+ startDate: new Date(row.startDate),
+ targetDate: row.targetDate ? new Date(row.targetDate) : undefined,
+ completedDate: row.completedDate
+ ? new Date(row.completedDate)
+ : undefined,
+ createdAt: new Date(row.createdAt),
+ updatedAt: new Date(row.updatedAt),
+ };
+ }
}
diff --git a/apps/mobile/src/config/api.ts b/apps/mobile/src/config/api.ts
index ca38de0..da96e2b 100644
--- a/apps/mobile/src/config/api.ts
+++ b/apps/mobile/src/config/api.ts
@@ -1,5 +1,5 @@
export const API_BASE_URL = __DEV__
- ? "https://e0877d294c41.ngrok-free.app"
+ ? "https://a4db649a0973.ngrok-free.app"
: "https://your-production-url.com";
export const API_ENDPOINTS = {
diff --git a/packages/database/src/index.ts b/packages/database/src/index.ts
index 81cb320..a78284e 100644
--- a/packages/database/src/index.ts
+++ b/packages/database/src/index.ts
@@ -1,15 +1,12 @@
-import Database from 'better-sqlite3'
-import { drizzle } from 'drizzle-orm/better-sqlite3'
-import * as schema from './schema'
+import Database from "better-sqlite3";
+import { drizzle } from "drizzle-orm/better-sqlite3";
+import * as schema from "./schema";
// Configurable database path with intelligent defaults
-const dbPath = process.env.DATABASE_URL ||
- (process.env.NODE_ENV === 'production'
- ? './data/fitai.db'
- : '../../apps/admin/data/fitai.db')
+const dbPath = "./data/fitai.db";
-const sqlite = new Database(dbPath)
-export const db = drizzle(sqlite, { schema })
+const sqlite = new Database(dbPath);
+export const db = drizzle(sqlite, { schema });
-export * from './schema'
-export { eq, and, or, desc, asc, sql } from 'drizzle-orm'
\ No newline at end of file
+export * from "./schema";
+export { eq, and, or, desc, asc, sql } from "drizzle-orm";