feat: move to monorepo

This commit is contained in:
Oleg Proskurin 2025-09-29 21:47:21 +07:00
parent 3c922c861b
commit babcbe29db
48 changed files with 4116 additions and 259 deletions

4
.gitignore vendored
View File

@ -9,6 +9,9 @@ pnpm-debug.log*
dist/ dist/
build/ build/
*.tsbuildinfo *.tsbuildinfo
apps/*/dist/
apps/*/.next/
.next/
# Environment files # Environment files
.env .env
@ -35,6 +38,7 @@ Thumbs.db
# Logs # Logs
logs/ logs/
apps/*/logs/
*.log *.log
# Runtime data # Runtime data

289
README.md
View File

@ -1,92 +1,142 @@
# Banatie - Nano Banana Image Generation Service # Banatie - AI Image Generation Service
A REST API service for AI-powered image generation using the Gemini Flash Image model. Banatie provides a simple HTTP interface for generating high-quality images from text prompts with optional reference images. A comprehensive monorepo for the Banatie AI image generation platform, featuring multiple applications for different use cases.
## 🚀 Quick Start ## Architecture Overview
```
banatie-service/
├── apps/
│ ├── api-service/ # REST API for image generation (Express.js + TypeScript)
│ ├── landing/ # Landing page with demo (Next.js)
│ ├── studio/ # SaaS platform with billing (Next.js + Supabase + Stripe)
│ └── admin/ # Administration dashboard (Next.js)
├── data/ # Docker volumes (postgres, minio)
├── docker-compose.yml # Infrastructure services
└── package.json # Workspace scripts
```
## Applications
### 🚀 API Service (`apps/api-service`)
- **Port**: 3000
- **Tech**: Express.js, TypeScript, Gemini AI
- **Purpose**: Core REST API for AI image generation
- **Features**: Image generation, file upload, rate limiting, logging
### 🌐 Landing Page (`apps/landing`)
- **Port**: 3001
- **Tech**: Next.js 14, Tailwind CSS
- **Purpose**: Public landing page with demo
- **Features**: Service overview, image generation demo
### 🏢 Studio (`apps/studio`)
- **Port**: 3002
- **Tech**: Next.js 14, Supabase, Stripe
- **Purpose**: SaaS platform for paid users
- **Features**: Authentication, billing, subscriptions, usage tracking
### 🔧 Admin (`apps/admin`)
- **Port**: 3003
- **Tech**: Next.js 14, Dashboard components
- **Purpose**: Service administration and monitoring
- **Features**: System monitoring, user management, analytics
## Quick Start
### Prerequisites ### Prerequisites
- Node.js >= 18.0.0 - Node.js >= 18.0.0
- pnpm >= 8.0.0 - pnpm >= 8.0.0
- Gemini API key from [Google AI Studio](https://aistudio.google.com/) - Docker & Docker Compose
### Installation ### Development Setup
```bash ```bash
# Clone the repository # Clone and install dependencies
git clone <repository-url> git clone <repository-url>
cd banatie cd banatie-service
# Install dependencies
pnpm install pnpm install
# Setup environment variables # Start infrastructure (PostgreSQL + MinIO)
cp .env.example .env docker compose up -d postgres minio storage-init
# Edit .env with your Gemini API key
```
### Development # Start all applications in development mode
```bash
# Start development server with auto-reload
pnpm dev pnpm dev
# Start production server # Or start individual apps
pnpm start pnpm dev:api # API Service on :3000
pnpm dev:landing # Landing Page on :3001
# Build for production pnpm dev:studio # Studio Platform on :3002
pnpm build pnpm dev:admin # Admin Dashboard on :3003
``` ```
## 📝 Environment Configuration ### Production Deployment
Copy `.env.example` to `.env` and configure:
```bash ```bash
# Required # Build all applications
GEMINI_API_KEY=your_gemini_api_key_here pnpm build
# Optional (with defaults) # Start infrastructure
PORT=3000 docker compose up -d
NODE_ENV=development
CORS_ORIGIN=* # Start production servers
MAX_FILE_SIZE=5242880 # 5MB pnpm start:api
MAX_FILES=3 pnpm start:landing
RESULTS_DIR=./results pnpm start:studio
UPLOADS_DIR=./uploads/temp pnpm start:admin
LOG_LEVEL=info
``` ```
## 🔌 API Endpoints ## Development Commands
### Health Check ```bash
``` # Install dependencies for all apps
GET /health pnpm install
```
Returns server status and uptime.
### API Information # Development (all apps in parallel)
pnpm dev
# Build all apps
pnpm build
# Type checking
pnpm typecheck
# Linting
pnpm lint
# Testing (API service only)
pnpm test
# Clean all build outputs
pnpm clean
``` ```
GET /api/info
``` ## Environment Configuration
Returns API details and configuration.
Each application has its own environment configuration:
- **Root**: `.env.docker` (for Docker services)
- **API Service**: `apps/api-service/.env`
- **Studio**: `apps/studio/.env.local`
- **Admin**: `apps/admin/.env.local`
See individual app README files for specific environment variables.
## Services & Ports
| Service | Port | Description |
|---------|------|-------------|
| API Service | 3000 | Core REST API |
| Landing Page | 3001 | Public website |
| Studio Platform | 3002 | SaaS application |
| Admin Dashboard | 3003 | Administration |
| PostgreSQL | 5434 | Database |
| MinIO API | 9000 | Object storage |
| MinIO Console | 9001 | Storage admin |
## API Usage
### Generate Image ### Generate Image
```
POST /api/generate
Content-Type: multipart/form-data
```
**Parameters:**
- `prompt` (string, required): Text description for image generation
- `filename` (string, optional): Custom filename for the generated image
- `referenceImages` (files, optional): Up to 3 reference images (5MB max each)
**Supported formats:** PNG, JPEG, JPG, WebP
## 📖 Usage Examples
### cURL
```bash ```bash
# Basic text-to-image # Basic text-to-image
curl -X POST http://localhost:3000/api/generate \ curl -X POST http://localhost:3000/api/generate \
@ -99,114 +149,15 @@ curl -X POST http://localhost:3000/api/generate \
-F "referenceImages=@./reference.jpg" -F "referenceImages=@./reference.jpg"
``` ```
### JavaScript/Fetch See `apps/api-service/README.md` for detailed API documentation.
```javascript
const formData = new FormData();
formData.append('prompt', 'A futuristic cityscape at sunset');
formData.append('filename', 'futuristic_city');
const response = await fetch('http://localhost:3000/api/generate', { ## Contributing
method: 'POST',
body: formData
});
const result = await response.json(); 1. Each app has its own package.json and dependencies
console.log(result); 2. Use the root workspace commands for multi-app operations
``` 3. Follow the existing code style and patterns
4. Run `pnpm typecheck` and `pnpm lint` before committing
### Response Format ## License
```json
{
"success": true,
"message": "Image generated successfully",
"data": {
"filename": "generated_image_123.png",
"filepath": "./results/generated_image_123.png",
"description": "Generated image description",
"model": "gemini-2.0-flash-exp",
"generatedAt": "2024-01-01T12:00:00.000Z"
}
}
```
## 🛠️ Development Scripts MIT License - see individual app directories for more details.
```bash
# Development
pnpm dev # Start with auto-reload
pnpm build # Build for production
pnpm start # Start production server
# Code Quality
pnpm typecheck # TypeScript type checking
pnpm lint # ESLint code linting
pnpm lint:fix # Fix ESLint issues
pnpm format # Format code with Prettier
pnpm format:check # Check code formatting
# Testing
pnpm test # Run tests
pnpm test:watch # Run tests in watch mode
pnpm test:coverage # Run tests with coverage
```
## 🏗️ Project Structure
```
banatie/
├── src/
│ ├── middleware/ # Express middleware
│ ├── routes/ # API route handlers
│ ├── services/ # Business logic services
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ ├── app.ts # Express app configuration
│ └── server.ts # Server entry point
├── tests/ # Test files
├── results/ # Generated images output
├── uploads/ # Temporary file uploads
└── logs/ # Application logs
```
## 🔧 Configuration
### File Limits
- **Max file size**: 5MB per image (configurable)
- **Max files**: 3 reference images per request (configurable)
- **Request size**: 10MB total request limit
### Supported Image Formats
- PNG
- JPEG/JPG
- WebP
## 🚦 Error Handling
The API provides detailed error responses:
**Validation Errors (400):**
- Missing required parameters
- Invalid file formats
- File size exceeded
- Too many files
**Server Errors (500):**
- Missing API key configuration
- Image generation failures
- Internal processing errors
## 📄 License
MIT License - see LICENSE file for details.
## 🤝 Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests and linting
5. Submit a pull request
## 📞 Support
For issues and questions, please open an issue on the GitHub repository.

18
apps/admin/.env.example Normal file
View File

@ -0,0 +1,18 @@
# Banatie API Configuration
BANATIE_API_URL=http://localhost:3000
# Database Configuration (Direct admin access)
POSTGRES_URL=postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie
# MinIO Storage Configuration
MINIO_ENDPOINT=http://localhost:9000
MINIO_ACCESS_KEY=your_minio_access_key
MINIO_SECRET_KEY=your_minio_secret_key
# Admin Authentication
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_admin_password
# Next.js Configuration
NEXTAUTH_URL=http://localhost:3003
NEXTAUTH_SECRET=your_nextauth_secret

66
apps/admin/README.md Normal file
View File

@ -0,0 +1,66 @@
# Banatie Admin
Administration dashboard for managing the entire Banatie AI image generation service.
## Features
- 📊 **System Monitoring**: Real-time service health and performance metrics
- 👥 **User Management**: Manage users, subscriptions, and permissions
- 🖼️ **Content Management**: Monitor generated images and usage patterns
- 🔧 **Service Control**: Start/stop services, update configurations
- 📈 **Analytics**: Detailed usage analytics and reporting
- 🚨 **Alerts**: System alerts and notifications
## Tech Stack
- **Framework**: Next.js 14 with App Router
- **Database**: Direct PostgreSQL connection for admin operations
- **Storage**: MinIO admin interface integration
- **Monitoring**: Integration with API service metrics
- **Styling**: Tailwind CSS with admin-focused components
- **Charts**: Recharts for data visualization
## Development
```bash
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env.local
# Start development server
pnpm dev
```
## Environment Variables
```env
# Banatie API
BANATIE_API_URL=http://localhost:3000
# Database (Direct admin access)
POSTGRES_URL=postgresql://user:password@localhost:5434/banatie
# Storage
MINIO_ENDPOINT=http://localhost:9000
MINIO_ACCESS_KEY=admin_access_key
MINIO_SECRET_KEY=admin_secret_key
# Admin Authentication
ADMIN_USERNAME=admin
ADMIN_PASSWORD=secure_password
```
## TODO
- [ ] Implement real-time metrics dashboard
- [ ] Add user management interface
- [ ] Create service control panel
- [ ] Add database admin tools
- [ ] Implement log viewer
- [ ] Add configuration management
- [ ] Create backup/restore functionality
- [ ] Add alert system
- [ ] Implement audit logging
- [ ] Add API key management

16
apps/admin/next.config.js Normal file
View File

@ -0,0 +1,16 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
images: {
domains: ['localhost'],
},
env: {
BANATIE_API_URL: process.env.BANATIE_API_URL || 'http://localhost:3000',
POSTGRES_URL: process.env.POSTGRES_URL,
MINIO_ENDPOINT: process.env.MINIO_ENDPOINT,
},
}
module.exports = nextConfig

37
apps/admin/package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "@banatie/admin",
"version": "1.0.0",
"description": "Banatie Admin - Administration dashboard for managing the entire Banatie service",
"private": true,
"scripts": {
"dev": "next dev -p 3003",
"build": "next build",
"start": "next start -p 3003",
"lint": "next lint",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"next": "^14.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/node": "^20.0.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.9.2",
"recharts": "^2.12.0",
"lucide-react": "^0.400.0"
},
"devDependencies": {
"tailwindcss": "^3.4.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.0",
"@tailwindcss/forms": "^0.5.0",
"@headlessui/react": "^2.0.0"
},
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
}
}

View File

@ -0,0 +1,22 @@
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Banatie Admin - Service Administration',
description: 'Administration dashboard for managing the Banatie AI image generation service',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className="min-h-screen bg-gray-100">
<div className="min-h-screen">
{children}
</div>
</body>
</html>
)
}

174
apps/admin/src/app/page.tsx Normal file
View File

@ -0,0 +1,174 @@
export default function AdminDashboard() {
return (
<div className="min-h-screen bg-gray-100">
{/* Header */}
<header className="bg-white shadow">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex items-center">
<h1 className="text-2xl font-bold text-gray-900">
Banatie Admin
</h1>
</div>
<div className="flex items-center space-x-4">
<span className="text-sm text-gray-500">System Status: Online</span>
</div>
</div>
</div>
</header>
{/* Main Content */}
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="px-4 py-6 sm:px-0">
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
{/* Stats Cards */}
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-blue-500 rounded-md flex items-center justify-center">
<span className="text-white text-sm font-medium">API</span>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
API Requests
</dt>
<dd className="text-lg font-medium text-gray-900">
1,234
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-green-500 rounded-md flex items-center justify-center">
<span className="text-white text-sm font-medium">IMG</span>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
Images Generated
</dt>
<dd className="text-lg font-medium text-gray-900">
567
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-yellow-500 rounded-md flex items-center justify-center">
<span className="text-white text-sm font-medium">USR</span>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
Active Users
</dt>
<dd className="text-lg font-medium text-gray-900">
89
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-red-500 rounded-md flex items-center justify-center">
<span className="text-white text-sm font-medium">ERR</span>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
Errors (24h)
</dt>
<dd className="text-lg font-medium text-gray-900">
3
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
{/* Services Status */}
<div className="mt-8">
<div className="bg-white shadow rounded-lg">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900 mb-4">
Service Status
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm font-medium text-gray-900">API Service</span>
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Healthy
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm font-medium text-gray-900">PostgreSQL Database</span>
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Connected
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm font-medium text-gray-900">MinIO Storage</span>
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Available
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm font-medium text-gray-900">Gemini AI</span>
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
Rate Limited
</span>
</div>
</div>
</div>
</div>
</div>
{/* Coming Soon Notice */}
<div className="mt-8">
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
<div className="flex">
<div className="ml-3">
<h3 className="text-sm font-medium text-blue-800">
Admin Dashboard Under Development
</h3>
<div className="mt-2 text-sm text-blue-700">
<p>
This admin dashboard is being developed to provide comprehensive
monitoring and management capabilities for the Banatie service.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
)
}

