Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/IvanchoDev89/maleku-system/llms.txt

Use this file to discover all available pages before exploring further.

Maleku System is built for production observability from day one. The FastAPI backend exposes a Prometheus scrape endpoint, ships pre-provisioned Grafana dashboards and datasource configs, uses structured JSON logging throughout, and records every state-changing operation in a persistent audit log. Together these layers give you metrics, logs, and a full audit trail without additional instrumentation.

Prometheus Metrics

In development, the Prometheus metrics endpoint is available at http://localhost:8000/metrics. In production on Railway, the endpoint is at https://your-backend.up.railway.app/metrics.
The FastAPI application exposes a GET /metrics endpoint in the standard Prometheus text exposition format. Prometheus is configured to scrape it every 10 seconds:
# infraestructura/prometheus/prometheus.yml
scrape_configs:
  - job_name: 'costarica-backend'
    static_configs:
      - targets: ['backend:8000']
    metrics_path: '/metrics'
    scrape_interval: 10s
Prometheus also scrapes sidecar exporters for the database and cache layers:
JobTargetScrape intervalWhat it monitors
costarica-backendbackend:800010 sFastAPI request counts, response times, error rates
postgrespostgres:918715 sPostgreSQL connections, query latency, cache hit ratio
redisredis:912115 sRedis memory, hit/miss rate, connected clients
Start the monitoring stack with the monitoring Docker Compose profile:
docker compose --profile monitoring up -d
Prometheus will be reachable at http://localhost:9090.

Grafana Dashboards

Grafana is provisioned automatically from the infraestructura/grafana/ directory. No manual dashboard imports are required — everything is loaded from files on container start. Datasource provisioning (infraestructura/grafana/datasources/datasource.yml):
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: false
    jsonData:
      timeInterval: 15s
Dashboard provisioning (infraestructura/grafana/dashboards/dashboard.yml) configures Grafana to load all JSON dashboard files from the same directory:
apiVersion: 1

providers:
  - name: 'Default'
    orgId: 1
    folder: ''
    type: file
    disableDeletion: true
    editable: true
    options:
      path: /etc/grafana/provisioning/dashboards
Grafana is available at http://localhost:3002 when started via Docker Compose. The default admin password is controlled by the GRAFANA_PASSWORD environment variable (defaults to admin if not set).
To add a new dashboard, export it as JSON from Grafana, save the file to infraestructura/grafana/dashboards/, and restart the Grafana container. It will be auto-provisioned on next start.

Structured Logging

All backend modules obtain a logger with get_logger(__name__) from app.core.logging. The logging system supports two output formats controlled by environment variables:
LOG_FORMAT valueFormatter usedBest for
(empty)SimpleFormatter — coloured, human-readableLocal development
jsonJSONFormatter — machine-parseableProduction / log aggregators
JSON log entry shape (production):
{
  "timestamp": "2024-11-15T10:23:41.123456+00:00",
  "level": "INFO",
  "logger": "app.api.v1.bookings",
  "message": "Booking created for tour_id=abc123",
  "request": {
    "method": "POST",
    "path": "/api/v1/bookings",
    "status_code": 201,
    "duration_ms": 84.37
  }
}
For WARNING and above, the entry also includes a source block with file, line, and function to pinpoint the origin without a stack trace. Privacy — the JSONFormatter and SimpleFormatter both redact email addresses in log messages automatically (e.g. user@example.comu***r@example.com), preventing accidental PII leakage in log aggregators. Configure logging with:
LOG_LEVEL=INFO        # DEBUG | INFO | WARNING | ERROR | CRITICAL
LOG_FORMAT=json       # empty for coloured dev output; "json" for production

Rate Limiting Observability

Maleku System uses SlowAPI (a Starlette/FastAPI port of Flask-Limiter) backed by Redis so rate-limit counters are shared across all Uvicorn workers. Rate limits are role-based — authenticated users get higher allowances keyed by user_id, while anonymous requests share per-IP buckets:
RoleDefault limit
Anonymous30 requests / minute
Client60 requests / minute
Vendor100 requests / minute
Admin200 requests / minute
Super Admin300 requests / minute
Specific endpoints carry tighter per-endpoint overrides:
EndpointLimit
POST /api/v1/auth/login5 / minute
POST /api/v1/bookings10 / minute
POST /api/v1/availability10 / minute
GET /api/v1/availability30 / minute
GET /api/v1/blog30 / minute
Admin write endpoints10 / minute
When a request is rejected (HTTP 429), the rate limiter logs a warning via get_logger(__name__):
Rate limit hit on POST /api/v1/bookings from 203.0.113.42
The response includes a Retry-After header so clients know when to retry. The X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers are injected on every response when headers_enabled=True (the default).

Audit Logging

AuditLog records every state-changing operation in the audit_logs PostgreSQL table. The table is indexed for common query patterns (by user_id + action, by entity_type + entity_id, and by created_at DESC). Accessing audit logs — superadmins can query the audit trail via:
GET /api/v1/superadmin/audit
Each AuditLog record contains the following fields:
FieldTypeDescription
idUUIDUnique log entry identifier
user_idUUIDUser who performed the action (nullable)
user_emailstringSnapshot of the email at time of action
actionAuditAction enumOne of: create, update, delete, login, logout, approve, reject, suspend, activate, payment, refund, cancel, confirm, complete, and more
entity_typestringResource type: user, vendor, booking, property, etc.
entity_idUUIDID of the affected resource
entity_namestringHuman-readable name of the resource
old_valuesJSONBState before the change
new_valuesJSONBState after the change
changes_summarytextHuman-readable diff
ip_addressINETClient IP address
user_agentstringClient User-Agent header
request_pathstringAPI path that triggered the action
created_attimestamptzUTC timestamp of the event
Security events are recorded in a separate security_logs table (SecurityLog model) with a severity field (info, warning, critical) and structured details JSONB. Tracked security actions include login_success, login_failure, password_change, rate_limit_hit, suspicious_activity, account_locked, and more. Security logs are accessible via:
GET /api/v1/superadmin/audit/security

Build docs developers (and LLMs) love