Skip to main content

System Architecture

AmbioSys follows a microservices architecture with clear separation of concerns. Each service is independently deployable, scalable, and maintainable.

Core Services

Backend API

Container: ambiotec-backendPort: 3000Technology: Express.js + Node.js 20Purpose: Main business logic and data management

WhatsApp Bot

Container: gpt4-ambiotec-botPort: 4500Technology: Express.js + OpenAI + Socket.IOPurpose: AI-powered customer conversations

Frontend

Container: (Development only)Port: 5173Technology: React 18 + Vite + Material-UIPurpose: User interface and interaction

Redis

Container: ambiotec-redisPort: 6379Technology: Redis 7 AlpinePurpose: Cache, sessions, job queues

Backend API Service

Service Structure

The backend API (Backend/web-ambiotec) is the core of AmbioSys, handling all business operations.
Backend/web-ambiotec/
├── src/
│   ├── app.js                 # Express app setup
│   ├── config/
│   │   ├── db.js             # PostgreSQL + Redis connections
│   │   └── constant.js       # Configuration constants
│   ├── middleware/
│   │   ├── auth.js           # JWT authentication
│   │   └── logApiUsage.js    # API usage logging
│   ├── routes/
│   │   ├── auth.js           # Login, register, sessions
│   │   ├── customer.js       # Customer management
│   │   ├── serviceRequests.js # Service request tracking
│   │   ├── quotations.js     # Quotation management
│   │   ├── credits.js        # Credit applications
│   │   ├── payments.js       # Payment processing
│   │   ├── whatsapp.js       # WhatsApp integration
│   │   ├── dashboard.js      # Analytics and metrics
│   │   └── ... (20+ more)
│   ├── controllers/          # Business logic
│   ├── services/             # External integrations
│   ├── jobs/
│   │   └── cronJobs.js       # Scheduled tasks
│   └── views/                # EJS templates
├── package.json
└── Dockerfile

Key Features

Implementation: src/middleware/auth.js
  • JWT-based authentication
  • Session management with Redis (connect-redis)
  • Role-based access control (RBAC)
  • Permission system with module-level granularity
// From src/middleware/auth.js
export const requireAuth = (req, res, next) => {
  if (!req.session?.user) {
    return res.status(401).json({ error: 'No autenticado' });
  }
  req.user = req.session.user;
  next();
};
Implementation: src/config/db.js
  • PostgreSQL connection pooling with retry logic
  • Configurable pool size (default 20 connections)
  • SSL support for cloud databases (AWS RDS)
  • Automatic reconnection with exponential backoff
  • Graceful shutdown handling
// From src/config/db.js
const pgPool = new Pool({
  host: constants.DB.PG_HOST,
  port: constants.DB.PG_PORT || 5432,
  user: constants.DB.PG_USER,
  password: constants.DB.PG_PASSWORD,
  database: constants.DB.PG_DATABASE_AMBIOTEC,
  max: parseInt(process.env.PG_POOL_MAX || '20', 10),
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 30000,
  ssl: { rejectUnauthorized: false }
});
Implementation: src/app.jsAll routes are protected with authentication and API usage logging:
// From src/app.js (lines 118-146)
app.use('/api', authRouter);
app.use('/api/customer', requireAuth, logApiUsage, customerRouter);
app.use('/api/user', requireAuth, logApiUsage, userRouter);
app.use('/api/serviceRequests', requireAuth, logApiUsage, serviceRequestRouter);
app.use('/api/quotations', requireAuth, logApiUsage, quotationRouter);
app.use('/api/credits', requireAuth, logApiUsage, creditsRouter);
app.use('/api/payments', requireAuth, logApiUsage, paymentsRouter);
app.use('/api/whatsapp', whatsappRouter); // Mixed public/protected
app.use('/api/dashboard', requireAuth, logApiUsage, dashboardRouter);
// ... 15+ more routes
Implementation: src/jobs/cronJobs.js
  • Quotation follow-up reminders
  • License expiration notifications
  • SLA deadline monitoring
  • Overdue service request alerts
Uses node-cron for scheduling and BullMQ for reliable job execution.

Key Dependencies

{
  "dependencies": {
    "express": "^4.21.2",
    "pg": "^8.10.0",
    "redis": "^4.6.5",
    "ioredis": "^5.8.2",
    "bullmq": "^5.66.4",
    "jsonwebtoken": "^9.0.0",
    "bcrypt": "^6.0.0",
    "express-session": "^1.17.3",
    "connect-redis": "^7.0.0",
    "@aws-sdk/client-s3": "^3.911.0",
    "openai": "^4.104.0",
    "axios": "^1.13.2",
    "nodemailer": "^7.0.6",
    "puppeteer": "^23.11.1",
    "node-cron": "^3.0.3",
    "swagger-jsdoc": "^6.2.8",
    "swagger-ui-express": "^5.0.1"
  }
}