31
apps/admin/tsconfig.json Normal file
View File

@ -0,0 +1,31 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "ES2022"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/lib/*": ["./src/lib/*"],
"@/types/*": ["./src/types/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,72 @@
{
"name": "@banatie/api-service",
"version": "1.0.0",
"description": "Nano Banana Image Generation Service - REST API for AI-powered image generation using Gemini Flash Image model",
"main": "dist/server.js",
"scripts": {
"dev": "tsx --watch src/server.ts",
"start": "node dist/server.js",
"build": "tsc",
"typecheck": "tsc --noEmit",
"lint": "eslint src/**/*.ts",
"lint:fix": "eslint src/**/*.ts --fix",
"format": "prettier --write src/**/*.ts",
"format:check": "prettier --check src/**/*.ts",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"clean": "rm -rf dist",
"prebuild": "npm run clean",
"prestart": "npm run build"
},
"keywords": [
"image-generation",
"ai",
"gemini",
"nano-banana",
"rest-api",
"express",
"typescript"
],
"author": "",
"license": "MIT",
"packageManager": "pnpm@10.11.0",
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
},
"dependencies": {
"@google/genai": "^1.17.0",
"cors": "^2.8.5",
"dotenv": "^17.2.2",
"express": "^5.1.0",
"express-rate-limit": "^7.4.1",
"express-validator": "^7.2.0",
"helmet": "^8.0.0",
"mime": "3.0.0",
"minio": "^8.0.6",
"multer": "^2.0.2",
"winston": "^3.17.0"
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jest": "^29.5.14",
"@types/multer": "^2.0.0",
"@types/node": "^24.3.1",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^8.18.2",
"@typescript-eslint/parser": "^8.18.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"jest": "^29.7.0",
"nodemon": "^3.1.9",
"prettier": "^3.4.2",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"tsx": "^4.20.5",
"typescript": "^5.9.2"
}
}

