diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..0e378c1 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,51 @@ +name: Deploy to Vercel + +on: + push: + branches: [main] + release: + types: [published] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: latest + + - name: Install dependencies + run: | + pnpm install --frozen-lockfile + cd backend && pnpm install + cd ../frontend && pnpm install + + - name: Build backend + run: | + cd backend + pnpm prisma:generate + pnpm build + + - name: Build frontend + run: | + cd frontend + pnpm build + + - name: Deploy to Vercel + uses: amondnet/vercel-action@v25 + with: + vercel-token: ${{ secrets.VERCEL_TOKEN }} + vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} + vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} + vercel-args: '--prod' + working-directory: ./ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3c3629e..81e83fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.vercel diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 0000000..a0b9f1c --- /dev/null +++ b/.vercelignore @@ -0,0 +1,13 @@ +node_modules +.env +.env.local +.env.*.local +.git +.gitignore +README.md +docker-compose.yml +backend/dist +backend/node_modules +frontend/node_modules +frontend/.next +*.log \ No newline at end of file diff --git a/TASK.md b/TASK.md new file mode 100644 index 0000000..2285ef4 --- /dev/null +++ b/TASK.md @@ -0,0 +1,31 @@ +Тестове завдання: Fullstack Developer +Завдання +Реалізувати простий застосунок «Міні-блог з авторизацією». +Функціонал + Фронтенд (Next.js + TypeScript): + Сторінка реєстрації / входу (email + пароль). + Сторінка зі списком постів (назва + короткий опис). + Сторінка одного поста (заголовок, текст, дата створення). + Сторінка створення нового поста (доступна тільки після авторизації). + Простий дизайн (Tailwind та будь-яку UI-бібліотеку). + -застосувати охайні базові стилі (TailwindCSS чи інша UI-бібліотека); + Сторінка редагування інформації про користувача (ім’я, email, пароль). + +Бекенд (Express.js + TypeScript): +Авторизація (JWT або сесії): + POST /auth/register — реєстрація. + POST /auth/login — вхід. + + API для постів: + GET /posts — отримати всі пости. + GET /posts/:id — отримати конкретний пост. + POST /posts — створити новий пост (тільки авторизований користувач). + + API для користувачів: + GET /users/me — отримати інформацію про поточного авторизованого користувача. + PUT /users/me — оновити інформацію (ім’я, email, пароль). + + (опціонально) DELETE /users/me — видалити свій акаунт. +Зберігання даних: +Використати PostgreSQL як базу даних. +Роботу з БД реалізувати через Prisma. diff --git a/VERCEL_SETUP.md b/VERCEL_SETUP.md new file mode 100644 index 0000000..ff25aaf --- /dev/null +++ b/VERCEL_SETUP.md @@ -0,0 +1,101 @@ +# Vercel Deployment Setup + +## 🚀 Deployment Steps + +### 1. Environment Variables + +Add these to your Vercel Dashboard (`Settings` → `Environment Variables`): + +```bash +# Production Database +DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require" + +# JWT Secret (generate strong secret) +JWT_SECRET="your-super-secret-jwt-key-256-bit" + +# Node Environment +NODE_ENV="production" + +# CORS Origins (your frontend domain) +CORS_ORIGINS="https://your-project.vercel.app" +``` + +### 2. Database Options + +#### Option A: Vercel Postgres (Recommended) +```bash +# Install Vercel Postgres +vercel storage create postgres + +# Copy connection string to env vars +``` + +#### Option B: Railway +```bash +# 1. Create account at railway.app +# 2. Create PostgreSQL database +# 3. Copy connection string +``` + +#### Option C: Supabase +```bash +# 1. Create project at supabase.com +# 2. Go to Settings → Database +# 3. Copy connection string +``` + +### 3. Deploy Commands + +```bash +# Connect to Vercel +vercel login + +# Link project +vercel link + +# Deploy +vercel --prod +``` + +### 4. After Deployment + +1. **Run migrations**: + ```bash + # In Vercel Functions tab, run: + npx prisma migrate deploy + ``` + +2. **Test API**: + ```bash + curl https://your-project.vercel.app/api/health + ``` + +## 🔧 Project Structure + +``` +├── vercel.json # Vercel configuration +├── .vercelignore # Files to ignore +├── backend/ +│ ├── api/index.ts # Vercel Function entry +│ ├── .env.production # Production env template +│ └── prisma/ +│ └── migrate-prod.ts # Production migrations +└── frontend/ # Next.js app +``` + +## 📝 Manual Setup Steps + +1. **Create Vercel project** +2. **Add environment variables** (see above) +3. **Choose database provider** +4. **Deploy**: `vercel --prod` +5. **Run migrations** in Vercel dashboard +6. **Test endpoints** + +## 🚨 Important Notes + +- **Never commit** real secrets to git +- **Use strong JWT secret** (256-bit recommended) +- **Enable SSL** for production database +- **Set CORS origins** correctly +- **Test thoroughly** before production use \ No newline at end of file diff --git a/backend/api/index.ts b/backend/api/index.ts new file mode 100644 index 0000000..23dc9e2 --- /dev/null +++ b/backend/api/index.ts @@ -0,0 +1,6 @@ +import { VercelRequest, VercelResponse } from '@vercel/node'; +import app from '../src/app'; + +export default function handler(req: VercelRequest, res: VercelResponse) { + return app(req, res); +} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 857edc7..2f781be 100644 --- a/backend/package.json +++ b/backend/package.json @@ -11,7 +11,9 @@ "db:down": "docker compose down", "prisma:generate": "prisma generate", "prisma:migrate": "prisma migrate dev", + "prisma:migrate:prod": "ts-node prisma/migrate-prod.ts", "prisma:studio": "prisma studio", + "vercel-build": "pnpm prisma:generate && pnpm build", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], @@ -19,6 +21,8 @@ "license": "ISC", "packageManager": "pnpm@10.8.0", "dependencies": { + "@prisma/client": "^6.16.1", + "@vercel/node": "^3.0.31", "cors": "^2.8.5", "dotenv": "^17.2.2", "express": "^5.1.0", @@ -26,7 +30,6 @@ "morgan": "^1.10.1" }, "devDependencies": { - "@prisma/client": "^6.16.1", "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/morgan": "^1.9.10", diff --git a/backend/prisma/migrate-prod.ts b/backend/prisma/migrate-prod.ts new file mode 100644 index 0000000..e442b80 --- /dev/null +++ b/backend/prisma/migrate-prod.ts @@ -0,0 +1,22 @@ +// Production migration script for Vercel +import { execSync } from 'child_process'; + +export default async function migrateProd() { + try { + // Generate Prisma client + execSync('npx prisma generate', { stdio: 'inherit' }); + + // Run migrations + execSync('npx prisma migrate deploy', { stdio: 'inherit' }); + + console.log('✅ Production migrations completed'); + } catch (error) { + console.error('❌ Migration failed:', error); + process.exit(1); + } +} + +// Run if called directly +if (require.main === module) { + migrateProd(); +} \ No newline at end of file diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..1a3e018 --- /dev/null +++ b/vercel.json @@ -0,0 +1,34 @@ +{ + "version": 2, + "builds": [ + { + "src": "frontend/package.json", + "use": "@vercel/next" + }, + { + "src": "backend/src/**/*.ts", + "use": "@vercel/node", + "config": { + "includeFiles": ["backend/prisma/**"] + } + } + ], + "routes": [ + { + "src": "/api/(.*)", + "dest": "backend/src/server.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