basic stracture and auth

in memory db :)
This commit is contained in:
dimitar committed 2025-11-07 20:59:56 +01:00
commit 3a554ba434
71 files changed
+28535

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
import { defineConfig } from 'drizzle-kit'
export default defineConfig({
schema: './src/schema.ts',
out: './drizzle',
driver: 'better-sqlite',
dbCredentials: {
url: './fitai.db',
},
})
+22
View File
@@ -0,0 +1,22 @@
{
"name": "@fitai/database",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"typecheck": "tsc --noEmit",
"db:push": "drizzle-kit push:sqlite",
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"drizzle-orm": "^0.29.0",
"better-sqlite3": "^9.0.0",
"@types/better-sqlite3": "^7.6.0"
},
"devDependencies": {
"typescript": "^5.0.0",
"drizzle-kit": "^0.20.0"
}
}
+8
View File
@@ -0,0 +1,8 @@
import Database from 'better-sqlite3'
import { drizzle } from 'drizzle-orm/better-sqlite3'
import * as schema from './schema'
const sqlite = new Database('./fitai.db')
export const db = drizzle(sqlite, { schema })
export * from './schema'
+72
View File
@@ -0,0 +1,72 @@
import { sqliteTable, text, integer, real } from 'drizzle-orm/sqlite-core'
export const users = sqliteTable('users', {
id: text('id').primaryKey(),
email: text('email').notNull().unique(),
firstName: text('first_name').notNull(),
lastName: text('last_name').notNull(),
password: text('password').notNull(),
role: text('role', { enum: ['admin', 'trainer', 'client'] }).notNull().default('client'),
phone: text('phone'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
})
export const clients = sqliteTable('clients', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
membershipType: text('membership_type', { enum: ['basic', 'premium', 'vip'] }).notNull().default('basic'),
membershipStatus: text('membership_status', { enum: ['active', 'inactive', 'suspended'] }).notNull().default('active'),
joinDate: integer('join_date', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
lastVisit: integer('last_visit', { mode: 'timestamp' }),
emergencyContactName: text('emergency_contact_name'),
emergencyContactPhone: text('emergency_contact_phone'),
emergencyContactRelationship: text('emergency_contact_relationship'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
})
export const payments = sqliteTable('payments', {
id: text('id').primaryKey(),
clientId: text('client_id').notNull().references(() => clients.id, { onDelete: 'cascade' }),
amount: real('amount').notNull(),
currency: text('currency').notNull().default('USD'),
status: text('status', { enum: ['pending', 'completed', 'failed', 'refunded'] }).notNull().default('pending'),
paymentMethod: text('payment_method', { enum: ['cash', 'card', 'bank_transfer'] }).notNull(),
dueDate: integer('due_date', { mode: 'timestamp' }).notNull(),
paidAt: integer('paid_at', { mode: 'timestamp' }),
description: text('description').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
})
export const attendance = sqliteTable('attendance', {
id: text('id').primaryKey(),
clientId: text('client_id').notNull().references(() => clients.id, { onDelete: 'cascade' }),
checkInTime: integer('check_in_time', { mode: 'timestamp' }).notNull(),
checkOutTime: integer('check_out_time', { mode: 'timestamp' }),
type: text('type', { enum: ['gym', 'class', 'personal_training'] }).notNull().default('gym'),
notes: text('notes'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
})
export const notifications = sqliteTable('notifications', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
title: text('title').notNull(),
message: text('message').notNull(),
type: text('type', { enum: ['payment_reminder', 'attendance', 'promotion', 'system'] }).notNull(),
read: integer('read', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
})
export type User = typeof users.$inferSelect
export type NewUser = typeof users.$inferInsert
export type Client = typeof clients.$inferSelect
export type NewClient = typeof clients.$inferInsert
export type Payment = typeof payments.$inferSelect
export type NewPayment = typeof payments.$inferInsert
export type Attendance = typeof attendance.$inferSelect
export type NewAttendance = typeof attendance.$inferInsert
export type Notification = typeof notifications.$inferSelect
export type NewNotification = typeof notifications.$inferInsert
+19
View File
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"lib": ["es2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
+17
View File
@@ -0,0 +1,17 @@
{
"name": "@fitai/shared",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"zod": "^3.22.0"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
+3
View File
@@ -0,0 +1,3 @@
export * from './types'
export * from './schemas'
export * from './utils'
+46
View File
@@ -0,0 +1,46 @@
import { z } from 'zod'
export const UserSchema = z.object({
id: z.string(),
email: z.string().email(),
firstName: z.string().min(1),
lastName: z.string().min(1),
role: z.enum(['admin', 'trainer', 'client']),
createdAt: z.date(),
updatedAt: z.date(),
})
export const ClientSchema = z.object({
id: z.string(),
userId: z.string(),
membershipType: z.enum(['basic', 'premium', 'vip']),
membershipStatus: z.enum(['active', 'inactive', 'suspended']),
joinDate: z.date(),
lastVisit: z.date().optional(),
emergencyContact: z.object({
name: z.string(),
phone: z.string(),
relationship: z.string(),
}),
})
export const PaymentSchema = z.object({
id: z.string(),
clientId: z.string(),
amount: z.number().positive(),
currency: z.string(),
status: z.enum(['pending', 'completed', 'failed', 'refunded']),
paymentMethod: z.enum(['cash', 'card', 'bank_transfer']),
dueDate: z.date(),
paidAt: z.date().optional(),
description: z.string(),
})
export const AttendanceSchema = z.object({
id: z.string(),
clientId: z.string(),
checkInTime: z.date(),
checkOutTime: z.date().optional(),
type: z.enum(['gym', 'class', 'personal_training']),
notes: z.string().optional(),
})
+57
View File
@@ -0,0 +1,57 @@
export interface User {
id: string
email: string
firstName: string
lastName: string
role: 'admin' | 'trainer' | 'client'
createdAt: Date
updatedAt: Date
}
export interface Client {
id: string
userId: string
user: User
membershipType: 'basic' | 'premium' | 'vip'
membershipStatus: 'active' | 'inactive' | 'suspended'
joinDate: Date
lastVisit?: Date
emergencyContact: {
name: string
phone: string
relationship: string
}
}
export interface Payment {
id: string
clientId: string
client: Client
amount: number
currency: string
status: 'pending' | 'completed' | 'failed' | 'refunded'
paymentMethod: 'cash' | 'card' | 'bank_transfer'
dueDate: Date
paidAt?: Date
description: string
}
export interface Attendance {
id: string
clientId: string
client: Client
checkInTime: Date
checkOutTime?: Date
type: 'gym' | 'class' | 'personal_training'
notes?: string
}
export interface Notification {
id: string
userId: string
title: string
message: string
type: 'payment_reminder' | 'attendance' | 'promotion' | 'system'
read: boolean
createdAt: Date
}
+26
View File
@@ -0,0 +1,26 @@
export const formatDate = (date: Date): string => {
return new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
}).format(date)
}
export const formatCurrency = (
amount: number,
currency: string = 'USD'
): string => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount)
}
export const calculateDaysBetween = (startDate: Date, endDate: Date): number => {
const timeDiff = endDate.getTime() - startDate.getTime()
return Math.ceil(timeDiff / (1000 * 3600 * 24))
}
export const generateId = (): string => {
return Math.random().toString(36).substr(2, 9)
}
+19
View File
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"lib": ["es2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}