31
apps/landing/README.md Normal file
View File

@ -0,0 +1,31 @@
# Banatie Landing Page
Next.js landing page for the Banatie AI image generation service.
## Features
- Landing page with service overview
- Demo page for image generation (TODO)
- Responsive design with Tailwind CSS
- Integration with Banatie API service
## Development
```bash
# Install dependencies
pnpm install
# Start development server
pnpm dev
# Build for production
pnpm build
```
## TODO
- [ ] Implement image generation demo
- [ ] Add API integration with ../api-service
- [ ] Design landing page content
- [ ] Add pricing section
- [ ] Add contact form

View File

@ -0,0 +1,11 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
images: {
domains: ['localhost'],
},
}
module.exports = nextConfig

33
apps/landing/package.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "@banatie/landing",
"version": "1.0.0",
"description": "Banatie Landing Page - Next.js landing page with image generation demo",
"private": true,
"scripts": {
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start -p 3001",
"lint": "next lint",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"next": "^14.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/node": "^20.0.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.9.2"
},
"devDependencies": {
"tailwindcss": "^3.4.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.0"
},
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
}
}

View File

@ -0,0 +1,22 @@
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Banatie - AI Image Generation',
description: 'Generate stunning images with AI using the Banatie service',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className="min-h-screen bg-gray-50">
<div className="container mx-auto px-4">
{children}
</div>
</body>
</html>
)
}

