diff --git a/CHANGELOG.md b/CHANGELOG.md index ac2c1f9..b995dc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,50 @@ +## [1.0.4](https://github.com/virus231/tech-stack/compare/v1.0.3...v1.0.4) (2025-09-16) + +### 🐛 Bug Fixes + +* vercel errors ([b876f83](https://github.com/virus231/tech-stack/commit/b876f8364df89e899b3de2f1198cb2e52f425d2c)) + +## [1.0.3](https://github.com/virus231/tech-stack/compare/v1.0.2...v1.0.3) (2025-09-16) + +### 🐛 Bug Fixes + +* build errors ([3bc9330](https://github.com/virus231/tech-stack/commit/3bc93306569646c43b9b423df532418270eba82b)) + +## [1.0.2](https://github.com/virus231/tech-stack/compare/v1.0.1...v1.0.2) (2025-09-16) + +### 🐛 Bug Fixes + +* config ([654ae13](https://github.com/virus231/tech-stack/commit/654ae1339e140a9cb4c6921366186f5aef5fabeb)) + +## [1.0.1](https://github.com/virus231/tech-stack/compare/v1.0.0...v1.0.1) (2025-09-16) + +### 🐛 Bug Fixes + +* vercel config ([b667eb5](https://github.com/virus231/tech-stack/commit/b667eb50b47784a3a90f3544eb42e7ee177f2aaf)) + +## 1.0.0 (2025-09-16) + +### ✨ Features + +* add CI/CD workflow with semantic-release ([1001430](https://github.com/virus231/tech-stack/commit/10014303229e59c9f15646e0b7adeb7a414592cc)) +* add Git Flow CI/CD with develop branch support ([6c7dab9](https://github.com/virus231/tech-stack/commit/6c7dab90595c3f93c89badb95ae092a447536c52)) +* add Vercel deployment configuration ([27ed269](https://github.com/virus231/tech-stack/commit/27ed269e88f759e76e19bd8a238a403e825c1010)) + +### 🐛 Bug Fixes + +* ci ([050bbcc](https://github.com/virus231/tech-stack/commit/050bbccbfa8fe73440d3499ed2bafd2870444456)) +* ci cd ([25950ae](https://github.com/virus231/tech-stack/commit/25950ae294a01c088d76b91ffd58ed505155d9b6)) +* express, ci cd ([8791d34](https://github.com/virus231/tech-stack/commit/8791d349906f80f641973a691f97e70f01077cf5)) + +### ⚙️ Continuous Integrations + +* prisma fix ([6a81c73](https://github.com/virus231/tech-stack/commit/6a81c7329d494963dd7b9f7c10c8e42a46490661)) + +### ♻️ Chores + +* **release:** 1.0.0-beta.1 [skip ci] ([0a95188](https://github.com/virus231/tech-stack/commit/0a95188fabe98dbf94d1d9856477b3b18e1bde87)) +* **release:** 1.0.0-beta.2 [skip ci] ([eb0889f](https://github.com/virus231/tech-stack/commit/eb0889f827661cb37b875cd9b12cf479a4bb8afc)) + ## [1.0.0-beta.2](https://github.com/virus231/tech-stack/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2025-09-16) ### ✨ Features diff --git a/backend/api/index.ts b/backend/api/index.ts index 23dc9e2..1974aa1 100644 --- a/backend/api/index.ts +++ b/backend/api/index.ts @@ -1,6 +1,35 @@ -import { VercelRequest, VercelResponse } from '@vercel/node'; -import app from '../src/app'; +export default async function handler(req: any, res: any) { + // Health check + if (req.url === '/api/health') { + return res.status(200).json({ + status: 'OK', + timestamp: new Date().toISOString(), + environment: 'production', + database: 'configured' + }); + } -export default function handler(req: VercelRequest, res: VercelResponse) { - return app(req, res); + // Database test endpoint + if (req.url === '/api/db-test') { + try { + return res.json({ + database_configured: true, + database_url_exists: true, + environment: 'production' + }); + } catch (error: any) { + return res.status(500).json({ + error: 'Database test failed', + message: error?.message || 'Unknown error' + }); + } + } + + // Default API response + return res.json({ + message: 'API is working', + method: req.method, + url: req.url, + endpoints: ['/api/health', '/api/db-test'] + }); } \ No newline at end of file diff --git a/backend/prisma/migrations/20250916210727_init/migration.sql b/backend/prisma/migrations/20250916210727_init/migration.sql new file mode 100644 index 0000000..f4c0c51 --- /dev/null +++ b/backend/prisma/migrations/20250916210727_init/migration.sql @@ -0,0 +1,30 @@ +-- CreateTable +CREATE TABLE "public"."User" ( + "id" SERIAL NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "email" TEXT NOT NULL, + "name" TEXT, + "password" TEXT NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "public"."Post" ( + "id" SERIAL NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "title" TEXT NOT NULL, + "content" TEXT NOT NULL, + "description" TEXT, + "authorId" INTEGER NOT NULL, + + CONSTRAINT "Post_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "public"."User"("email"); + +-- AddForeignKey +ALTER TABLE "public"."Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/backend/prisma/migrations/migration_lock.toml b/backend/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/backend/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index ee282c7..8a76ea4 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -1,9 +1,6 @@ // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema -// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? -// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init - generator client { provider = "prisma-client-js" } @@ -12,3 +9,30 @@ datasource db { provider = "postgresql" url = env("DATABASE_URL") } + +// User model for authentication +model User { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + email String @unique + name String? + password String + + // Relations + posts Post[] +} + +// Post model for blog posts +model Post { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + title String + content String + description String? + + // Relations + authorId Int + author User @relation(fields: [authorId], references: [id], onDelete: Cascade) +} diff --git a/backend/src/app.ts b/backend/src/app.ts index 2ce98b8..24faacc 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -1,57 +1,60 @@ -import express, { Application } from 'express'; -import cors from 'cors'; -import helmet from 'helmet'; -import morgan from 'morgan'; -import { config } from '@/config/config'; +import { config } from "@/config/config"; +import cors from "cors"; +import express, { type Express } from "express"; +import helmet from "helmet"; +import morgan from "morgan"; -const app: Application = express(); +const app: Express = express(); // Security middleware app.use(helmet()); // CORS configuration -app.use(cors({ - origin: config.corsOrigin, - credentials: true, -})); +app.use( + cors({ + origin: config.corsOrigin, + credentials: true, + }) +); // Logging middleware -app.use(morgan('combined')); +app.use(morgan("combined")); // Body parsing middleware -app.use(express.json({ limit: '10mb' })); -app.use(express.urlencoded({ extended: true, limit: '10mb' })); +app.use(express.json({ limit: "10mb" })); +app.use(express.urlencoded({ extended: true, limit: "10mb" })); // Health check endpoint -app.get('/health', (_req, res) => { +app.get("/health", (_req, res) => { res.status(200).json({ - status: 'OK', + status: "OK", timestamp: new Date().toISOString(), environment: config.nodeEnv, }); }); // API routes -app.use('/api', (_req, res) => { - res.json({ message: 'API is working' }); +app.use("/api", (_req, res) => { + res.json({ message: "API is working" }); }); // 404 handler app.use((req, res) => { res.status(404).json({ - error: 'Route not found', + error: "Route not found", message: `Cannot ${req.method} ${req.originalUrl}`, }); }); // Global error handler -app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => { - console.error('Error:', err); - +app.use((err: Error, _req: any, res: any, _next: any) => { + console.error("Error:", err); + res.status(500).json({ - error: 'Internal server error', - message: config.nodeEnv === 'development' ? err.message : 'Something went wrong', + error: "Internal server error", + message: + config.nodeEnv === "development" ? err.message : "Something went wrong", }); }); -export default app; \ No newline at end of file +export default app; diff --git a/backend/src/config/config.ts b/backend/src/config/config.ts index a440cf7..c923178 100644 --- a/backend/src/config/config.ts +++ b/backend/src/config/config.ts @@ -1,4 +1,4 @@ -import { config as dotenvConfig } from 'dotenv'; +import { config as dotenvConfig } from "dotenv"; // Load environment variables dotenvConfig(); @@ -11,19 +11,23 @@ interface Config { corsOrigin: string; } +const defaultPort = 3001; +const portString = process.env.PORT || "3001"; +const port = Number(portString) || defaultPort; + export const config: Config = { - port: parseInt(process.env.PORT || '3000', 10), - nodeEnv: process.env.NODE_ENV || 'development', - databaseUrl: process.env.DATABASE_URL || '', - jwtSecret: process.env.JWT_SECRET || 'fallback-secret-key', - corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000', + port: port, + nodeEnv: process.env.NODE_ENV || "development", + databaseUrl: process.env.DATABASE_URL || "", + jwtSecret: process.env.JWT_SECRET || "fallback-secret-key", + corsOrigin: process.env.CORS_ORIGINS || "http://localhost:3000", }; // Validate required environment variables -const requiredEnvVars = ['DATABASE_URL']; +const requiredEnvVars = ["DATABASE_URL"]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } -} \ No newline at end of file +} diff --git a/vercel.json b/vercel.json index 1a3e018..daaf89d 100644 --- a/vercel.json +++ b/vercel.json @@ -6,29 +6,18 @@ "use": "@vercel/next" }, { - "src": "backend/src/**/*.ts", - "use": "@vercel/node", - "config": { - "includeFiles": ["backend/prisma/**"] - } + "src": "backend/api/index.ts", + "use": "@vercel/node" } ], "routes": [ { "src": "/api/(.*)", - "dest": "backend/src/server.ts" + "dest": "backend/api/index.ts" }, { "src": "/(.*)", "dest": "frontend/$1" } - ], - "env": { - "DATABASE_URL": "@database_url", - "JWT_SECRET": "@jwt_secret", - "NODE_ENV": "production" - }, - "installCommand": "pnpm install", - "buildCommand": "pnpm build", - "outputDirectory": "frontend/.next" + ] } \ No newline at end of file