📦 Versionado Git desde el Día Uno
Principio:
El código de HANA (tablas, vistas, cálculos, seguridad) debe estar en Git desde la primera línea. No es un "extra", es el repositorio de verdad.
Estructura del Repositorio:
proyecto-logali/
├── .git/ (Git history)
├── .gitignore (Archivos no versionados)
├── README.md (Documentación general)
├── docs/ (Documentación técnica)
│ ├── ARCHITECTURE.md
│ ├── NAMING_CONVENTIONS.md
│ └── DEPLOYMENT.md
├── db/ (Módulo de base de datos)
│ ├── mta.yaml (Despliegue)
│ ├── package.json (Dependencias npm)
│ ├── src/
│ │ ├── logali/ (Dominio principal)
│ │ │ ├── core/ (Tablas base, dim comunes)
│ │ │ ├── sales/ (Dominio de ventas)
│ │ │ ├── finance/ (Dominio de finanzas)
│ │ │ ├── supply/ (Dominio de supply chain)
│ │ │ └── shared/ (Dimensiones compartidas)
│ └── cfg/ (Configuración)
│ ├── HANA.yml
│ └── credentials.env
├── srv/ (Servicios OData / CAP)
└── app/ (Frontend UI5 / Fiori)
.gitignore para SAP HANA:
# No versionamos artifacts de compilación
*.jar
*.zip
*.tar.gz
/db/.hanarc
/db/node_modules
/db/package-lock.json
# Configuración local y secretos
.env
.env.local
credentials.json
secrets/
*.key
*.pem
# IDEs locales
.vscode/
.idea/
*.swp
*.swo
*~
# Builds
/mta_archives/
dist/
build/
# Logs
*.log
# OS
.DS_Store
Thumbs.db
Commits estructurados:
# ✅ BUENO - Describe qué y por qué
git commit -m "core: Add Products dimension for sales analytics
- Add hdbtable Product with 8 fields (ID, name, category, price)
- Add hdbindex for category lookups
- Update namespace documentation
- Reason: Foundation for sales cube, needed by SalesAgg calc view"
# ❌ MALO - Vago
git commit -m "Update tables"
git commit -m "Fix stuff"
✅ Beneficio:
Historial limpio = auditoría completa. Sabes quién cambió qué tabla, cuándo, y por qué. Rollback a cualquier punto en 30 segundos.
⚙️ Módulo db es Código
Archivos de HANA en el repo:
logali/core/
├── data_types.hdbdd # Tipos de datos custom
├── Products.hdbtable # Tabla de productos
├── Products.hdbindex # Índice en PRODUCT_ID
├── Customers.hdbtable # Tabla de clientes
├── Sales.hdbtable # Tabla de hechos
├── SalesAgg.hdbcalculationview # Agregación de ventas
├── Products.hdbsynonym # Alias de tabla (si aplica)
├── MasterProductData.hdbtabledata # Data maestro inicial
└── .hdbgrants # Permisos por rol
logali/core/grants/
├── tech_user_core.hdbgrants
├── analyst_user_sales.hdbgrants
└── integration_service.hdbgrants
Cada tipo de archivo:
.hdbtable
Definición de tabla. Siempre en Git. Es el "schema definition".
.hdbindex
Índices para performance. Siempre en Git. Afecta queries.
.hdbcalculationview
Vistas de cálculo. Siempre en Git. Lógica de analítica.
.hdbsynonym
Aliases de tablas. Siempre en Git. Encapsulación.
.hdbgrants
Permisos por rol. Siempre en Git. Auditoría de seguridad.
.hdbtabledata
Datos maestros. Solo datos estables. NO para datasets grandes.
Archivo de ejemplo: Products.hdbtable
namespace logali.core;
@AbapCatalog.sqlViewName: 'PRODUCTS'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Catálogo de Productos'
context Products {
type ProductKey : String(20);
entity Products {
key ID: ProductKey;
NAME: String(255);
CATEGORY: String(50);
LIST_PRICE: Decimal(10,2);
COST: Decimal(10,2);
ACTIVE: Boolean default true;
CREATED_AT: Timestamp;
UPDATED_AT: Timestamp;
};
define view Products as SELECT from Products as p {
p.ID,
p.NAME,
p.CATEGORY,
p.LIST_PRICE,
p.COST,
p.ACTIVE,
p.CREATED_AT,
p.UPDATED_AT
};
};
✅ Ventaja:
Todo en Git = puedes rollback, comparar versiones, hacer code review antes de deploy. Es como tener Git para tu BD.
🏢 Separación de Namespaces por Dominio Funcional
El problema:
⚠️ Anti-patrón:
Todo en logali.hana.* → A los 6 meses tienes 500 tablas en el mismo namespace. Nadie sabe dónde está nada. Los pulls tardan 10 minutos. Merge conflicts diarios.
La solución: Namespaces por dominio:
logali.core (Datos maestros compartidos)
logali.core.dimensions (Dimensiones comunes)
logali.sales (Ventas y órdenes)
logali.sales.analytics (Agregaciones de ventas)
logali.finance (Contabilidad, facturas)
logali.finance.analytics (Reportes financieros)
logali.supply (Inventory, supply chain)
logali.supply.analytics (KPIs de logística)
logali.integration (Integraciones externas)
logali.security (Datos sensibles, encriptados)
Estructura de carpetas en Git:
src/
├── logali/
│ ├── core/
│ │ ├── dimensions/
│ │ │ ├── Customer.hdbtable
│ │ │ ├── Product.hdbtable
│ │ │ ├── Time.hdbtable
│ │ │ └── .hdbgrants
│ │ └── shared/
│ │ ├── CommonTypes.hdbdd
│ │ └── .hdbgrants
│ │
│ ├── sales/
│ │ ├── Orders.hdbtable
│ │ ├── OrderItems.hdbtable
│ │ ├── SalesKPI.hdbcalculationview
│ │ └── .hdbgrants
│ │
│ ├── finance/
│ │ ├── Invoices.hdbtable
│ │ ├── InvoiceLines.hdbtable
│ │ ├── FinanceAgg.hdbcalculationview
│ │ └── .hdbgrants
│ │
│ └── security/
│ ├── SensitiveData.hdbtable
│ ├── RLS_Rules.hdbgrants
│ └── Encryption.hdbdd
Beneficios por dominio:
- Claridad: Dónde están las órdenes? →
logali/sales
- Autonomía: El equipo de Finanzas toca solo
logali/finance
- Escalabilidad: 100 tablas pero distribuidas = fácil de navegar
- Permisos: Cada dominio con sus propios .hdbgrants
- Versionado: Conflictos mínimos si cada equipo trabaja en su namespace
💡 Nota:
Los namespaces también afectan OData. Un modelo CDS en logali.sales expone automáticamente las vistas como /odata/logali.sales/SalesKPI.
🔐 .hdbgrants - Principio de Menor Privilegio
Regla de oro:
Concede SOLO los permisos mínimos necesarios para que el usuario haga su trabajo. Si no lo necesita, no se lo des.
Tipos de usuarios en SAP HANA:
Usuario Técnico (Tech User)
Despliega código, ejecuta migraciones, desarrolla vistas.
Permisos: CREATE TABLE, EXECUTE, SELECT en su schema.
Usuario de Análisis (Analyst)
Lee dashboards, ejecuta reportes.
Permisos: SELECT en vistas (NO en tablas base).
Servicio de Integración
Carga datos desde sistemas externos (SAP ECC, etc).
Permisos: INSERT/UPDATE/DELETE en tablas staging.
Admin (Raro)
Mantenimiento crítico, recuperación.
Permisos: Acceso total (controlado).
Ejemplo: .hdbgrants para usuario técnico
role_name: "logali_tech_core";
privileges:
# Crear y modificar tablas en su schema
- privilege: "CREATE TABLE";
object_type: "SCHEMA";
object_name: "LOGALI_CORE";
# Ejecutar vistas de cálculo (para testing)
- privilege: "SELECT";
object_type: "VIEW";
object_names:
- "LOGALI_CORE::Products";
- "LOGALI_CORE::Customers";
# NO darle INSERT/UPDATE en tablas base (eso lo hace App)
# NO darle DROP (peligroso)
# NO darle ALTER SYSTEM (nivel DB)
# Asignación al usuario:
user: "TECH_LOGALI";
roles:
- "logali_tech_core";
Ejemplo: .hdbgrants para usuario de análisis
role_name: "logali_analyst_sales";
privileges:
# Solo lectura en vistas de agregación
- privilege: "SELECT";
object_type: "VIEW";
object_names:
- "LOGALI.SALES::SalesKPI";
- "LOGALI.SALES::RegionalAnalysis";
# NO acceso a tabla de hechos directa (usa vistas)
# NO acceso a tablas de staging
# NO acceso a datos sensibles
# Asignación:
user: "ANALYST_MARIA";
roles:
- "logali_analyst_sales";
Ejemplo: .hdbgrants para servicio de integración
role_name: "logali_integration_ecc";
privileges:
# INSERT/UPDATE en tablas de staging (no master)
- privilege: "INSERT";
object_type: "TABLE";
object_names:
- "LOGALI_INTEGRATION::SAP_ECC_ORDERS_STAGING";
- "LOGALI_INTEGRATION::SAP_ECC_ITEMS_STAGING";
- privilege: "UPDATE";
object_type: "TABLE";
object_names:
- "LOGALI_INTEGRATION::SAP_ECC_ORDERS_STAGING";
# NO DELETE (evita borrados accidentales)
# NO acceso a tablas master
# NO modificar vistas
# Asignación:
user: "ECC_INTEGRATION_USER";
password: "(gestionar en vault, no en código)";
roles:
- "logali_integration_ecc";
⚠️ Nunca hagas esto:
- Conceder
SYSTEM PRIVILEGE a usuarios de aplicación
- Dar DELETE a usuarios que no lo necesitan
- Usar una contraseña default en .hdbgrants
- El mismo usuario para múltiples capas (app, integration, analytics)
✅ Beneficio:
Si un usuario es comprometido, el daño es limitado a sus permisos. Si ANALYST_MARIA es hackeada, solo puede leer vistas de sales, no tocar datos sensibles.
📊 .hdbtabledata - Cuándo Usarlo (y Cuándo No)
¿Qué es .hdbtabledata?
Un archivo CSV o JSON que se carga automáticamente en una tabla durante el despliegue. Útil para datos maestros estables que nunca cambian.
✅ CORRECTO: Usar .hdbtabledata para:
Datos maestros pequeños y estables:
- Catálogo de países (200 registros)
- Configuración de tipos de producto (50 registros)
- Dimensión Tiempo (7 años × 365 días = 2.555 registros)
- Códigos de estado (10 valores: 'Pendiente', 'Aprobado', etc.)
Ejemplo correcto: Countries.hdbtabledata
{
"format_version": 1,
"imports": [
{
"target_table": "LOGALI_CORE::Countries",
"source_data": {
"data_file": "Countries.csv"
},
"import_settings": {
"create_target": false,
"mode": "REPLACE"
}
}
]
}
# Countries.csv:
COUNTRY_CODE,COUNTRY_NAME,REGION,CURRENCY
ES,Spain,Europe,EUR
UK,United Kingdom,Europe,GBP
FR,France,Europe,EUR
US,USA,Americas,USD
❌ INCORRECTO: NO usar .hdbtabledata para:
Datasets grandes o transaccionales:
- Tabla de Ventas (millones de registros) → Sistema lentísimo en deploy
- Datos de clientes activos (50M registros) → NO cabe en un archivo
- Staging de integraciones → Cambia diariamente
- Datos históricos mensurales → Crece constantemente
- Credenciales o datos sensibles → NUNCA en .hdbtabledata
Comparación:
| Scenario |
.hdbtabledata |
Alternativa |
| Cargar 200 países una sola vez |
✅ Perfecto |
— |
| Importar 5M registros de ventas |
❌ No |
API REST + JDBC, batch job |
| Datos maestro estable (lista de categorías) |
✅ Sí |
— |
| Staging diario de ECC |
❌ No |
Data replication, BW extractor |
| Dimensión Tiempo (fechas precargadas) |
✅ Sí |
— |
| Contraseñas o API keys |
❌ NUNCA |
Credential store, environment vars |
💡 Regla práctica:
Si tienes más de 10K registros o los datos cambian más de 1x al mes, NO uses .hdbtabledata.
✅ Checklist de Gobernanza
Antes de hacer commit:
- □ ¿Está el archivo en Git? (.hdbtable, .hdbcalculationview, .hdbgrants)
- □ ¿Es el mensaje de commit descriptivo? (por qué, no solo qué)
- □ ¿El namespace es correcto? (¿en qué dominio va?)
- □ ¿He revisado .hdbgrants? (¿permisos mínimos?)
- □ ¿Usé .hdbtabledata solo para datos maestros? (<10K registros?)
- □ ¿Los filtros son tempranos en la calc view? (proyecciones pre-filtradas)
Antes de hacer deploy:
- □ ¿Pasó code review? (otro dev, no el autor)
- □ ¿Testeé en un schema de staging primero?
- □ ¿Están los índices correctamente nombrados?
- □ ¿Los grants reflejan la realidad (quién necesita acceso)?
- □ ¿Backup hecho antes de cambios en schema?
- □ ¿Hay rollback plan si algo sale mal?
💡 Última regla:
Si no está en Git, no existe. Si existe pero no está en Git, peligra. Siempre: Git primero, deploy segundo.