View File

@ -0,0 +1,28 @@
export default function HomePage() {
return (
<div className="py-12">
<div className="text-center">
<h1 className="text-4xl font-bold text-gray-900 mb-4">
Welcome to Banatie
</h1>
<p className="text-xl text-gray-600 mb-8">
AI-Powered Image Generation Service
</p>
<div className="bg-white rounded-lg shadow-md p-8 max-w-2xl mx-auto">
<h2 className="text-2xl font-semibold mb-4">Demo Coming Soon</h2>
<p className="text-gray-600">
Experience the power of AI image generation with our Gemini Flash model integration.
</p>
<div className="mt-6">
<button
className="bg-blue-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50"
disabled
>
Try Demo (Coming Soon)
</button>
</div>
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "ES2022"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

16
apps/studio/.env.example Normal file
View File

@ -0,0 +1,16 @@
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
# Stripe Configuration
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
# App Configuration
NEXTAUTH_URL=http://localhost:3002
NEXTAUTH_SECRET=your_nextauth_secret
# Banatie API
BANATIE_API_URL=http://localhost:3000

50
apps/studio/README.md Normal file
View File

@ -0,0 +1,50 @@
# Banatie Studio
SaaS platform for the Banatie AI image generation service. Based on Vercel's Next.js SaaS starter template with Supabase authentication and Stripe billing.
## Features
- 🔐 **Authentication**: Supabase Auth with social login
- 💳 **Billing**: Stripe subscriptions and payment processing
- 🎨 **AI Generation**: Integration with Banatie API service
- 📊 **Dashboard**: User dashboard with usage analytics
- 🏢 **Multi-tenant**: Organization and team management
## Tech Stack
- **Framework**: Next.js 14 with App Router
- **Authentication**: Supabase Auth
- **Database**: Supabase (PostgreSQL)
- **Payments**: Stripe
- **Styling**: Tailwind CSS
- **TypeScript**: Full type safety
## Development
```bash
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env.local
# Start development server
pnpm dev
```
## Environment Setup
1. **Supabase**: Create a new project at [supabase.com](https://supabase.com)
2. **Stripe**: Set up your account at [stripe.com](https://stripe.com)
3. **Environment Variables**: Copy `.env.example` to `.env.local` and fill in your keys
## TODO
- [ ] Set up Supabase authentication
- [ ] Configure Stripe billing
- [ ] Implement user dashboard
- [ ] Add subscription tiers
- [ ] Integrate with Banatie API
- [ ] Add usage tracking
- [ ] Implement team management
- [ ] Add billing portal

View File

@ -0,0 +1,16 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
images: {
domains: ['localhost', 'avatars.githubusercontent.com'],
},
env: {
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
},
}
module.exports = nextConfig

39
apps/studio/package.json Normal file
View File

@ -0,0 +1,39 @@
{
"name": "@banatie/studio",
"version": "1.0.0",
"description": "Banatie Studio - SaaS platform for managing AI image generation subscriptions",
"private": true,
"scripts": {
"dev": "next dev -p 3002",
"build": "next build",
"start": "next start -p 3002",
"lint": "next lint",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"next": "^14.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/node": "^20.0.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.9.2",
"@supabase/supabase-js": "^2.45.0",
"@supabase/auth-helpers-nextjs": "^0.10.0",
"stripe": "^16.0.0",
"@stripe/stripe-js": "^4.0.0"
},
"devDependencies": {
"tailwindcss": "^3.4.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.0",
"@tailwindcss/forms": "^0.5.0",
"@tailwindcss/typography": "^0.5.0"
},
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
}
}

View File

@ -0,0 +1,22 @@
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Banatie Studio - AI Image Generation SaaS',
description: 'Professional AI image generation platform with subscription management',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className="min-h-screen bg-gray-50">
<div className="min-h-screen">
{children}
</div>
</body>
</html>
)
}