WhatsApp Bot Service

Service Structure

The WhatsApp bot (Backend/gpt4-ambiotec-bot) provides AI-powered customer support.
Backend/gpt4-ambiotec-bot/
├── src/
│   ├── app.js                # Express + Socket.IO setup
│   ├── routes/
│   │   └── webhook.js        # WhatsApp webhook handlers
│   ├── controllers/
│   │   └── webhookController.js  # Message processing
│   ├── services/
│   │   └── openai.js         # GPT-4 integration
│   └── config/
│       └── db.js             # Database connections
├── package.json
└── Dockerfile

Real-Time Architecture

1

WhatsApp Message Received

Meta’s WhatsApp Business API sends a POST request to /webhook:
POST http://your-domain:4500/webhook
{
  "entry": [{
    "changes": [{
      "value": {
        "messages": [{
          "from": "50370123456",
          "text": { "body": "Necesito ayuda con mi cotización" }
        }]
      }
    }]
  }]
}
2

Message Processing

The webhook controller:
  1. Validates the request signature
  2. Extracts message content and sender
  3. Retrieves conversation context from Redis
  4. Queries customer data from PostgreSQL
3

GPT-4 Response Generation

Context is sent to OpenAI:
const completion = await openai.chat.completions.create({
  model: "gpt-4",
  messages: [
    { role: "system", content: "You are a helpful Ambiotec assistant..." },
    ...conversationHistory,
    { role: "user", content: userMessage }
  ]
});
4

Real-Time Broadcast

Response is sent via Socket.IO to all connected clients:
// From src/app.js (line 56)
io.emit("chat:new-message-chatweb", response);
And also sent back to WhatsApp via Meta’s API.

Socket.IO Events

Emitted by: Frontend (internal team chat)Handled by: Bot service
// From src/app.js (lines 52-57)
socket.on("chat:send-message", async (data) => {
  console.log("📩 Mensaje recibido:", data);
  const response = await handleWebhook(data);
  io.emit("chat:new-message-chatweb", response);
});
Emitted by: Frontend (customer-facing web chat)Handled by: Bot service with GPT-4 processing
// From src/app.js (lines 60-65)
socket.on("chat:send-message-chatweb", async(data) => {
  console.log("📩 Mensaje recibido desde chat web:", data);
  const response = await handleWebhook(data);
  io.emit("chat:new-message-chatweb", response);
});

Frontend Application

Technology Stack

{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.30.1",
    "@mui/material": "^7.2.0",
    "@mui/icons-material": "^7.2.0",
    "@mui/x-data-grid": "^8.9.1",
    "@mui/x-date-pickers": "^8.9.0",
    "axios": "^1.10.0",
    "socket.io-client": "^4.8.1",
    "react-hook-form": "^7.61.1",
    "yup": "^1.6.1",
    "react-hot-toast": "^2.5.2",
    "dayjs": "^1.11.13",
    "framer-motion": "^12.23.3"
  },
  "devDependencies": {
    "vite": "^7.0.4",
    "@vitejs/plugin-react": "^4.0.0",
    "tailwindcss": "^4.1.11"
  }
}

Context Architecture

The frontend uses React Context for state management:
// From src/main.jsx (lines 48-60)
ReactDOM.createRoot(document.getElementById('root')).render(
  <AuthProvider>
    <PermissionProvider>
      <NotificationsProvider>
        <ThemeModeProvider>
          <ThemedApp />
        </ThemeModeProvider>
      </NotificationsProvider>
    </PermissionProvider>
  </AuthProvider>
);

AuthContext

User authentication state, login/logout, token management

PermissionContext

Role-based UI rendering, feature flags, module access

NotificationsContext

Real-time notification management and display

ThemeModeContext

Dark/light theme toggle with Material-UI integration

Data Flow

Example: Creating a Service Request

1

User Submits Form

Frontend sends POST request:
POST /api/serviceRequests
Authorization: Bearer <jwt-token>

{
  "customer_id": 123,
  "service_type_id": 2,
  "description": "Necesito mantenimiento de PTAR",
  "requested_delivery_date": "2026-03-15",
  "priority": "high"
}
2

Backend Validates & Processes

  1. requireAuth middleware verifies JWT
  2. logApiUsage middleware logs the request
  3. Route handler validates input with express-validator
  4. Business logic in controller
3

Database Transaction

