1203 lines
36 KiB
Markdown
1203 lines
36 KiB
Markdown
|
|
# VibeCode Complete Implementation Roadmap v2.0
|
||
|
|
## Dual Deployment: Internal GB Apps + External Forgejo ALM Projects
|
||
|
|
|
||
|
|
## Executive Summary
|
||
|
|
|
||
|
|
**Current Status:** BotUI's backend is **80% complete** with powerful LLM-driven code generation. The frontend needs professional tools, AND the platform must support **two deployment models**:
|
||
|
|
|
||
|
|
1. **Internal GB Apps** - Apps served directly from the GB platform using API endpoints
|
||
|
|
2. **External Forgejo ALM Projects** - Apps deployed to external Forgejo repositories with CI/CD
|
||
|
|
|
||
|
|
**What Works (Backend):**
|
||
|
|
- ✅ LLM-powered app generation (AppGenerator: 3400+ lines)
|
||
|
|
- ✅ Multi-agent pipeline (Orchestrator: Plan → Build → Review → Deploy → Monitor)
|
||
|
|
- ✅ Real-time WebSocket progress
|
||
|
|
- ✅ Database schema generation
|
||
|
|
- ✅ File generation (HTML, CSS, JS, BAS)
|
||
|
|
- ✅ Designer AI (runtime modifications with undo/redo)
|
||
|
|
- ✅ chromiumoxide dependency ready for browser automation
|
||
|
|
- ✅ **Forgejo ALM integration** (mTLS, runners, web server on port 3000)
|
||
|
|
- ✅ **App deployment** (`/apps/{name}` routes, Drive storage)
|
||
|
|
|
||
|
|
**What's Missing (Critical Gaps):**
|
||
|
|
- ❌ Deployment routing logic (internal vs external)
|
||
|
|
- ❌ Forgejo project initialization & git push
|
||
|
|
- ❌ CI/CD pipeline generation for Forgejo projects
|
||
|
|
- ❌ Monaco/CodeMirror editor (just textarea now)
|
||
|
|
- ❌ Database UI (no schema visualizer)
|
||
|
|
- ❌ Git operations UI
|
||
|
|
- ❌ Browser automation engine UI
|
||
|
|
- ❌ Multi-file editing workspace
|
||
|
|
- ❌ Enhanced terminal
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Architecture: Dual Deployment Model
|
||
|
|
|
||
|
|
```
|
||
|
|
┌──────────────────────────────────────────────────────────────────┐
|
||
|
|
│ USER REQUEST │
|
||
|
|
│ "I want a full CRM system" │
|
||
|
|
└────────────────────────────┬─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌──────────────────────────────────────────────────────────────────┐
|
||
|
|
│ VIBE BUILDER UI │
|
||
|
|
│ ┌──────────────────┐ ┌──────────────────┐ │
|
||
|
|
│ │ Agent Sidebar │ │ Canvas Area │ │
|
||
|
|
│ │ (Mantis #1-4) │ │ - Task Nodes │ │
|
||
|
|
│ │ - Status cards │ │ - Preview │ │
|
||
|
|
│ │ - Workspaces │ │ - Chat Overlay │ │
|
||
|
|
│ └──────────────────┘ └──────────────────┘ │
|
||
|
|
│ │
|
||
|
|
│ ⚠️ DEPLOYMENT CHOICE (NEW): │
|
||
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ 📱 Deploy to GB Platform 🌐 Deploy to Forgejo │ │
|
||
|
|
│ │ - Serve from /apps/{name} - Push to repo │ │
|
||
|
|
│ │ - Use GB API - CI/CD pipeline │ │
|
||
|
|
│ │ - Fast iteration - Custom domain │ │
|
||
|
|
│ │ - Shared resources - Independent │ │
|
||
|
|
│ └─────────────────────────────────────────────────────┘ │
|
||
|
|
└────────────────────────────┬─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
┌────────────┴────────────┐
|
||
|
|
│ │
|
||
|
|
▼ ▼
|
||
|
|
┌───────────────────────┐ ┌──────────────────────────────────┐
|
||
|
|
│ INTERNAL GB APPS │ │ EXTERNAL FORGEJO PROJECTS │
|
||
|
|
│ │ │ │
|
||
|
|
│ Deployment Flow: │ │ Deployment Flow: │
|
||
|
|
│ 1. Generate files │ │ 1. Generate files │
|
||
|
|
│ 2. Store in Drive │ │ 2. Init git repo │
|
||
|
|
│ 3. Serve from /apps/ │ │ 3. Push to Forgejo │
|
||
|
|
│ 4. Use GB APIs │ │ 4. Create CI/CD (.forgejo/*) │
|
||
|
|
│ 5. Shared DB │ │ 5. Runner builds & deploys │
|
||
|
|
│ 6. Shared auth │ │ 6. Independent deployment │
|
||
|
|
│ │ │ 7. Custom domain │
|
||
|
|
│ ┌─────────────────┐ │ │ │
|
||
|
|
│ │ App Router │ │ │ ┌──────────────────────────────┐ │
|
||
|
|
│ │ /apps/{name} │ │ │ │ Forgejo ALM (port 3000) │ │
|
||
|
|
│ │ - HTMX routes │ │ │ │ - Git server │ │
|
||
|
|
│ │ - API proxy │ │ │ │ - CI/CD (.forgejo/workflows) │ │
|
||
|
|
│ │ - Auth wrapper │ │ │ │ - Packages (npm, cargo) │ │
|
||
|
|
│ └─────────────────┘ │ │ │ - Actions runner │ │
|
||
|
|
│ │ │ └──────────────────────────────┘ │
|
||
|
|
└───────────────────────┘ └──────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part I: Deployment Infrastructure (CRITICAL - Phase 0)
|
||
|
|
|
||
|
|
### Current State Analysis
|
||
|
|
|
||
|
|
**Existing Infrastructure:**
|
||
|
|
```rust
|
||
|
|
// Forgejo ALM is already configured:
|
||
|
|
botserver/src/security/mutual_tls.rs:150
|
||
|
|
- configure_forgejo_mtls() - mTLS setup for Forgejo
|
||
|
|
|
||
|
|
botserver/src/core/package_manager/installer.rs
|
||
|
|
- forgejo binary installer
|
||
|
|
- forgejo-runner integration
|
||
|
|
- ALM_URL environment variable
|
||
|
|
- Port 3000 for Forgejo web UI
|
||
|
|
|
||
|
|
botserver/src/basic/keywords/create_site.rs
|
||
|
|
- CREATE SITE keyword for app generation
|
||
|
|
- Stores to Drive: apps/{alias}
|
||
|
|
- Serves from: /apps/{alias}
|
||
|
|
|
||
|
|
botserver/src/basic/keywords/app_server.rs
|
||
|
|
- Suite JS file serving
|
||
|
|
- Vendor file routing
|
||
|
|
```
|
||
|
|
|
||
|
|
**Missing Components:**
|
||
|
|
1. ❌ Deployment routing logic (internal vs external choice)
|
||
|
|
2. ❌ Forgejo repository initialization API
|
||
|
|
3. ❌ Git push to Forgejo repositories
|
||
|
|
4. ❌ CI/CD pipeline template generation
|
||
|
|
5. ❌ Forgejo Actions workflow builder
|
||
|
|
6. ❌ Custom domain configuration for external projects
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 0.1: Deployment Router (P0 - CRITICAL)
|
||
|
|
|
||
|
|
**Goal:** Create routing logic to deploy apps internally or to Forgejo
|
||
|
|
|
||
|
|
**File:** `botserver/src/deployment/mod.rs`
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
use std::path::PathBuf;
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub enum DeploymentTarget {
|
||
|
|
/// Serve from GB platform (/apps/{name})
|
||
|
|
Internal {
|
||
|
|
route: String,
|
||
|
|
shared_resources: bool,
|
||
|
|
},
|
||
|
|
/// Deploy to external Forgejo repository
|
||
|
|
External {
|
||
|
|
repo_url: String,
|
||
|
|
custom_domain: Option<String>,
|
||
|
|
ci_cd_enabled: bool,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub struct DeploymentConfig {
|
||
|
|
pub app_name: String,
|
||
|
|
pub target: DeploymentTarget,
|
||
|
|
pub environment: DeploymentEnvironment,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub enum DeploymentEnvironment {
|
||
|
|
Development,
|
||
|
|
Staging,
|
||
|
|
Production,
|
||
|
|
}
|
||
|
|
|
||
|
|
pub struct DeploymentRouter {
|
||
|
|
forgejo_url: String,
|
||
|
|
forgejo_token: Option<String>,
|
||
|
|
internal_base_path: PathBuf,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl DeploymentRouter {
|
||
|
|
pub fn new(
|
||
|
|
forgejo_url: String,
|
||
|
|
forgejo_token: Option<String>,
|
||
|
|
internal_base_path: PathBuf,
|
||
|
|
) -> Self {
|
||
|
|
Self {
|
||
|
|
forgejo_url,
|
||
|
|
forgejo_token,
|
||
|
|
internal_base_path,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Route deployment based on target type
|
||
|
|
pub async fn deploy(
|
||
|
|
&self,
|
||
|
|
config: DeploymentConfig,
|
||
|
|
generated_app: GeneratedApp,
|
||
|
|
) -> Result<DeploymentResult, DeploymentError> {
|
||
|
|
match config.target {
|
||
|
|
DeploymentTarget::Internal { route, .. } => {
|
||
|
|
self.deploy_internal(route, generated_app).await
|
||
|
|
}
|
||
|
|
DeploymentTarget::External { ref repo_url, .. } => {
|
||
|
|
self.deploy_external(repo_url, generated_app).await
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Deploy internally to GB platform
|
||
|
|
async fn deploy_internal(
|
||
|
|
&self,
|
||
|
|
route: String,
|
||
|
|
app: GeneratedApp,
|
||
|
|
) -> Result<DeploymentResult, DeploymentError> {
|
||
|
|
// 1. Store files in Drive
|
||
|
|
// 2. Register route in app router
|
||
|
|
// 3. Create API endpoints
|
||
|
|
// 4. Return deployment URL
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Deploy externally to Forgejo
|
||
|
|
async fn deploy_external(
|
||
|
|
&self,
|
||
|
|
repo_url: &str,
|
||
|
|
app: GeneratedApp,
|
||
|
|
) -> Result<DeploymentResult, DeploymentError> {
|
||
|
|
// 1. Initialize git repo
|
||
|
|
// 2. Add Forgejo remote
|
||
|
|
// 3. Push generated files
|
||
|
|
// 4. Create CI/CD workflow
|
||
|
|
// 5. Trigger build
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub struct DeploymentResult {
|
||
|
|
pub url: String,
|
||
|
|
pub deployment_type: String,
|
||
|
|
pub status: DeploymentStatus,
|
||
|
|
pub metadata: serde_json::Value,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub enum DeploymentStatus {
|
||
|
|
Pending,
|
||
|
|
Building,
|
||
|
|
Deployed,
|
||
|
|
Failed,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug)]
|
||
|
|
pub enum DeploymentError {
|
||
|
|
InternalDeploymentError(String),
|
||
|
|
ForgejoError(String),
|
||
|
|
GitError(String),
|
||
|
|
CiCdError(String),
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Estimated Effort:** 12-16 hours
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 0.2: Forgejo Integration (P0 - CRITICAL)
|
||
|
|
|
||
|
|
**Goal:** Initialize repositories and push code to Forgejo
|
||
|
|
|
||
|
|
**File:** `botserver/src/deployment/forgejo.rs`
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use git2::{Repository, Oid};
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
|
||
|
|
pub struct ForgejoClient {
|
||
|
|
base_url: String,
|
||
|
|
token: String,
|
||
|
|
client: reqwest::Client,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl ForgejoClient {
|
||
|
|
pub fn new(base_url: String, token: String) -> Self {
|
||
|
|
Self {
|
||
|
|
base_url,
|
||
|
|
token,
|
||
|
|
client: reqwest::Client::new(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Create a new repository in Forgejo
|
||
|
|
pub async fn create_repository(
|
||
|
|
&self,
|
||
|
|
name: &str,
|
||
|
|
description: &str,
|
||
|
|
private: bool,
|
||
|
|
) -> Result<ForgejoRepo, ForgejoError> {
|
||
|
|
let url = format!("{}/api/v1/user/repos", self.base_url);
|
||
|
|
|
||
|
|
let payload = CreateRepoRequest {
|
||
|
|
name: name.to_string(),
|
||
|
|
description: description.to_string(),
|
||
|
|
private,
|
||
|
|
auto_init: true,
|
||
|
|
gitignores: Some("Node,React,Vite".to_string()),
|
||
|
|
license: Some("MIT".to_string()),
|
||
|
|
readme: Some("Default".to_string()),
|
||
|
|
};
|
||
|
|
|
||
|
|
let response = self
|
||
|
|
.client
|
||
|
|
.post(&url)
|
||
|
|
.header("Authorization", format!("token {}", self.token))
|
||
|
|
.json(&payload)
|
||
|
|
.send()
|
||
|
|
.await
|
||
|
|
.map_err(|e| ForgejoError::HttpError(e.to_string()))?;
|
||
|
|
|
||
|
|
if response.status().is_success() {
|
||
|
|
let repo: ForgejoRepo = response
|
||
|
|
.json()
|
||
|
|
.await
|
||
|
|
.map_err(|e| ForgejoError::JsonError(e.to_string()))?;
|
||
|
|
Ok(repo)
|
||
|
|
} else {
|
||
|
|
Err(ForgejoError::ApiError(
|
||
|
|
response.status().to_string(),
|
||
|
|
))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Push generated app to Forgejo repository
|
||
|
|
pub async fn push_app(
|
||
|
|
&self,
|
||
|
|
repo_url: &str,
|
||
|
|
app: &GeneratedApp,
|
||
|
|
branch: &str,
|
||
|
|
) -> Result<String, ForgejoError> {
|
||
|
|
// 1. Initialize local git repo
|
||
|
|
let repo = Repository::init(app.temp_dir()?)?;
|
||
|
|
|
||
|
|
// 2. Add all files
|
||
|
|
let mut index = repo.index()?;
|
||
|
|
for file in &app.files {
|
||
|
|
index.add_path(PathBuf::from(&file.path))?;
|
||
|
|
}
|
||
|
|
index.write()?;
|
||
|
|
|
||
|
|
// 3. Create commit
|
||
|
|
let tree_id = index.write_tree()?;
|
||
|
|
let tree = repo.find_tree(tree_id)?;
|
||
|
|
|
||
|
|
let sig = repo.signature()?;
|
||
|
|
let oid = repo.commit(
|
||
|
|
Some(&format!("refs/heads/{}", branch)),
|
||
|
|
&sig,
|
||
|
|
&sig,
|
||
|
|
&format!("Initial commit: {}", app.description),
|
||
|
|
&tree,
|
||
|
|
&[],
|
||
|
|
)?;
|
||
|
|
|
||
|
|
// 4. Add Forgejo remote
|
||
|
|
let mut remote = repo.remote(
|
||
|
|
"origin",
|
||
|
|
&format!(
|
||
|
|
"{}",
|
||
|
|
repo_url.replace("https://", &format!("https://{}@", self.token))
|
||
|
|
),
|
||
|
|
)?;
|
||
|
|
|
||
|
|
// 5. Push to Forgejo
|
||
|
|
remote.push(&[format!("refs/heads/{}", branch)], None)?;
|
||
|
|
|
||
|
|
Ok(oid.to_string())
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Create CI/CD workflow for the app
|
||
|
|
pub async fn create_cicd_workflow(
|
||
|
|
&self,
|
||
|
|
repo_url: &str,
|
||
|
|
app_type: AppType,
|
||
|
|
build_config: BuildConfig,
|
||
|
|
) -> Result<(), ForgejoError> {
|
||
|
|
let workflow = match app_type {
|
||
|
|
AppType::Htmx => self.generate_htmx_workflow(build_config),
|
||
|
|
AppType::React => self.generate_react_workflow(build_config),
|
||
|
|
AppType::Vue => self.generate_vue_workflow(build_config),
|
||
|
|
};
|
||
|
|
|
||
|
|
// Create .forgejo/workflows/deploy.yml
|
||
|
|
// Commit and push
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn generate_htmx_workflow(&self, config: BuildConfig) -> String {
|
||
|
|
r#"
|
||
|
|
name: Deploy HTMX App
|
||
|
|
|
||
|
|
on:
|
||
|
|
push:
|
||
|
|
branches: [main, develop]
|
||
|
|
|
||
|
|
jobs:
|
||
|
|
deploy:
|
||
|
|
runs-on: ubuntu-latest
|
||
|
|
steps:
|
||
|
|
- uses: actions/checkout@v3
|
||
|
|
|
||
|
|
- name: Setup Node.js
|
||
|
|
uses: actions/setup-node@v3
|
||
|
|
with:
|
||
|
|
node-version: '20'
|
||
|
|
|
||
|
|
- name: Install dependencies
|
||
|
|
run: npm ci
|
||
|
|
|
||
|
|
- name: Build
|
||
|
|
run: npm run build
|
||
|
|
|
||
|
|
- name: Deploy to server
|
||
|
|
run: |
|
||
|
|
# Add deployment commands here
|
||
|
|
echo "Deploying to production..."
|
||
|
|
"#
|
||
|
|
.to_string()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn generate_react_workflow(&self, config: BuildConfig) -> String {
|
||
|
|
// Generate React/Vite CI/CD workflow
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn generate_vue_workflow(&self, config: BuildConfig) -> String {
|
||
|
|
// Generate Vue CI/CD workflow
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
|
|
pub struct ForgejoRepo {
|
||
|
|
pub id: u64,
|
||
|
|
pub name: String,
|
||
|
|
pub full_name: String,
|
||
|
|
pub clone_url: String,
|
||
|
|
pub html_url: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Serialize)]
|
||
|
|
struct CreateRepoRequest {
|
||
|
|
name: String,
|
||
|
|
description: String,
|
||
|
|
private: bool,
|
||
|
|
auto_init: bool,
|
||
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||
|
|
gitignores: Option<String>,
|
||
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||
|
|
license: Option<String>,
|
||
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||
|
|
readme: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Copy)]
|
||
|
|
pub enum AppType {
|
||
|
|
Htmx,
|
||
|
|
React,
|
||
|
|
Vue,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub struct BuildConfig {
|
||
|
|
pub node_version: String,
|
||
|
|
pub build_command: String,
|
||
|
|
pub output_directory: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug)]
|
||
|
|
pub enum ForgejoError {
|
||
|
|
HttpError(String),
|
||
|
|
JsonError(String),
|
||
|
|
ApiError(String),
|
||
|
|
GitError(String),
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**API Endpoints:**
|
||
|
|
```rust
|
||
|
|
// botserver/src/deployment/api.rs
|
||
|
|
|
||
|
|
use axum::{
|
||
|
|
extract::State,
|
||
|
|
response::Json,
|
||
|
|
routing::{get, post},
|
||
|
|
Router, Json as ResponseJson,
|
||
|
|
};
|
||
|
|
|
||
|
|
use crate::core::shared::state::AppState;
|
||
|
|
|
||
|
|
pub fn configure_deployment_routes() -> Router<Arc<AppState>> {
|
||
|
|
Router::new()
|
||
|
|
// Get deployment targets (internal vs external)
|
||
|
|
.route("/api/deployment/targets", get(get_deployment_targets))
|
||
|
|
|
||
|
|
// Deploy app
|
||
|
|
.route("/api/deployment/deploy", post(deploy_app))
|
||
|
|
|
||
|
|
// Get deployment status
|
||
|
|
.route("/api/deployment/status/:id", get(get_deployment_status))
|
||
|
|
|
||
|
|
// Forgejo repositories
|
||
|
|
.route("/api/deployment/forgejo/repos", get(list_forgejo_repos))
|
||
|
|
.route("/api/deployment/forgejo/create-repo", post(create_forgejo_repo))
|
||
|
|
|
||
|
|
// CI/CD workflows
|
||
|
|
.route("/api/deployment/forgejo/workflows", get(list_workflows))
|
||
|
|
.route("/api/deployment/forgejo/workflows/create", post(create_workflow))
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn get_deployment_targets(
|
||
|
|
State(_state): State<Arc<AppState>>,
|
||
|
|
) -> Json<serde_json::Value> {
|
||
|
|
Json(serde_json::json!({
|
||
|
|
"targets": [
|
||
|
|
{
|
||
|
|
"id": "internal",
|
||
|
|
"name": "GB Platform",
|
||
|
|
"description": "Deploy to the GB platform with shared resources",
|
||
|
|
"features": [
|
||
|
|
"Fast deployment",
|
||
|
|
"Shared authentication",
|
||
|
|
"Shared database",
|
||
|
|
"API integration",
|
||
|
|
"Instant scaling"
|
||
|
|
],
|
||
|
|
"icon": "📱"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "external",
|
||
|
|
"name": "Forgejo ALM",
|
||
|
|
"description": "Deploy to an external Forgejo repository with CI/CD",
|
||
|
|
"features": [
|
||
|
|
"Independent deployment",
|
||
|
|
"Custom domain",
|
||
|
|
"Version control",
|
||
|
|
"CI/CD pipelines",
|
||
|
|
"Separate infrastructure"
|
||
|
|
],
|
||
|
|
"icon": "🌐"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn deploy_app(
|
||
|
|
State(state): State<Arc<AppState>>,
|
||
|
|
ResponseJson(payload): ResponseJson<DeploymentRequest>,
|
||
|
|
) -> Result<Json<DeploymentResult>, DeploymentError> {
|
||
|
|
let router = state.deployment_router.clone();
|
||
|
|
|
||
|
|
let config = DeploymentConfig {
|
||
|
|
app_name: payload.app_name,
|
||
|
|
target: payload.target,
|
||
|
|
environment: payload.environment.unwrap_or(DeploymentEnvironment::Production),
|
||
|
|
};
|
||
|
|
|
||
|
|
let generated_app = generate_app_from_manifest(&payload.manifest).await?;
|
||
|
|
|
||
|
|
let result = router.deploy(config, generated_app).await?;
|
||
|
|
|
||
|
|
Ok(Json(result))
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub struct DeploymentRequest {
|
||
|
|
pub app_name: String,
|
||
|
|
pub target: DeploymentTarget,
|
||
|
|
pub environment: Option<DeploymentEnvironment>,
|
||
|
|
pub manifest: serde_json::Value,
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Estimated Effort:** 20-24 hours
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 0.3: Deployment UI in Vibe (P0 - CRITICAL)
|
||
|
|
|
||
|
|
**Goal:** Add deployment choice UI to Vibe Builder
|
||
|
|
|
||
|
|
**File:** `botui/ui/suite/partials/vibe-deployment.html`
|
||
|
|
|
||
|
|
```html
|
||
|
|
<!-- Deployment Choice Modal -->
|
||
|
|
<div class="deployment-modal" id="deploymentModal" style="display:none;">
|
||
|
|
<div class="deployment-modal-backdrop" onclick="closeDeploymentModal()"></div>
|
||
|
|
<div class="deployment-modal-content">
|
||
|
|
<div class="deployment-modal-header">
|
||
|
|
<h2>Choose Deployment Target</h2>
|
||
|
|
<button class="close-btn" onclick="closeDeploymentModal()">×</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="deployment-targets">
|
||
|
|
<!-- Internal GB Platform -->
|
||
|
|
<div class="deployment-target-card" onclick="selectDeploymentTarget('internal')">
|
||
|
|
<div class="target-icon">📱</div>
|
||
|
|
<div class="target-info">
|
||
|
|
<h3>GB Platform</h3>
|
||
|
|
<p>Deploy directly to the GB platform with shared resources</p>
|
||
|
|
<ul class="target-features">
|
||
|
|
<li>✓ Fast deployment</li>
|
||
|
|
<li>✓ Shared authentication</li>
|
||
|
|
<li>✓ Shared database</li>
|
||
|
|
<li>✓ API integration</li>
|
||
|
|
<li>✓ Instant scaling</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
<div class="target-status">Recommended for quick prototypes</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- External Forgejo -->
|
||
|
|
<div class="deployment-target-card" onclick="selectDeploymentTarget('external')">
|
||
|
|
<div class="target-icon">🌐</div>
|
||
|
|
<div class="target-info">
|
||
|
|
<h3>Forgejo ALM</h3>
|
||
|
|
<p>Deploy to an external Forgejo repository with full CI/CD</p>
|
||
|
|
<ul class="target-features">
|
||
|
|
<li>✓ Independent deployment</li>
|
||
|
|
<li>✓ Custom domain</li>
|
||
|
|
<li>✓ Version control</li>
|
||
|
|
<li>✓ CI/CD pipelines</li>
|
||
|
|
<li>✓ Separate infrastructure</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
<div class="target-status">Best for production apps</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Forgejo Configuration (shown when external selected) -->
|
||
|
|
<div id="forgejoConfig" class="forgejo-config" style="display:none;">
|
||
|
|
<h3>Forgejo Configuration</h3>
|
||
|
|
<form id="forgejoConfigForm">
|
||
|
|
<div class="form-group">
|
||
|
|
<label>Repository Name</label>
|
||
|
|
<input type="text" id="repoName" placeholder="my-crm-app" required />
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label>Custom Domain (Optional)</label>
|
||
|
|
<input type="text" id="customDomain" placeholder="crm.example.com" />
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label>
|
||
|
|
<input type="checkbox" id="ciCdEnabled" checked />
|
||
|
|
Enable CI/CD Pipeline
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label>Build Environment</label>
|
||
|
|
<select id="buildEnv">
|
||
|
|
<option value="production">Production</option>
|
||
|
|
<option value="staging">Staging</option>
|
||
|
|
<option value="development">Development</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Internal Configuration (shown when internal selected) -->
|
||
|
|
<div id="internalConfig" class="internal-config" style="display:none;">
|
||
|
|
<h3>Internal Deployment Configuration</h3>
|
||
|
|
<form id="internalConfigForm">
|
||
|
|
<div class="form-group">
|
||
|
|
<label>App Route</label>
|
||
|
|
<input type="text" id="appRoute" placeholder="/apps/my-crm" required />
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label>
|
||
|
|
<input type="checkbox" id="sharedDb" checked />
|
||
|
|
Use Shared Database
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label>
|
||
|
|
<input type="checkbox" id="sharedAuth" checked />
|
||
|
|
Use GB Authentication
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="deployment-actions">
|
||
|
|
<button class="btn-cancel" onclick="closeDeploymentModal()">Cancel</button>
|
||
|
|
<button class="btn-deploy" onclick="confirmDeployment()">Deploy App</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
.deployment-modal {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
bottom: 0;
|
||
|
|
z-index: 1000;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-modal-backdrop {
|
||
|
|
position: absolute;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
bottom: 0;
|
||
|
|
background: rgba(0, 0, 0, 0.6);
|
||
|
|
backdrop-filter: blur(4px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-modal-content {
|
||
|
|
position: relative;
|
||
|
|
background: var(--surface, #fff);
|
||
|
|
border-radius: 16px;
|
||
|
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||
|
|
max-width: 800px;
|
||
|
|
width: 90%;
|
||
|
|
max-height: 90vh;
|
||
|
|
overflow-y: auto;
|
||
|
|
padding: 32px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-modal-header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
margin-bottom: 24px;
|
||
|
|
padding-bottom: 16px;
|
||
|
|
border-bottom: 1px solid var(--border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-modal-header h2 {
|
||
|
|
margin: 0;
|
||
|
|
font-size: 24px;
|
||
|
|
font-weight: 700;
|
||
|
|
color: var(--text);
|
||
|
|
}
|
||
|
|
|
||
|
|
.close-btn {
|
||
|
|
background: none;
|
||
|
|
border: none;
|
||
|
|
font-size: 32px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
cursor: pointer;
|
||
|
|
padding: 0;
|
||
|
|
width: 32px;
|
||
|
|
height: 32px;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
border-radius: 8px;
|
||
|
|
transition: background 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.close-btn:hover {
|
||
|
|
background: var(--surface-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-targets {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
|
|
gap: 16px;
|
||
|
|
margin-bottom: 24px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-target-card {
|
||
|
|
border: 2px solid var(--border);
|
||
|
|
border-radius: 12px;
|
||
|
|
padding: 24px;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.2s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-target-card:hover {
|
||
|
|
border-color: var(--accent);
|
||
|
|
box-shadow: 0 4px 12px rgba(132, 214, 105, 0.2);
|
||
|
|
transform: translateY(-2px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-target-card.selected {
|
||
|
|
border-color: var(--accent);
|
||
|
|
background: rgba(132, 214, 105, 0.05);
|
||
|
|
}
|
||
|
|
|
||
|
|
.target-icon {
|
||
|
|
font-size: 48px;
|
||
|
|
margin-bottom: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.target-info h3 {
|
||
|
|
margin: 0 0 8px 0;
|
||
|
|
font-size: 18px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--text);
|
||
|
|
}
|
||
|
|
|
||
|
|
.target-info p {
|
||
|
|
margin: 0 0 12px 0;
|
||
|
|
font-size: 14px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
line-height: 1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
.target-features {
|
||
|
|
list-style: none;
|
||
|
|
padding: 0;
|
||
|
|
margin: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.target-features li {
|
||
|
|
padding: 4px 0;
|
||
|
|
font-size: 13px;
|
||
|
|
color: var(--text);
|
||
|
|
}
|
||
|
|
|
||
|
|
.target-status {
|
||
|
|
margin-top: 12px;
|
||
|
|
padding: 6px 12px;
|
||
|
|
background: var(--surface-hover);
|
||
|
|
border-radius: 6px;
|
||
|
|
font-size: 12px;
|
||
|
|
font-weight: 500;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.forgejo-config,
|
||
|
|
.internal-config {
|
||
|
|
padding: 24px;
|
||
|
|
background: var(--surface-hover);
|
||
|
|
border-radius: 12px;
|
||
|
|
margin-bottom: 24px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.form-group {
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.form-group label {
|
||
|
|
display: block;
|
||
|
|
margin-bottom: 6px;
|
||
|
|
font-weight: 500;
|
||
|
|
font-size: 14px;
|
||
|
|
color: var(--text);
|
||
|
|
}
|
||
|
|
|
||
|
|
.form-group input[type="text"],
|
||
|
|
.form-group select {
|
||
|
|
width: 100%;
|
||
|
|
padding: 10px 14px;
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
border-radius: 8px;
|
||
|
|
font-size: 14px;
|
||
|
|
transition: border-color 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.form-group input:focus,
|
||
|
|
.form-group select:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: var(--accent);
|
||
|
|
}
|
||
|
|
|
||
|
|
.deployment-actions {
|
||
|
|
display: flex;
|
||
|
|
justify-content: flex-end;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-cancel {
|
||
|
|
padding: 10px 24px;
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
border-radius: 8px;
|
||
|
|
background: transparent;
|
||
|
|
font-size: 14px;
|
||
|
|
font-weight: 500;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-cancel:hover {
|
||
|
|
background: var(--surface-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-deploy {
|
||
|
|
padding: 10px 24px;
|
||
|
|
border: none;
|
||
|
|
border-radius: 8px;
|
||
|
|
background: var(--accent);
|
||
|
|
color: var(--bg, #fff);
|
||
|
|
font-size: 14px;
|
||
|
|
font-weight: 600;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-deploy:hover {
|
||
|
|
background: var(--accent-hover);
|
||
|
|
transform: translateY(-1px);
|
||
|
|
box-shadow: 0 4px 12px rgba(132, 214, 105, 0.3);
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
let selectedTarget = null;
|
||
|
|
|
||
|
|
function openDeploymentModal() {
|
||
|
|
document.getElementById('deploymentModal').style.display = 'flex';
|
||
|
|
selectedTarget = null;
|
||
|
|
document.querySelectorAll('.deployment-target-card').forEach(card => {
|
||
|
|
card.classList.remove('selected');
|
||
|
|
});
|
||
|
|
document.getElementById('forgejoConfig').style.display = 'none';
|
||
|
|
document.getElementById('internalConfig').style.display = 'none';
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeDeploymentModal() {
|
||
|
|
document.getElementById('deploymentModal').style.display = 'none';
|
||
|
|
}
|
||
|
|
|
||
|
|
function selectDeploymentTarget(target) {
|
||
|
|
selectedTarget = target;
|
||
|
|
document.querySelectorAll('.deployment-target-card').forEach(card => {
|
||
|
|
card.classList.remove('selected');
|
||
|
|
});
|
||
|
|
event.currentTarget.classList.add('selected');
|
||
|
|
|
||
|
|
if (target === 'external') {
|
||
|
|
document.getElementById('forgejoConfig').style.display = 'block';
|
||
|
|
document.getElementById('internalConfig').style.display = 'none';
|
||
|
|
} else {
|
||
|
|
document.getElementById('forgejoConfig').style.display = 'none';
|
||
|
|
document.getElementById('internalConfig').style.display = 'block';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function confirmDeployment() {
|
||
|
|
if (!selectedTarget) {
|
||
|
|
alert('Please select a deployment target');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const manifest = getCurrentManifest(); // Get from Vibe canvas
|
||
|
|
|
||
|
|
let payload = {
|
||
|
|
app_name: document.getElementById('repoName')?.value || document.getElementById('appRoute')?.value?.replace('/apps/', ''),
|
||
|
|
target: {},
|
||
|
|
environment: document.getElementById('buildEnv')?.value || 'production',
|
||
|
|
manifest: manifest
|
||
|
|
};
|
||
|
|
|
||
|
|
if (selectedTarget === 'external') {
|
||
|
|
payload.target = {
|
||
|
|
External: {
|
||
|
|
repo_url: `https://forgejo.example.com/${payload.app_name}`,
|
||
|
|
custom_domain: document.getElementById('customDomain')?.value || null,
|
||
|
|
ci_cd_enabled: document.getElementById('ciCdEnabled')?.checked ?? true
|
||
|
|
}
|
||
|
|
};
|
||
|
|
} else {
|
||
|
|
payload.target = {
|
||
|
|
Internal: {
|
||
|
|
route: document.getElementById('appRoute')?.value || `/apps/${payload.app_name}`,
|
||
|
|
shared_resources: true
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const response = await fetch('/api/deployment/deploy', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify(payload)
|
||
|
|
});
|
||
|
|
|
||
|
|
const result = await response.json();
|
||
|
|
|
||
|
|
if (result.status === 'Deployed') {
|
||
|
|
closeDeploymentModal();
|
||
|
|
showDeploymentSuccess(result);
|
||
|
|
} else {
|
||
|
|
alert('Deployment failed: ' + result.status);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
alert('Deployment error: ' + e.message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function showDeploymentSuccess(result) {
|
||
|
|
const modal = document.getElementById('deploymentModal');
|
||
|
|
modal.innerHTML = `
|
||
|
|
<div class="deployment-success">
|
||
|
|
<div class="success-icon">✅</div>
|
||
|
|
<h2>Deployment Successful!</h2>
|
||
|
|
<p>Your app is now deployed at:</p>
|
||
|
|
<a href="${result.url}" target="_blank" class="deployment-url">${result.url}</a>
|
||
|
|
<button onclick="location.reload()" class="btn-close">Close</button>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
```
|
||
|
|
|
||
|
|
**Integration into Vibe:**
|
||
|
|
```javascript
|
||
|
|
// In vibe.html, add deployment button to the canvas header:
|
||
|
|
|
||
|
|
<div class="vibe-canvas-header">
|
||
|
|
<span>// DASHBOARD > // ${currentProject}</span>
|
||
|
|
<button class="vibe-deploy-btn" onclick="openDeploymentModal()">
|
||
|
|
🚀 Deploy
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
```
|
||
|
|
|
||
|
|
**Estimated Effort:** 8-10 hours
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part II: Remaining Feature Implementation (Phases 1-7)
|
||
|
|
|
||
|
|
After deployment infrastructure is in place, continue with the original plan:
|
||
|
|
|
||
|
|
### Phase 1: Code Editor Integration (P0 - Critical)
|
||
|
|
*(Same as original TASK.md - Monaco Editor)*
|
||
|
|
|
||
|
|
### Phase 2: Database UI & Schema Visualization (P0 - Critical)
|
||
|
|
*(Same as original TASK.md)*
|
||
|
|
|
||
|
|
### Phase 3: Git Operations UI (P1 - High Priority)
|
||
|
|
**UPDATED:** Add Forgejo-specific git operations
|
||
|
|
- View Forgejo repository status
|
||
|
|
- Sync with Forgejo remote
|
||
|
|
- View CI/CD pipeline status
|
||
|
|
- Trigger manual builds
|
||
|
|
|
||
|
|
### Phase 4: Browser Automation Engine (P1 - High Priority)
|
||
|
|
*(Same as original TASK.md)*
|
||
|
|
|
||
|
|
### Phase 5: Multi-File Editing Workspace (P2 - Medium Priority)
|
||
|
|
*(Same as original TASK.md)*
|
||
|
|
|
||
|
|
### Phase 6: Enhanced Terminal (P2 - Medium Priority)
|
||
|
|
*(Same as original TASK.md)*
|
||
|
|
|
||
|
|
### Phase 7: Advanced CRM Templates (P2 - Medium Priority)
|
||
|
|
**UPDATED:** Templates should support both deployment models
|
||
|
|
- Internal deployment templates (use GB APIs)
|
||
|
|
- External deployment templates (standalone with CI/CD)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part III: Updated Rollout Plan
|
||
|
|
|
||
|
|
### Milestone 0: Deployment Infrastructure (Week 0)
|
||
|
|
- **Day 1-3:** Phase 0.1 - Deployment Router
|
||
|
|
- **Day 4-5:** Phase 0.2 - Forgejo Integration
|
||
|
|
- **Day 6-7:** Phase 0.3 - Deployment UI
|
||
|
|
|
||
|
|
**Success Criteria:**
|
||
|
|
- ✅ Can deploy app internally to /apps/{name}
|
||
|
|
- ✅ Can deploy app externally to Forgejo
|
||
|
|
- ✅ CI/CD pipeline auto-generated
|
||
|
|
- ✅ Deployment choice works in Vibe UI
|
||
|
|
|
||
|
|
### Milestone 1-7: (Weeks 1-4)
|
||
|
|
*(Same as original TASK.md)*
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part IV: Technical Implementation Notes
|
||
|
|
|
||
|
|
### File Organization (UPDATED)
|
||
|
|
|
||
|
|
**Botserver (Backend):**
|
||
|
|
```
|
||
|
|
botserver/src/
|
||
|
|
deployment/ # NEW - Deployment infrastructure
|
||
|
|
mod.rs # DeploymentRouter
|
||
|
|
forgejo.rs # ForgejoClient
|
||
|
|
api.rs # Deployment API endpoints
|
||
|
|
templates.rs # CI/CD workflow templates
|
||
|
|
api/
|
||
|
|
editor.rs
|
||
|
|
database.rs
|
||
|
|
git.rs # UPDATED - Add Forgejo git operations
|
||
|
|
browser/
|
||
|
|
mod.rs
|
||
|
|
recorder.rs
|
||
|
|
validator.rs
|
||
|
|
api.rs
|
||
|
|
test_generator.rs
|
||
|
|
templates/
|
||
|
|
crm/
|
||
|
|
sales.json
|
||
|
|
real_estate.json
|
||
|
|
healthcare.json
|
||
|
|
mod.rs
|
||
|
|
sources/ # EXISTING - MCP integration
|
||
|
|
mod.rs
|
||
|
|
mcp.rs
|
||
|
|
ui.rs
|
||
|
|
knowledge_base.rs
|
||
|
|
```
|
||
|
|
|
||
|
|
**Botui (Frontend):**
|
||
|
|
```
|
||
|
|
botui/ui/suite/
|
||
|
|
partials/
|
||
|
|
vibe.html # UPDATED - Add deploy button
|
||
|
|
vibe-deployment.html # NEW - Deployment modal
|
||
|
|
editor.html
|
||
|
|
database.html
|
||
|
|
git-status.html # UPDATED - Add Forgejo status
|
||
|
|
git-diff.html
|
||
|
|
browser-controls.html
|
||
|
|
terminal.html
|
||
|
|
template-gallery.html
|
||
|
|
js/
|
||
|
|
deployment.js # NEW - Deployment logic
|
||
|
|
editor.js
|
||
|
|
database.js
|
||
|
|
git.js # UPDATED - Add Forgejo operations
|
||
|
|
browser.js
|
||
|
|
terminal.js
|
||
|
|
templates.js
|
||
|
|
css/
|
||
|
|
deployment.css # NEW - Deployment styles
|
||
|
|
editor.css
|
||
|
|
database.css
|
||
|
|
git.css
|
||
|
|
browser.css
|
||
|
|
terminal.css
|
||
|
|
templates.css
|
||
|
|
```
|
||
|
|
|
||
|
|
### Dependencies (UPDATED)
|
||
|
|
|
||
|
|
**Already in Workspace:**
|
||
|
|
```toml
|
||
|
|
[dependencies]
|
||
|
|
chromiumoxide = "0.7" # Browser automation
|
||
|
|
tokio = "1.41" # Async runtime
|
||
|
|
axum = "0.7" # HTTP framework
|
||
|
|
diesel = "2.1" # Database
|
||
|
|
git2 = "0.18" # Git operations
|
||
|
|
reqwest = { version = "0.11", features = ["json"] } # HTTP client
|
||
|
|
```
|
||
|
|
|
||
|
|
**Frontend:**
|
||
|
|
```
|
||
|
|
monaco-editor@0.45.0 # Code editor
|
||
|
|
xterm.js@5.3.0 # Terminal (already vendor file)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part V: Success Metrics (UPDATED)
|
||
|
|
|
||
|
|
### Deployment Infrastructure
|
||
|
|
- ✅ Internal deployment succeeds in < 30 seconds
|
||
|
|
- ✅ External Forgejo deployment succeeds in < 2 minutes
|
||
|
|
- ✅ CI/CD pipeline auto-generates correctly
|
||
|
|
- ✅ Both deployment models accessible from Vibe UI
|
||
|
|
- ✅ Can switch between internal/external deployment
|
||
|
|
|
||
|
|
### Phases 1-7
|
||
|
|
*(Same as original TASK.md)*
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Conclusion
|
||
|
|
|
||
|
|
The **critical gap** in the original TASK.md was the **deployment routing logic**. The platform must support:
|
||
|
|
|
||
|
|
1. **Internal GB Apps** - Quick prototypes using GB APIs and shared resources
|
||
|
|
2. **External Forgejo Projects** - Production apps with independent infrastructure and CI/CD
|
||
|
|
|
||
|
|
**Updated Priority:**
|
||
|
|
1. ⚠️ **Phase 0** - Deployment Infrastructure (CRITICAL - Week 0)
|
||
|
|
- Phase 0.1: Deployment Router
|
||
|
|
- Phase 0.2: Forgejo Integration
|
||
|
|
- Phase 0.3: Deployment UI
|
||
|
|
|
||
|
|
2. 📝 **Phase 1** - Code Editor (Week 1)
|
||
|
|
|
||
|
|
3. 🗄️ **Phase 2** - Database UI (Week 2)
|
||
|
|
|
||
|
|
4. 🐙 **Phase 3** - Git Operations + Forgejo (Week 2)
|
||
|
|
|
||
|
|
5. 🌐 **Phase 4** - Browser Automation (Week 3)
|
||
|
|
|
||
|
|
6. 📂 **Phase 5** - Multi-File Workspace (Week 3)
|
||
|
|
|
||
|
|
7. 🖥️ **Phase 6** - Terminal (Week 4)
|
||
|
|
|
||
|
|
8. 📇 **Phase 7** - CRM Templates (Week 4)
|
||
|
|
|
||
|
|
Once Phase 0 is complete, VibeCode will be able to **deploy apps both internally and externally**, giving users the flexibility to choose the right deployment model for their use case.
|
||
|
|
|
||
|
|
**Total Estimated Effort:** 125-155 hours (~3-4 weeks with 1 developer)
|
||
|
|
**Including Phase 0:** +40-50 hours
|
||
|
|
|
||
|
|
**Final Total:** 165-205 hours (~4-5 weeks with 1 developer)
|