diff --git a/apps/api/drizzle.config.ts b/apps/api/drizzle.config.ts new file mode 100644 index 0000000..45a3f9e --- /dev/null +++ b/apps/api/drizzle.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/db/schema.ts', + out: './drizzle', + dialect: 'postgresql', + dbCredentials: { + url: process.env.DATABASE_URL ?? 'postgres://postgres:postgres@localhost:5432/zeavis_edu', + }, +}); diff --git a/apps/api/moon.yml b/apps/api/moon.yml new file mode 100644 index 0000000..91b9bd6 --- /dev/null +++ b/apps/api/moon.yml @@ -0,0 +1,23 @@ +type: application +language: typescript + +tasks: + dev: + command: bun run dev + local: true + build: + command: bun build src/index.ts --outdir dist --target bun + inputs: + - src/**/* + - package.json + - tsconfig.json + - drizzle.config.ts + outputs: + - dist + typecheck: + command: bun run typecheck + inputs: + - src/**/* + - package.json + - tsconfig.json + - drizzle.config.ts diff --git a/apps/api/package.json b/apps/api/package.json new file mode 100644 index 0000000..9229a2d --- /dev/null +++ b/apps/api/package.json @@ -0,0 +1,23 @@ +{ + "name": "@zeavis/api", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "bun --watch src/index.ts", + "start": "bun src/index.ts", + "typecheck": "tsc --project tsconfig.json", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate" + }, + "dependencies": { + "@zeavis/shared": "workspace:*", + "drizzle-orm": "^0.36.4", + "elysia": "^1.1.25", + "postgres": "^3.4.5" + }, + "devDependencies": { + "drizzle-kit": "^0.27.1", + "typescript": "^5.6.3" + } +} diff --git a/apps/api/src/config/env.ts b/apps/api/src/config/env.ts new file mode 100644 index 0000000..a54a31c --- /dev/null +++ b/apps/api/src/config/env.ts @@ -0,0 +1,4 @@ +export const env = { + port: Number(Bun.env.API_PORT ?? 3000), + databaseUrl: Bun.env.DATABASE_URL, +}; diff --git a/apps/api/src/db/client.ts b/apps/api/src/db/client.ts new file mode 100644 index 0000000..5c2c11b --- /dev/null +++ b/apps/api/src/db/client.ts @@ -0,0 +1,13 @@ +import { drizzle } from 'drizzle-orm/postgres-js'; +import postgres from 'postgres'; +import { env } from '../config/env'; +import * as schema from './schema'; + +export function createDbClient() { + if (!env.databaseUrl) { + throw new Error('DATABASE_URL is required to create a database client'); + } + + const client = postgres(env.databaseUrl); + return drizzle(client, { schema }); +} diff --git a/apps/api/src/db/schema.ts b/apps/api/src/db/schema.ts new file mode 100644 index 0000000..d3ff328 --- /dev/null +++ b/apps/api/src/db/schema.ts @@ -0,0 +1,7 @@ +import { pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; + +export const appEvents = pgTable('app_events', { + id: uuid('id').primaryKey().defaultRandom(), + name: varchar('name', { length: 120 }).notNull(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts new file mode 100644 index 0000000..9add3f1 --- /dev/null +++ b/apps/api/src/index.ts @@ -0,0 +1,10 @@ +import { Elysia } from 'elysia'; +import { env } from './config/env'; +import { healthRoutes } from './routes/health'; +import { statusRoutes } from './routes/status'; + +const app = new Elysia().use(healthRoutes).use(statusRoutes).listen(env.port); + +console.log(`ZeaVis Edu API running at http://${app.server?.hostname}:${app.server?.port}`); + +export type App = typeof app; diff --git a/apps/api/src/routes/health.ts b/apps/api/src/routes/health.ts new file mode 100644 index 0000000..87eb2ce --- /dev/null +++ b/apps/api/src/routes/health.ts @@ -0,0 +1,5 @@ +import { Elysia } from 'elysia'; + +export const healthRoutes = new Elysia().get('/health', () => ({ + status: 'ok' as const, +})); diff --git a/apps/api/src/routes/status.ts b/apps/api/src/routes/status.ts new file mode 100644 index 0000000..681050c --- /dev/null +++ b/apps/api/src/routes/status.ts @@ -0,0 +1,6 @@ +import { createAppStatus } from '@zeavis/shared'; +import { Elysia } from 'elysia'; + +export const statusRoutes = new Elysia({ prefix: '/api/v1' }).get('/status', () => + createAppStatus(), +); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json new file mode 100644 index 0000000..5e8ac20 --- /dev/null +++ b/apps/api/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["ES2022"], + "types": ["bun"], + "noEmit": true + }, + "include": ["src", "drizzle.config.ts"] +}