View File

@ -0,0 +1,49 @@
export default function StudioPage() {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<div className="container mx-auto px-4 py-12">
<div className="text-center">
<h1 className="text-5xl font-bold text-gray-900 mb-6">
Banatie Studio
</h1>
<p className="text-xl text-gray-600 mb-8 max-w-2xl mx-auto">
Professional AI image generation platform with subscription management,
user authentication, and billing integration.
</p>
<div className="grid md:grid-cols-3 gap-8 mt-12 max-w-4xl mx-auto">
<div className="bg-white rounded-lg shadow-lg p-6">
<h3 className="text-xl font-semibold mb-4">🔐 Authentication</h3>
<p className="text-gray-600">
Secure user authentication powered by Supabase with social login support.
</p>
</div>
<div className="bg-white rounded-lg shadow-lg p-6">
<h3 className="text-xl font-semibold mb-4">💳 Billing</h3>
<p className="text-gray-600">
Stripe integration for subscription management and payment processing.
</p>
</div>
<div className="bg-white rounded-lg shadow-lg p-6">
<h3 className="text-xl font-semibold mb-4">🎨 AI Generation</h3>
<p className="text-gray-600">
Professional image generation with usage tracking and limits.
</p>
</div>
</div>
<div className="mt-12">
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 max-w-2xl mx-auto">
<p className="text-yellow-800">
<strong>Coming Soon:</strong> This SaaS platform is under development.
Based on Vercel&apos;s Next.js SaaS starter template.
</p>
</div>
</div>
</div>
</div>
</div>
)
}