Stored procedure called:
SELECT * FROM db_ambiotec.sp_create_service_request(
  $1, $2, $3, $4, $5
);
This:
  • Inserts into service_requests table
  • Creates initial status entry
  • Calculates SLA deadlines
  • Triggers notification job
4

Job Queue & Notifications

BullMQ job added to Redis:
await notificationQueue.add('notify-service-request', {
  request_id: newRequest.request_id,
  notification_group_id: 2
});
Worker sends emails to assigned vendors.
5

Real-Time Dashboard Update

Backend emits event (if Socket.IO enabled):
io.emit('service-request:created', newRequest);
Frontend dashboard updates automatically.

Database Architecture

Schema Structure

PostgreSQL database with the db_ambiotec schema:
  • users - System users with roles and permissions
  • customers - Customer organizations
  • contacts - Customer contact persons
  • departments - Geographic departments
  • municipio - Municipalities within departments
  • roles - User roles with descriptions
  • modules - System modules for permissions

Stored Procedures

Business logic encapsulated in PostgreSQL functions:
-- Example: Get service requests with filters
SELECT * FROM db_ambiotec.fn_get_service_requests(
  p_request_id INT,
  p_customer_id INT,
  p_status_id INT,
  p_from_date TIMESTAMPTZ,
  p_to_date TIMESTAMPTZ,
  -- ... more parameters
);
Located in DB/Functions_StoredProcedures/:
  • SP_ServiceRequest.sql
  • SP_Quotations.sql
  • SP_Customers.sql
  • SP_Creditos.sql
  • SP_Payments.sql
  • And more…

Docker Orchestration

Network Architecture

# From docker-compose.yml
networks:
  ambio_net:
    driver: bridge
All services communicate over the ambio_net Docker network:
  • Backend → Redis (via hostname redis)
  • Bot → Redis (via hostname redis)
  • Backend → PostgreSQL (external host)
  • Bot → PostgreSQL (external host)

Volume Management

# From docker-compose.yml (lines 36-40)
volumes:
  # Live code for hot-reload with nodemon
  - ./Backend/web-ambiotec:/usr/src/app
  # Preserve container's node_modules (avoid conflicts with host)
  - backend_node_modules:/usr/src/app/node_modules
volumes:
  - redis_data:/data
Ensures Redis data survives container restarts.

Security Considerations

These security measures are implemented in AmbioSys:
  • JWT tokens with configurable expiration
  • Secure session storage in Redis
  • Password hashing with bcrypt (work factor 10)
  • HTTPS enforcement in production
  • express-validator for all API inputs
  • SQL injection prevention via parameterized queries
  • XSS protection with DOMPurify on frontend
  • File upload validation (MIME type, size limits)
  • Rate limiting (TODO: implement with express-rate-limit)
  • CORS configuration for allowed origins
  • Request size limits (50MB for file uploads)
  • API usage logging for audit trails
  • Query parameters sanitized in logs:
// From src/app.js (lines 49-68)
const SENSITIVE_QUERY_PARAMS = new Set([
  "token", "access_token", "refresh_token", "authorization"
]);

const sanitizeUrl = (rawUrl) => {
  // Replaces sensitive params with [REDACTED]
};

Performance Optimizations

Database Connection Pooling

20 concurrent connections with automatic retry and backoff

Redis Caching

Session data, conversation context, and frequently accessed data

Job Queue Processing

Asynchronous email sending and notification processing with BullMQ

Frontend Code Splitting

React lazy loading for routes and heavy components

Monitoring & Logging

Morgan HTTP request logging:
GET /api/dashboard/metrics 200 1234 - 45.123 ms
POST /api/serviceRequests 201 456 - 123.456 ms
Custom application logs:
console.log('✅ Servidor Express corriendo en http://localhost:3000');
console.log('✔ Conectado a PostgreSQL');
console.log('✔ Conectado a Redis');

Deployment Considerations

For production deployment:
  1. Build production images:
    docker build -f Dockerfile.prod -t alvarosp24/ambiotec-backend:prod .
    
  2. Environment-specific configs:
    • Use secrets management (AWS Secrets Manager, HashiCorp Vault)
    • Enable SSL/TLS for database connections
    • Set NODE_ENV=production
  3. Scaling:
    • Deploy multiple backend instances behind a load balancer
    • Use Redis Cluster for high availability
    • Consider PostgreSQL read replicas for analytics
  4. Monitoring:
    • Integrate with APM tools (New Relic, Datadog)
    • Set up health check endpoints
    • Configure alerting for errors and performance

Next Steps

API Reference

Explore detailed endpoint documentation

Database Schema

Deep dive into table structures and relationships

Environment Variables

Fine-tune environment variables and settings

Docker Setup

Production deployment with Docker

Build docs developers (and LLMs) love