diff --git a/backend/diagnose-server.sh b/backend/diagnose-server.sh deleted file mode 100755 index 1e19785..0000000 --- a/backend/diagnose-server.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -echo "==========================================" -echo "Backend Diagnostic Script for 10.0.10.30" -echo "==========================================" -echo "" - -echo "1. Checking Docker containers..." -docker ps --filter "name=normogen" --format "table {{.Names}} {{.Status}} {{.Ports}}" -echo "" - -echo "2. Checking if port 6500 is listening..." -sudo ss -tlnp | grep 6500 || echo "Port 6500 NOT listening" -echo "" - -echo "3. Checking firewall status..." -sudo ufw status || echo "UFW not installed" -echo "" - -echo "4. Checking Docker network..." -docker network ls | grep normogen -echo "" - -echo "5. Backend container logs (last 20 lines)..." -docker logs --tail 20 normogen-backend-dev 2>&1 -echo "" - -echo "6. Testing local connection..." -curl -s --max-time 3 http://localhost:6500/health || echo "Local connection failed" -echo "" - -echo "7. Testing container connection..." -docker exec normogen-backend-dev curl -s --max-time 3 http://localhost:8000/health || echo "Container connection failed" -echo "" - -echo "==========================================" -echo "Diagnostic complete" -echo "==========================================" diff --git a/backend/docker-compose.dev.yml b/backend/docker-compose.dev.yml index b21c00a..54c73e1 100644 --- a/backend/docker-compose.dev.yml +++ b/backend/docker-compose.dev.yml @@ -11,6 +11,7 @@ services: - '6500:8000' volumes: - ./src:/app/src + # Mount a volume to capture logs - startup-logs:/tmp environment: - RUST_LOG=debug @@ -25,8 +26,8 @@ services: condition: service_healthy networks: - normogen-network - restart: unless-stopped - + # DISABLE RESTART TEMPORARILY TO DEBUG + restart: "no" mongodb: image: mongo:6.0 container_name: normogen-mongodb-dev @@ -46,14 +47,11 @@ services: timeout: 5s retries: 5 start_period: 60s - restart: unless-stopped - volumes: mongodb_dev_data: driver: local startup-logs: driver: local - networks: normogen-network: driver: bridge diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index ce883ce..7cbe40d 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -3,46 +3,51 @@ services: build: context: . dockerfile: docker/Dockerfile - args: - BUILDKIT_INLINE_CACHE: 0 - pull_policy: build container_name: normogen-backend ports: - - '8000:8000' + - '6800:8000' environment: - RUST_LOG=info - SERVER_PORT=8000 - - SERVER_HOST=0.0.0.0 - MONGODB_URI=mongodb://mongodb:27017 - - MONGODB_DATABASE=normogen - - JWT_SECRET=${JWT_SECRET:-please-change-this-in-production} + - DATABASE_NAME=normogen + env_file: + - .env depends_on: mongodb: condition: service_healthy networks: - normogen-network restart: unless-stopped - # Disable DNS search domain to fix hostname resolution - dns_search: [] + deploy: + resources: + limits: + cpus: '1.0' + memory: 1000M + healthcheck: + test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:8000/health'] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s mongodb: image: mongo:6.0 container_name: normogen-mongodb + ports: + - '27017:27017' environment: - MONGO_INITDB_DATABASE=normogen volumes: - mongodb_data:/data/db networks: - normogen-network - healthcheck: - test: | - echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet - interval: 30s - timeout: 10s - retries: 5 - start_period: 40s restart: unless-stopped - # Disable DNS search domain to fix hostname resolution - dns_search: [] + healthcheck: + test: ['CMD', 'mongosh', '--eval', 'db.adminCommand.ping()'] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s volumes: mongodb_data: driver: local diff --git a/backend/src/db/mongodb_impl.rs b/backend/src/db/mongodb_impl.rs index efe044e..00a7826 100644 --- a/backend/src/db/mongodb_impl.rs +++ b/backend/src/db/mongodb_impl.rs @@ -21,71 +21,25 @@ impl MongoDb { eprintln!("[MongoDB] Starting connection to: {}", uri); // Parse the URI first - let mut client_options = match ClientOptions::parse(uri).await { - Ok(opts) => { - eprintln!("[MongoDB] URI parsed successfully"); - opts - } - Err(e) => { - eprintln!("[MongoDB] ERROR: Failed to parse URI: {}", e); - - let error_msg = e.to_string().to_lowercase(); - if error_msg.contains("dns") || error_msg.contains("resolution") || error_msg.contains("lookup") { - eprintln!("[MongoDB] DNS RESOLUTION ERROR DETECTED!"); - eprintln!("[MongoDB] Cannot resolve hostname in: {}", uri); - eprintln!("[MongoDB] Error: {}", e); - } - eprintln!("[MongoDB] Will continue in degraded mode (database operations will fail)"); - - // Create a minimal configuration that will allow the server to start - // but database operations will fail gracefully - let mut opts = ClientOptions::parse("mongodb://localhost:27017").await - .map_err(|e| anyhow::anyhow!("Failed to create fallback client options: {}", e))?; - opts.server_selection_timeout = Some(Duration::from_secs(1)); - opts.connect_timeout = Some(Duration::from_secs(1)); - - let client = Client::with_options(opts) - .map_err(|e| anyhow::anyhow!("Failed to create MongoDB client: {}", e))?; - - let database = client.database(db_name); - - return Ok(Self { - users: database.collection("users"), - shares: database.collection("shares"), - database, - }); - } - }; + let mut client_options = ClientOptions::parse(uri).await + .map_err(|e| { + eprintln!("[MongoDB] Failed to parse URI: {}", e); + anyhow::anyhow!("Failed to parse MongoDB URI: {}", e) + })?; - // Set connection timeout with retry logic - client_options.server_selection_timeout = Some(Duration::from_secs(10)); - client_options.connect_timeout = Some(Duration::from_secs(10)); + eprintln!("[MongoDB] URI parsed successfully"); + + // Set connection timeout + client_options.server_selection_timeout = Some(Duration::from_secs(5)); + client_options.connect_timeout = Some(Duration::from_secs(5)); eprintln!("[MongoDB] Connecting to server..."); - let client = match Client::with_options(client_options) { - Ok(c) => { - eprintln!("[MongoDB] Client created successfully"); - c - } - Err(e) => { - eprintln!("[MongoDB] ERROR: Failed to create client: {}", e); - eprintln!("[MongoDB] Will continue in degraded mode"); - - // Create a fallback client - let fallback_opts = ClientOptions::parse("mongodb://localhost:27017").await - .map_err(|e| anyhow::anyhow!("Failed to create fallback client options: {}", e))?; - let fallback_client = Client::with_options(fallback_opts) - .map_err(|e| anyhow::anyhow!("Failed to create MongoDB client: {}", e))?; - let database = fallback_client.database(db_name); - - return Ok(Self { - users: database.collection("users"), - shares: database.collection("shares"), - database, - }); - } - }; + let client = Client::with_options(client_options) + .map_err(|e| { + eprintln!("[MongoDB] Failed to create client: {}", e); + anyhow::anyhow!("Failed to create MongoDB client: {}", e) + })?; eprintln!("[MongoDB] Client created, selecting database..."); @@ -102,18 +56,9 @@ impl MongoDb { pub async fn health_check(&self) -> Result { eprintln!("[MongoDB] Health check: pinging database..."); - match self.database.run_command(doc! { "ping": 1 }, None).await { - Ok(_) => { - eprintln!("[MongoDB] Health check: OK"); - Ok("OK".to_string()) - } - Err(e) => { - eprintln!("[MongoDB] Health check: FAILED - {}", e); - // Return OK anyway to allow the server to continue running - // The actual database operations will fail when needed - Ok("DEGRADED".to_string()) - } - } + self.database.run_command(doc! { "ping": 1 }, None).await?; + eprintln!("[MongoDB] Health check: OK"); + Ok("OK".to_string()) } // ===== User Methods ===== diff --git a/backend/src/main.rs b/backend/src/main.rs index 6eda459..12ed1f7 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,128 +1,28 @@ -mod config; -mod db; -mod models; -mod auth; -mod handlers; -mod middleware; +use std::fs::OpenOptions; +use std::io::Write; -use axum::{ - routing::{get, post, put, delete}, - Router, - middleware as axum_middleware, -}; -use tower::ServiceBuilder; -use tower_http::{ - cors::CorsLayer, - trace::TraceLayer, -}; -use config::Config; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - eprintln!("NORMOGEN BACKEND STARTING..."); - eprintln!("Loading environment variables..."); +fn main() { + let msg = format!("BINARY STARTED: {}\n", chrono::Utc::now().to_rfc3339()); - match dotenv::dotenv() { - Ok(path) => eprintln!("Loaded .env from: {:?}", path), - Err(e) => eprintln!("No .env file found (this is OK in Docker): {}", e), + // Try to write to file + if let Ok(mut file) = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open("/tmp/test-startup.log") + { + let _ = file.write_all(msg.as_bytes()); + let _ = file.flush(); } - eprintln!("Initializing logging..."); - tracing_subscriber::fmt() - .with_env_filter( - tracing_subscriber::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| "normogen_backend=debug,tower_http=debug,axum=debug".into()) - ) - .init(); + // Try to print to stdout + println!("BINARY STARTED"); + let _ = std::io::stdout().flush(); - eprintln!("Loading configuration..."); - let config = match Config::from_env() { - Ok(cfg) => { - tracing::info!("Configuration loaded successfully"); - eprintln!("Config loaded: DB={}, Port={}", cfg.database.database, cfg.server.port); - cfg - } - Err(e) => { - eprintln!("FATAL: Failed to load configuration: {}", e); - return Err(e); - } - }; + // Try to print to stderr + eprintln!("BINARY STARTED (stderr)"); + let _ = std::io::stderr().flush(); - tracing::info!("Connecting to MongoDB at {}", config.database.uri); - eprintln!("Connecting to MongoDB..."); - let db = match db::MongoDb::new(&config.database.uri, &config.database.database).await { - Ok(db) => { - tracing::info!("Connected to MongoDB database: {}", config.database.database); - eprintln!("MongoDB connection successful"); - db - } - Err(e) => { - eprintln!("FATAL: Failed to connect to MongoDB: {}", e); - return Err(e); - } - }; - - tracing::info!("MongoDB health check: {}", db.health_check().await?); - - let jwt_service = auth::JwtService::new(config.jwt.clone()); - - let app_state = config::AppState { - db, - jwt_service, - config: config.clone(), - }; - - eprintln!("Building router..."); - - let public_routes = Router::new() - .route("/health", get(handlers::health_check)) - .route("/ready", get(handlers::ready_check)) - .route("/api/auth/register", post(handlers::register)) - .route("/api/auth/login", post(handlers::login)) - .route("/api/auth/recover-password", post(handlers::recover_password)) - .layer( - ServiceBuilder::new() - .layer(TraceLayer::new_for_http()) - .layer(CorsLayer::new()) - ); - - let protected_routes = Router::new() - // Profile management - .route("/api/users/me", get(handlers::get_profile)) - .route("/api/users/me", put(handlers::update_profile)) - .route("/api/users/me", delete(handlers::delete_account)) - // Account settings - .route("/api/users/me/settings", get(handlers::get_settings)) - .route("/api/users/me/settings", put(handlers::update_settings)) - .route("/api/users/me/change-password", post(handlers::change_password)) - // Share management (Phase 2.5) - .route("/api/shares", post(handlers::create_share)) - .route("/api/shares", get(handlers::list_shares)) - .route("/api/shares/:id", get(handlers::get_share)) - .route("/api/shares/:id", put(handlers::update_share)) - .route("/api/shares/:id", delete(handlers::delete_share)) - // Permissions (Phase 2.5) - .route("/api/permissions/check", post(handlers::check_permission)) - .layer( - ServiceBuilder::new() - .layer(TraceLayer::new_for_http()) - .layer(CorsLayer::new()) - ) - .route_layer(axum_middleware::from_fn_with_state( - app_state.clone(), - crate::middleware::auth::jwt_auth_middleware - )); - - let app = public_routes.merge(protected_routes).with_state(app_state); - - eprintln!("Binding to {}:{}...", config.server.host, config.server.port); - let listener = tokio::net::TcpListener::bind(&format!("{}:{}", config.server.host, config.server.port)) - .await?; - - tracing::info!("Server listening on {}:{}", config.server.host, config.server.port); - eprintln!("Server is running on http://{}:{}", config.server.host, config.server.port); - - axum::serve(listener, app).await?; - - Ok(()) + // Sleep to keep container alive + std::thread::sleep(std::time::Duration::from_secs(60)); } diff --git a/backend/src/main.rs.restore b/backend/src/main.rs.restore deleted file mode 100644 index dc5d375..0000000 --- a/backend/src/main.rs.restore +++ /dev/null @@ -1,2 +0,0 @@ -fatal: path 'backend/src/main.rs' exists, but not 'src/main.rs' -hint: Did you mean 'a316699:backend/src/main.rs' aka 'a316699:./src/main.rs'? diff --git a/backend/start-dev.sh b/backend/start-dev.sh deleted file mode 100755 index 9d231f8..0000000 --- a/backend/start-dev.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -set -e - -echo "🚀 Starting Normogen Backend Development Environment..." -cd "$(dirname "$0")" - -# Build and start containers -echo "📦 Building and starting containers..." -docker-compose -f docker-compose.dev.yml up --build -d - -# Wait for MongoDB to be healthy -echo "⏳ Waiting for MongoDB to be healthy..." -timeout=60 -while [ $timeout -gt 0 ]; do - if docker inspect normogen-mongodb-dev --format='{{.State.Health.Status}}' | grep -q "healthy"; then - echo "✅ MongoDB is healthy!" - break - fi - sleep 2 - timeout=$((timeout - 2)) -done - -if [ $timeout -eq 0 ]; then - echo "❌ MongoDB health check timeout" - exit 1 -fi - -# Wait for backend to be ready -echo "⏳ Waiting for backend to start..." -timeout=30 -while [ $timeout -gt 0 ]; do - if curl -s http://localhost:6500/health > /dev/null 2>&1; then - echo "✅ Backend is ready!" - break - fi - sleep 2 - timeout=$((timeout - 2)) -done - -if [ $timeout -eq 0 ]; then - echo "⚠️ Backend may still be starting..." -fi - -echo "" -echo "🎉 Development environment is ready!" -echo "" -echo "📊 Services:" -docker-compose -f docker-compose.dev.yml ps -echo "" -echo "🔗 Backend: http://localhost:6500" -echo "🔗 MongoDB: mongodb://localhost:27017" -echo "" -echo "📝 To view logs:" -echo " docker-compose -f docker-compose.dev.yml logs -f" -echo "" -echo "🛑 To stop:" -echo " ./stop-dev.sh" diff --git a/backend/stop-dev.sh b/backend/stop-dev.sh deleted file mode 100755 index bf65c0d..0000000 --- a/backend/stop-dev.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e - -echo "🛑 Stopping Normogen Backend Development Environment..." -cd "$(dirname "$0")" - -docker-compose -f docker-compose.dev.yml down - -echo "✅ Development environment stopped!"