Backend API Next.js dengan integrasi Gemini AI untuk Jekyll Studio webapp. API ini menyediakan endpoints lengkap untuk membuat, mengelola, dan men-deploy Jekyll sites menggunakan AI.
Terinspirasi dari "Firebase Studio, tapi untuk Jekyll" membangun fondasi backend yang solid dan canggih untuk melakukan persis seperti Firebase Studio.
-
Backend Terkelola (Managed Backend): Sama seperti Firebase yang menyediakan backend siap pakai, proyek ini juga menyediakan API yang mengabstraksi semua kerumitan. Pengguna frontend tidak perlu tahu cara install Ruby, menjalankan
jekyll build, atau mengelola Docker. Mereka tinggal klik satu tombol di UI. -
Fungsi Inti Yang Sudah Siap:
- "Authentication/Database" (Manajemen Situs): Punya sistem untuk membuat, melihat, dan menghapus "proyek" atau situs.
- "Hosting" (Build & Serve): Punya endpoint untuk men-deploy (
jekyll serve) dan membangun (jekyll build) situs. - "Cloud Functions" (AI & Kustomisasi): Menggunakan kekuatan AI dari Gemini sebagai "fungsi cloud" untuk men-generate seluruh struktur situs dari sebuah prompt, sesuatu yang sangat modern.
- "Storage" (File Management): Punya API untuk eksplorasi, membaca, dan menulis file di dalam setiap situs Jekyll.
- β Gemini AI Integration - Generate Jekyll sites dari natural language prompts
- β Jekyll Container Management - Automated Jekyll site creation dan building
- β Real-time Updates - WebSocket untuk live updates dan file changes
- β File Management - CRUD operations untuk Jekyll files
- β Security - Rate limiting, CORS, input validation
- β Multi-site Support - Handle multiple Jekyll sites simultaneously
- β Live Preview - Development server dengan live reload
- Node.js 18+
- Docker & Docker Compose
- Gemini AI API Key
git clone https://github.com/daffadevhosting/jekyll-studio-api.git
cd jekyll-studio-apinpm installcp .env.example .env
# Edit .env dengan your API keysnpm run dev# Start complete stack
docker-compose -f docker-compose.api.yml up -d
# Start only API + Jekyll
docker-compose -f docker-compose.api.yml up api jekyll redisjekyll-studio-api/
βββ pages/api/ # Next.js API routes
β βββ sites/ # Site management endpoints
β βββ ai/ # AI generation endpoints
β βββ websocket.ts # WebSocket server
βββ lib/ # Core libraries
β βββ gemini.ts # Gemini AI service
β βββ jekyll-manager.ts # Jekyll operations manager
β βββ utils.ts # Utility functions
βββ middleware/ # Security middleware
βββ docker/ # Docker configurations
βββ projects/ # Generated Jekyll sites
βββ templates/ # Jekyll templates
POST /api/sites/create
Content-Type: application/json
{
"name": "my-blog",
"prompt": "Create a personal tech blog with dark theme and syntax highlighting"
}GET /api/sitesGET /api/sites/[id]DELETE /api/sites/[id]POST /api/sites/[id]/buildPOST /api/sites/[id]/serve
Content-Type: application/json
{
"port": 4001 // optional
}DELETE /api/sites/[id]/serveGET /api/sites/[id]/files?path=/GET /api/sites/[id]/files?path=_config.ymlPUT /api/sites/[id]/files
Content-Type: application/json
{
"filePath": "_posts/2024-01-01-hello-world.md",
"content": "---\nlayout: post\ntitle: Hello World\n---\n\nContent here..."
}POST /api/ai/generate
Content-Type: application/json
{
"type": "site",
"prompt": "Create a portfolio website for a web developer"
}POST /api/ai/generate
Content-Type: application/json
{
"type": "component",
"prompt": "Create a hero section layout",
"context": {
"componentType": "layout"
}
}POST /api/ai/generate
Content-Type: application/json
{
"type": "styles",
"prompt": "Modern dark theme with purple accents"
}POST /api/ai/generate
Content-Type: application/json
{
"type": "improve",
"prompt": "Make this more engaging",
"context": {
"content": "existing content here",
"improvements": "add more personality and examples"
}
}const ws = new WebSocket('ws://localhost:8080');
ws.on('message', (data) => {
const event = JSON.parse(data);
console.log('Event:', event.type, event.data);
});sites- Initial sites listsiteStatusChanged- Site status updatesfileChanged- File change notificationssiteBuilt- Build completion notifications
- API Calls: 100 requests/minute
- AI Generation: 10 requests/minute
- Site Creation: 5 sites/5 minutes
- XSS protection
- SQL injection prevention
- File path traversal protection
- Site name validation
- Configurable allowed origins
- Secure headers
- Credential support
docker-compose -f docker-compose.api.yml up -d# With HTTPS and database
docker-compose -f docker-compose.api.yml --profile production --profile persistence up -d- API: Next.js application
- Jekyll: Jekyll container for site operations
- Redis: Caching and session storage
- Nginx: Reverse proxy (production)
- PostgreSQL: Data persistence (optional)
- FileBrowser: File management UI (optional)
GEMINI_API_KEY=your_gemini_api_key
NEXTAUTH_SECRET=your_secure_secret# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/jekyll_studio
# Redis
REDIS_URL=redis://localhost:6379
# Security
ALLOWED_ORIGINS=http://localhost:3000,https://yourdomain.com
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=100
# Email (notifications)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASS=your_app_password- Default: API + Jekyll + Redis
- Production: + Nginx with SSL
- Persistence: + PostgreSQL database
- Tools: + FileBrowser for file management
// Create new site
async function createSite(prompt) {
const response = await fetch('/api/sites/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'my-site',
prompt: prompt
})
});
return response.json();
}
// Watch site status
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'siteStatusChanged') {
updateSiteStatus(data.data);
}
};// composables/useSites.js
import { ref, onMounted } from 'vue'
export function useSites() {
const sites = ref([])
const loading = ref(false)
const createSite = async (siteData) => {
loading.value = true
try {
const response = await $fetch('/api/sites/create', {
method: 'POST',
body: siteData
})
sites.value.push(response.site)
return response
} finally {
loading.value = false
}
}
const fetchSites = async () => {
const response = await $fetch('/api/sites')
sites.value = response.sites
}
onMounted(fetchSites)
return { sites, createSite, fetchSites, loading }
}# Create site
curl -X POST http://localhost:3000/api/sites/create \
-H "Content-Type: application/json" \
-d '{"name": "blog", "prompt": "Create a minimalist blog"}'
# Build site
curl -X POST http://localhost:3000/api/sites/{id}/build
# Update file
curl -X PUT http://localhost:3000/api/sites/{id}/files \
-H "Content-Type: application/json" \
-d '{"filePath": "index.md", "content": "# Hello World"}'import requests
import json
class JekyllStudioClient:
def __init__(self, base_url="http://localhost:3000"):
self.base_url = base_url
def create_site(self, name, prompt):
response = requests.post(
f"{self.base_url}/api/sites/create",
json={"name": name, "prompt": prompt}
)
return response.json()
def build_site(self, site_id):
response = requests.post(
f"{self.base_url}/api/sites/{site_id}/build"
)
return response.json()
def serve_site(self, site_id, port=None):
data = {"port": port} if port else {}
response = requests.post(
f"{self.base_url}/api/sites/{site_id}/serve",
json=data
)
return response.json()
# Usage
client = JekyllStudioClient()
site = client.create_site("my-blog", "Create a tech blog with dark theme")
build_result = client.build_site(site['site']['id'])
serve_result = client.serve_site(site['site']['id'])npm run testnpm run test:integrationImport the Postman collection:
curl -o jekyll-studio.postman_collection.json \
https://raw.githubusercontent.com/your-repo/postman-collection.json# Install k6
npm install -g k6
# Run load tests
k6 run tests/load-test.jsGET /api/healthResponse:
{
"status": "healthy",
"timestamp": "2024-01-01T00:00:00Z",
"services": {
"jekyll": "running",
"redis": "connected",
"database": "connected"
}
}# View API logs
docker-compose logs -f api
# View Jekyll container logs
docker-compose logs -f jekyll
# View all logs
docker-compose logs -fGET /api/metrics# Production environment
cp .env.example .env.production
# Configure production valuesdocker build -t jekyll-studio-api:latest -f Dockerfile.api .# Start production stack
docker-compose -f docker-compose.api.yml --profile production up -d# Generate SSL certificates (Let's Encrypt)
docker run --rm -v ./nginx/ssl:/etc/letsencrypt \
certbot/certbot certonly --webroot \
-w /var/www/certbot -d yourdomain.comdocker-compose exec postgres psql -U jekyll_user -d jekyll_studio -f /app/migrations/init.sql# Backup PostgreSQL
docker-compose exec postgres pg_dump -U jekyll_user jekyll_studio > backup.sql
# Restore
docker-compose exec -T postgres psql -U jekyll_user jekyll_studio < backup.sql# Backup all sites
tar -czf sites-backup.tar.gz projects/
# Restore
tar -xzf sites-backup.tar.gzError: GEMINI_API_KEY is required
Solution: Set your Gemini API key in .env
Error: Permission denied accessing /var/run/docker.sock
Solution: Add user to docker group
sudo usermod -aG docker $USERError: Port 3000 is already in use
Solution: Change port in .env or stop conflicting service
Check logs:
docker-compose logs jekyll# Enable debug logging
DEBUG=jekyll-studio:* npm run dev# Clone repository
git clone https://github.com/daffadevhosting/jekyll-studio-api.git
cd jekyll-studio-api
# Install dependencies
npm install
# Start development environment
npm run dev
# Run tests
npm test- ESLint configuration
- Prettier formatting
- TypeScript strict mode
- Fork repository
- Create feature branch
- Add tests for new features
- Ensure all tests pass
- Update documentation
- Submit pull request
CC0 1.0 Universal License - see LICENSE file for details.
- Frontend Repository: Jekyll Studio Frontend
- Docker Images: Docker Hub
- Documentation: Full Documentation
- Issues: GitHub Issues