31
apps/studio/tsconfig.json Normal file
View File

@ -0,0 +1,31 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "ES2022"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/lib/*": ["./src/lib/*"],
"@/types/*": ["./src/types/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@ -2,14 +2,14 @@
services: services:
app: app:
build: build:
context: . context: ./apps/api-service
target: development target: development
container_name: banatie-app container_name: banatie-app
ports: ports:
- "3000:3000" - "3000:3000"
volumes: volumes:
- ./src:/app/src - ./apps/api-service/src:/app/src
- ./logs:/app/logs - ./apps/api-service/logs:/app/logs
networks: networks:
- banatie-network - banatie-network
depends_on: depends_on:

View File

@ -1,72 +1,55 @@
{ {
"name": "banatie", "name": "banatie-monorepo",
"version": "1.0.0", "version": "1.0.0",
"description": "Nano Banana Image Generation Service - REST API for AI-powered image generation using Gemini Flash Image model", "description": "Banatie AI Image Generation Service - Monorepo with API, Landing, Studio, and Admin apps",
"main": "dist/server.js", "private": true,
"scripts": {
"dev": "tsx --watch src/server.ts",
"start": "node dist/server.js",
"build": "tsc",
"typecheck": "tsc --noEmit",
"lint": "eslint src/**/*.ts",
"lint:fix": "eslint src/**/*.ts --fix",
"format": "prettier --write src/**/*.ts",
"format:check": "prettier --check src/**/*.ts",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"clean": "rm -rf dist",
"prebuild": "npm run clean",
"prestart": "npm run build"
},
"keywords": [
"image-generation",
"ai",
"gemini",
"nano-banana",
"rest-api",
"express",
"typescript"
],
"author": "",
"license": "MIT",
"packageManager": "pnpm@10.11.0", "packageManager": "pnpm@10.11.0",
"engines": { "engines": {
"node": ">=18.0.0", "node": ">=18.0.0",
"pnpm": ">=8.0.0" "pnpm": ">=8.0.0"
}, },
"dependencies": { "scripts": {
"@google/genai": "^1.17.0", "dev": "pnpm --parallel run dev",
"cors": "^2.8.5", "dev:api": "pnpm --filter @banatie/api-service dev",
"dotenv": "^17.2.2", "dev:landing": "pnpm --filter @banatie/landing dev",
"express": "^5.1.0", "dev:studio": "pnpm --filter @banatie/studio dev",
"express-rate-limit": "^7.4.1", "dev:admin": "pnpm --filter @banatie/admin dev",
"express-validator": "^7.2.0", "build": "pnpm -r build",
"helmet": "^8.0.0", "build:api": "pnpm --filter @banatie/api-service build",
"mime": "3.0.0", "build:landing": "pnpm --filter @banatie/landing build",
"minio": "^8.0.6", "build:studio": "pnpm --filter @banatie/studio build",
"multer": "^2.0.2", "build:admin": "pnpm --filter @banatie/admin build",
"winston": "^3.17.0" "start:api": "pnpm --filter @banatie/api-service start",
"start:landing": "pnpm --filter @banatie/landing start",
"start:studio": "pnpm --filter @banatie/studio start",
"start:admin": "pnpm --filter @banatie/admin start",
"lint": "pnpm -r lint",
"lint:api": "pnpm --filter @banatie/api-service lint",
"lint:landing": "pnpm --filter @banatie/landing lint",
"lint:studio": "pnpm --filter @banatie/studio lint",
"lint:admin": "pnpm --filter @banatie/admin lint",
"typecheck": "pnpm -r typecheck",
"typecheck:api": "pnpm --filter @banatie/api-service typecheck",
"typecheck:landing": "pnpm --filter @banatie/landing typecheck",
"typecheck:studio": "pnpm --filter @banatie/studio typecheck",
"typecheck:admin": "pnpm --filter @banatie/admin typecheck",
"test": "pnpm --filter @banatie/api-service test",
"clean": "pnpm -r clean && rm -rf node_modules",
"install:all": "pnpm install"
}, },
"keywords": [
"monorepo",
"image-generation",
"ai",
"gemini",
"rest-api",
"nextjs",
"saas",
"admin-dashboard"
],
"author": "",
"license": "MIT",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.36.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jest": "^29.5.14",
"@types/multer": "^2.0.0",
"@types/node": "^24.3.1",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^8.18.2",
"@typescript-eslint/parser": "^8.18.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"jest": "^29.7.0",
"nodemon": "^3.1.9",
"prettier": "^3.4.2",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"tsx": "^4.20.5",
"typescript": "^5.9.2" "typescript": "^5.9.2"
} }
} }

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,2 @@
packages:
- 'apps/*'