Package Exports
- @rempays/data-core
- @rempays/data-core/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@rempays/data-core) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@rempays/data-core
PostgreSQL data layer for RemPays platform. Centralized data persistence with TypeORM, extensible seeders, and Lambda-ready architecture.
Table of Contents
- Features
- Installation
- Quick Start
- Development Setup
- Creating New Entities
- Migrations
- Seeders
- Usage in Lambdas
- Database Schema
- API Reference
- Scripts
- Environment Variables
- Publishing
- CI/CD & Automated Deployment
- Project Structure
- Troubleshooting
Features
- 🗄️ PostgreSQL with TypeORM: Full ESM support with TypeScript
- 🔄 Migration System: Version-controlled schema changes
- 🌱 Extensible Seeder System: Core seeders + Lambda-registrable seeders
- 🐳 Docker Compose: Local development environment
- 📦 NPM Package: Ready for Lambda consumption
- 🔐 Cognito Integration: User authentication ready
- 🤖 AI Agent Configuration: System prompts, validation rules, and dynamic tools
- 🔌 Connection Pooling: Optimized for serverless environments
- 🎯 TypeScript Strict Mode: Full type safety
- 🔑 UUID Primary Keys: Using PostgreSQL uuid_generate_v4()
- 🗑️ Soft Delete: All entities support soft deletion
Installation
For Lambda Projects
npm install @rempays/data-coreFor Development
git clone <repository-url>
cd data-core
npm installQuick Start
1. Environment Setup
Create a .env file:
# Local Development
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/rempays_dev
DB_HOST=localhost
DB_PORT=5433
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_NAME=rempays_dev
NODE_ENV=development
# Production (Neon)
# DATABASE_URL=postgresql://user:password@ep-xxx.neon.tech/rempays?sslmode=require
# NODE_ENV=production2. Start Local Database
# Start PostgreSQL in Docker
npm run db:start
# Verify it's running
docker ps | grep rempays-postgres3. Run Migrations
# Build and run migrations
npm run migration:run4. Seed Initial Data
# Run all seeders (categories, validation rules, templates)
npm run seed:run5. Verify Setup
# Check database tables
docker exec rempays-postgres psql -U postgres -d rempays_dev -c "\dt"
# Check seeded data
docker exec rempays-postgres psql -U postgres -d rempays_dev -c "SELECT code, name FROM categories;"Development Setup
Prerequisites
- Node.js >= 18.0.0
- Docker and Docker Compose
- PostgreSQL client (optional, for manual queries)
Initial Setup
# 1. Install dependencies
npm install
# 2. Start database
npm run db:start
# 3. Run migrations
npm run migration:run
# 4. Seed data
npm run seed:run
# 5. Build project
npm run buildDevelopment Workflow
# Watch mode for TypeScript compilation
npm run build:watch
# In another terminal, make changes and test
npm run migration:generate MyNewFeature
npm run migration:runCreating New Entities
Step 1: Create Entity File
Create src/modules/my-entity/my-entity.entity.ts:
import { Entity, Column, Index, ManyToOne, JoinColumn } from 'typeorm';
import { BaseEntity } from '../../abstract/base.entity';
import { Business } from '../business/business.entity';
@Entity('my_entities')
@Index(['businessId', 'code'], { unique: true })
export class MyEntity extends BaseEntity {
@Column({ type: 'varchar', length: 100 })
code: string;
@Column({ type: 'varchar', length: 255 })
name: string;
@Column({ type: 'text', nullable: true })
description?: string;
// Relationship
@Column({ type: 'uuid' })
businessId: string;
@ManyToOne(() => 'Business', { lazy: true })
@JoinColumn({ name: 'business_id' })
business: Promise<Business>;
}Important:
- Extend
BaseEntityfor automatic id, timestamps, and soft delete - Use camelCase for properties (TypeORM handles snake_case in DB)
- Use lazy loading with string references to avoid circular dependencies
- Add indexes for frequently queried fields
Step 2: Create Repository
Create src/modules/my-entity/my-entity.repository.ts:
import { DataSource, Repository } from 'typeorm';
import { MyEntity } from './my-entity.entity';
export class MyEntityRepository extends Repository<MyEntity> {
constructor(dataSource: DataSource) {
super(MyEntity, dataSource.createEntityManager());
}
/**
* Find by code
*/
async findByCode(code: string): Promise<MyEntity | null> {
return this.findOne({ where: { code } });
}
/**
* Find all by business
*/
async findByBusiness(businessId: string): Promise<MyEntity[]> {
return this.find({
where: { businessId },
order: { createdAt: 'DESC' },
});
}
/**
* Find active entities
*/
async findActive(): Promise<MyEntity[]> {
return this.createQueryBuilder('entity')
.where('entity.deletedAt IS NULL')
.orderBy('entity.name', 'ASC')
.getMany();
}
}Step 3: Create Index File
Create src/modules/my-entity/index.ts:
export * from './my-entity.entity';
export * from './my-entity.repository';Step 4: Export from Main Index
Add to src/index.ts:
// My Entity module
export * from './modules/my-entity';Step 5: Generate Migration
# Build first
npm run build
# Generate migration
npm run migration:generate MyEntityTable
# Review the generated migration in migrations/
# Then run it
npm run migration:runStep 6: Create Seeder (Optional)
# Generate seeder template
npm run seeder:generate my-entity
# Edit src/seeders/004-my-entity.seeder.tsExample seeder:
import { DataSource } from 'typeorm';
import { MyEntityRepository } from '../modules/my-entity';
export async function seedMyEntity(dataSource: DataSource): Promise<void> {
const repo = new MyEntityRepository(dataSource);
const entities = [
{
code: 'ENTITY_1',
name: 'Entity One',
description: 'First entity',
businessId: null, // or specific business ID
},
{
code: 'ENTITY_2',
name: 'Entity Two',
description: 'Second entity',
businessId: null,
},
];
for (const data of entities) {
const existing = await repo.findByCode(data.code);
if (!existing) {
const entity = repo.create(data);
await repo.save(entity);
console.log(`✅ Entity created: ${data.name}`);
} else {
console.log(`⏭️ Entity already exists: ${data.name}`);
}
}
}Step 7: Test Locally
# Rebuild
npm run build
# Run new seeder
npm run seed:run
# Verify in database
docker exec rempays-postgres psql -U postgres -d rempays_dev -c "SELECT * FROM my_entities;"Migrations
Generate Migration
# After creating/modifying entities
npm run build
npm run migration:generate MyFeatureNameThis creates a timestamped migration file in src/migrations/ which will be compiled to dist/migrations/ during build.
Run Migrations
# Run all pending migrations
npm run migration:runRevert Migration
# Revert the last migration
npm run migration:revertMigration Best Practices
- Always review generated migrations before running
- Test migrations locally with Docker before production
- Never edit migrations after they've been run in production
- Use descriptive names:
AddUserEmailIndex, notMigration1 - One feature per migration: Don't mix unrelated changes
Manual Migration Example
If you need to create a migration manually:
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddMyEntityTable1234567890 implements MigrationInterface {
name = 'AddMyEntityTable1234567890'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE "my_entities" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"created_at" TIMESTAMP NOT NULL DEFAULT now(),
"updated_at" TIMESTAMP NOT NULL DEFAULT now(),
"deleted_at" TIMESTAMP,
"code" character varying(100) NOT NULL,
"name" character varying(255) NOT NULL,
"description" text,
"business_id" uuid,
CONSTRAINT "PK_my_entities" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
CREATE UNIQUE INDEX "IDX_my_entities_code"
ON "my_entities" ("business_id", "code")
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_my_entities_code"`);
await queryRunner.query(`DROP TABLE "my_entities"`);
}
}Seeders
Core Seeders (Included in Package)
The package includes 3 core seeders:
- 001-categories.seeder.ts - Business categories (restaurant, hardware-store, etc.)
- 002-validation-rules.seeder.ts - 17 AI validation rules
- 003-system-prompt-templates.seeder.ts - AI prompt templates per category
Generate New Seeder
npm run seeder:generate my-featureThis creates src/seeders/00X-my-feature.seeder.ts with the next available number.
Seeder Template
import { DataSource } from 'typeorm';
import { MyEntityRepository } from '../modules/my-entity';
export async function seedMyFeature(dataSource: DataSource): Promise<void> {
const repo = new MyEntityRepository(dataSource);
// Your seeding logic here
const data = [
{ code: 'ITEM_1', name: 'Item One' },
{ code: 'ITEM_2', name: 'Item Two' },
];
for (const item of data) {
const existing = await repo.findByCode(item.code);
if (!existing) {
const entity = repo.create(item);
await repo.save(entity);
console.log(`✅ Created: ${item.name}`);
} else {
console.log(`⏭️ Already exists: ${item.name}`);
}
}
}Run Seeders
# Run all seeders
npm run seed:run
# Run specific seeder
npm run seed:specific categoriesSeeder Priority System
Seeders run in order based on their numeric prefix:
- 001-099: Core package seeders
- 100-199: Lambda-specific seeders (recommended)
- 200+: Custom/optional seeders
Extensible Seeders for Lambdas
Lambdas can register their own seeders:
import { registerSeeder, runAllSeeders } from '@rempays/data-core';
// Register custom seeder
registerSeeder({
name: 'lambda-custom-tools',
priority: 100,
fn: async (dataSource) => {
// Your seeding logic
}
});
// Run all seeders (core + custom)
await runAllSeeders(dataSource);See Usage in Lambdas for more details.
Usage in Lambdas
Basic Repository Usage
import {
ConnectionManager,
UserRepository,
BusinessRepository
} from '@rempays/data-core';
export const handler = async (event) => {
// Get database connection
const connectionManager = ConnectionManager.getInstance();
const dataSource = await connectionManager.getDataSource();
// Use repositories
const userRepo = new UserRepository(dataSource);
const user = await userRepo.findByEmail(event.email);
if (!user) {
return { statusCode: 404, body: 'User not found' };
}
return {
statusCode: 200,
body: JSON.stringify(user)
};
};Registering Custom Seeders from Lambdas
import {
registerSeeder,
runAllSeeders,
ConnectionManager,
DynamicToolRepository
} from '@rempays/data-core';
// Register a custom seeder for your lambda
registerSeeder({
name: 'lambda-custom-tools',
priority: 100, // Higher priority = runs after core seeders (0-99)
fn: async (dataSource) => {
const toolRepo = new DynamicToolRepository(dataSource);
// Check if tool already exists
const existing = await toolRepo.findByFunctionName('get_menu');
if (existing) {
console.log('✅ Tool already exists: get_menu');
return;
}
// Create your custom tool
const tool = toolRepo.create({
functionName: 'get_menu',
businessId: null, // null = global tool
schemaJson: {
name: 'get_menu',
description: 'Get restaurant menu items',
parameters: {
type: 'object',
properties: {
category: { type: 'string' }
}
}
},
actionType: 'TYPEORM_SAVE',
actionConfig: {
entity: 'CatalogItem',
operation: 'find'
},
isActive: true
});
await toolRepo.save(tool);
console.log('✅ Tool created: get_menu');
}
});
// Run all seeders (core + custom)
export const seedHandler = async () => {
const connectionManager = ConnectionManager.getInstance();
const dataSource = await connectionManager.getDataSource();
await runAllSeeders(dataSource);
return { statusCode: 200, body: 'Seeders completed' };
};Seeder Priority System
- 0-99: Reserved for core data-core seeders (categories, validation rules, templates)
- 100-199: Lambda-specific seeders (recommended range)
- 200+: Custom/optional seeders
// Example: Multiple seeders with different priorities
registerSeeder({
name: 'lambda-base-tools',
priority: 100, // Runs first among lambda seeders
fn: async (dataSource) => {
// Seed base tools
}
});
registerSeeder({
name: 'lambda-business-specific',
priority: 150, // Runs after base tools
fn: async (dataSource) => {
// Seed business-specific data
}
});Advanced Seeder Options
import { runAllSeeders, listSeeders } from '@rempays/data-core';
// Run only external (lambda) seeders
await runAllSeeders(dataSource, { onlyExternal: true });
// Run only internal (core) seeders
await runAllSeeders(dataSource, { onlyInternal: true });
// Silent mode (no console output)
await runAllSeeders(dataSource, { silent: true });
// List all registered seeders
const seeders = await listSeeders();
console.log(seeders);
// [
// { name: '001-categories.seeder', priority: 1, type: 'internal' },
// { name: 'lambda-custom-tools', priority: 100, type: 'external' }
// ]Connection Management
import { ConnectionManager } from '@rempays/data-core';
// Singleton pattern - reuses connection
const connectionManager = ConnectionManager.getInstance();
const dataSource = await connectionManager.getDataSource();
// Connection is automatically managed
// No need to close in Lambda (reused across invocations)Environment Variables for Lambdas
# Set in Lambda environment variables
DATABASE_URL=postgresql://user:password@ep-xxx.neon.tech/rempays?sslmode=require
NODE_ENV=productionDatabase Schema
Core Tables
users
User profiles linked to AWS Cognito
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| cognito_sub | varchar | Cognito user ID (unique) |
| varchar | Email (unique) | |
| phone_number | varchar | Phone (unique) |
| first_name | varchar | First name |
| last_name | varchar | Last name |
| document_number | varchar | ID document |
| business_id | uuid | Associated business (nullable) |
| created_at | timestamp | Creation time |
| updated_at | timestamp | Last update |
| deleted_at | timestamp | Soft delete |
businesses
Business entities with DIAN integration
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| legal_name | varchar | Legal business name |
| commercial_name | varchar | Commercial name |
| nit | varchar | Tax ID (unique) |
| category_id | uuid | Business category |
| owner_user_id | uuid | Owner user |
| email_contact | varchar | Contact email |
| phone_contact | varchar | Contact phone |
| address | text | Physical address |
| city | varchar | City |
| country | varchar | Country |
| logo_url | text | Logo URL |
| description | text | Description |
| dian_document_url | text | DIAN document |
| dian_extracted_data | jsonb | Extracted DIAN data |
| is_active | boolean | Active status |
categories
Business categories with AI templates
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| code | varchar | Category code (unique) |
| name | varchar | Category name |
| description | text | Description |
| ai_template_prompt | text | AI template |
business_configs
AI agent configurations per business
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| business_id | uuid | Business reference |
| config_name | varchar | Config name |
| system_prompt | text | AI system prompt |
| context | text | Business context |
| questions | jsonb | FAQ structure |
| is_active | boolean | Active status |
business_channels
Communication channels (WhatsApp, Web, etc.)
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| business_config_id | uuid | Config reference |
| channel_type | enum | WHATSAPP, WEB, INSTAGRAM, FACEBOOK |
| purpose | enum | ORDERS, SUPPORT, GENERAL, SALES, APPOINTMENTS |
| identifier | varchar | Phone/Page ID |
| provider_meta | jsonb | Provider metadata |
AI & Tools Tables
system_prompt_templates
Reusable AI prompt templates
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| template_name | varchar | Template name |
| template_code | varchar | Unique code |
| content | text | Prompt content |
| version | integer | Version number |
| category_code | varchar | Category reference |
| required_variables | jsonb | Required variables |
| is_active | boolean | Active status |
| is_default | boolean | Default for category |
validation_rules
Global security and validation rules
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| rule_name | varchar | Rule name (unique) |
| description | text | Description |
| rule_content | text | Rule content |
| priority | integer | Priority (1 = highest) |
| is_active | boolean | Active status |
| applies_to_all_businesses | boolean | Global rule |
dynamic_tools
AI function calling definitions
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| function_name | varchar | Function name |
| business_id | uuid | Business (null = global) |
| schema_json | jsonb | Function schema |
| action_type | enum | MONGO_AGGREGATE, TYPEORM_SAVE, API_CALL, CUSTOM |
| action_config | jsonb | Action configuration |
| is_active | boolean | Active status |
| metadata | jsonb | Additional metadata |
chats
Conversation history
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| contact_id | varchar | Customer ID |
| business_id | uuid | Business reference |
| channel | enum | whatsapp, web, api |
| last_incoming_message | text | Last message |
| message_count | integer | Message count |
| last_message_timestamp | timestamptz | Last message time |
| messages | jsonb | Message history |
API Reference
ConnectionManager
Singleton for managing database connections.
const connectionManager = ConnectionManager.getInstance();
const dataSource = await connectionManager.getDataSource();Repositories
All repositories extend TypeORM's Repository class.
UserRepository
const userRepo = new UserRepository(dataSource);
// Find by email
const user = await userRepo.findByEmail('user@example.com');
// Find by Cognito sub
const user = await userRepo.findByCognitoSub('cognito-sub-id');
// Find by phone
const user = await userRepo.findByPhoneNumber('+1234567890');
// Find by business
const users = await userRepo.findByBusiness('business-uuid');BusinessRepository
const businessRepo = new BusinessRepository(dataSource);
// Find by NIT
const business = await businessRepo.findByNit('900123456-7');
// Find by owner
const businesses = await businessRepo.findByOwner('user-uuid');
// Find active businesses
const active = await businessRepo.findActive();
// Find by category
const restaurants = await businessRepo.findByCategory('category-uuid');CategoryRepository
const categoryRepo = new CategoryRepository(dataSource);
// Find by code
const category = await categoryRepo.findByCode('restaurant');
// Find all active
const categories = await categoryRepo.findAllActive();Seeder Functions
import {
registerSeeder,
runAllSeeders,
runSeeder,
listSeeders,
clearExternalSeeders
} from '@rempays/data-core';
// Register seeder
registerSeeder({
name: 'my-seeder',
priority: 100,
fn: async (dataSource) => { /* ... */ }
});
// Run all seeders
await runAllSeeders(dataSource);
// Run specific seeder
await runSeeder(dataSource, 'categories');
// List seeders
const seeders = await listSeeders();
// Clear external seeders (testing)
clearExternalSeeders();Scripts
Database Management
# Start PostgreSQL in Docker
npm run db:start
# Stop database
npm run db:stop
# Stop and remove data (fresh start)
npm run db:reset
# View logs
npm run db:logsBuild
# Build once
npm run build
# Watch mode
npm run build:watch
# Pre-publish build (automatic)
npm run prepublishOnlyMigrations
# Generate migration
npm run migration:generate MigrationName
# Run migrations
npm run migration:run
# Revert last migration
npm run migration:revert
# Sync schema (dev only - dangerous!)
npm run schema:syncSeeders
# Generate seeder
npm run seeder:generate seeder-name
# Run all seeders
npm run seed:run
# Run specific seeder
npm run seed:specific categories
# Test seeder system
npm run test:seedersTesting
# Full local test (db + migrations + seeders)
npm run test:local
# Test seeder system
npm run test:seedersEnvironment Variables
Local Development
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/rempays_dev
DB_HOST=localhost
DB_PORT=5433
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_NAME=rempays_dev
NODE_ENV=developmentProduction (Neon)
DATABASE_URL=postgresql://user:password@ep-xxx.neon.tech/rempays?sslmode=require
NODE_ENV=productionLambda Environment
Set these in AWS Lambda environment variables:
DATABASE_URL=<neon-connection-string>
NODE_ENV=productionPublishing
The package uses automated CI/CD with GitHub Actions for publishing to NPM.
Automated Publishing
| Branch/Tag | Environment | Version | NPM Tag | Action |
|---|---|---|---|---|
develop |
Beta | Auto-increment | beta |
Auto-publish |
main |
Production | package.json | latest |
Auto-publish |
v*.*.* |
Release | From tag | latest |
Auto-publish + GitHub Release |
| Pull Request | CI Testing | - | - | Test only, no publish |
Developer Workflow
Beta Release (develop):
git checkout develop
git add .
git commit -m "feat: new feature"
git push origin develop
# → Automatically publishes @rempays/data-core@betaProduction Release (main with tag):
git checkout main
git merge develop
npm version patch # or minor, or major
git push origin main
git tag v1.0.1
git push origin v1.0.1
# → Automatically publishes @rempays/data-core@1.0.1Manual Publishing (First Time Only)
For the initial package creation:
npm login
npm publish --access restrictedAfter this, CI/CD handles all updates automatically.
CI/CD & Automated Deployment
Overview
El proyecto usa GitHub Actions para automatizar testing, publicación a NPM, y deployment de migraciones/seeders a la base de datos.
Workflow Completo
Push to develop/main
↓
Build Package
↓
Publish to NPM
↓
Deploy to Database (Migrations + Seeders)Detección Automática de Entorno
| Branch/Tag | Environment | NPM Tag | Database | Migrations | Seeders |
|---|---|---|---|---|---|
develop |
Beta | beta |
Develop DB | ✅ | ✅ |
main |
Production | latest |
Production DB | ✅ | ✅ |
v*.*.* |
Release | latest |
Production DB | ✅ | ✅ |
| Pull Request | CI Test | - | - | ❌ | ❌ |
GitHub Environments Setup
El workflow usa GitHub Environments para gestionar credenciales de base de datos por entorno.
1. Crear Environments
Ve a Settings → Environments en tu repositorio GitHub.
2. Environment: develop
Nombre: develop
Secret: DATABASE_URL = postgresql://user:pass@ep-xxx.neon.tech/rempays_dev?sslmode=require
Deployment branches: develop3. Environment: production
Nombre: production
Secret: DATABASE_URL = postgresql://user:pass@ep-yyy.neon.tech/rempays_prod?sslmode=require
Deployment branches: main, v*.*.*
Required reviewers: [Tu usuario] (recomendado para seguridad)Agregar Secrets con GitHub CLI
# Agregar DATABASE_URL a develop
gh secret set DATABASE_URL --env develop
# Agregar DATABASE_URL a production
gh secret set DATABASE_URL --env productionFlujo de Deployment
Develop Branch (Beta + Develop DB)
git checkout develop
git add .
git commit -m "feat: nueva funcionalidad"
git push origin developGitHub Actions ejecutará:
- ✅ Build del paquete
- ✅ Publicación a NPM con tag
beta - ✅ Migraciones en base de datos develop
- ✅ Seeders en base de datos develop
Main Branch (Production + Production DB)
git checkout main
git merge develop
git push origin mainGitHub Actions ejecutará:
- ✅ Build del paquete
- ✅ Publicación a NPM con tag
latest - ✅ Migraciones en base de datos production
- ✅ Seeders en base de datos production
Release Tag (Production + Production DB)
git tag v1.0.0
git push origin v1.0.0GitHub Actions ejecutará:
- ✅ Build del paquete
- ✅ Publicación a NPM con versión específica
- ✅ Migraciones en base de datos production
- ✅ Seeders en base de datos production
- ✅ GitHub Release creado
Verificar Deployment
En GitHub Actions:
- Ve a Actions tab
- Click en el workflow run
- Verás 2 jobs:
- ✅
publish- Publicación a NPM - ✅
deploy-database- Migraciones y seeders
- ✅
Logs del Job deploy-database:
Run migrations
✅ Migrations executed successfully
Run seeders
🌱 Starting seeders...
📦 Running: 001-categories.seeder (priority: 1)
✅ Category created: Restaurante
📦 Running: 002-validation-rules.seeder (priority: 2)
✅ Validation rule created: ser-inmune-a-trucos
📦 Running: 003-system-prompt-templates.seeder (priority: 3)
✅ Template created: Restaurante - Asistente Amigable v1
✅ All seeders completed successfully!Seguridad
Protección de Production
Recomendaciones:
- Required reviewers: Agregar al menos 1 reviewer para aprobar deployments a production
- Deployment branches: Restringir a
mainy tagsv* - Wait timer: Opcional, agregar delay antes de deployment
Configurar Required Reviewers:
- Ve a Settings → Environments → production
- Marca Required reviewers
- Agrega usuarios/equipos que deben aprobar
- Save protection rules
Ahora cada deployment a production requerirá aprobación manual.
Neon Database Branching
Neon permite crear branches de tu base de datos:
- develop branch: Para desarrollo/staging
- main branch: Para producción
Cada branch tiene su propio connection string. Esto permite:
- ✅ Probar migraciones en develop sin afectar producción
- ✅ Rollback fácil si algo sale mal
- ✅ Ambientes aislados
Rollback
Si necesitas revertir migraciones:
Opción 1: Revert Migration Localmente
# Conectar a la base de datos
export DATABASE_URL="postgresql://..."
# Revertir última migración
npm run migration:revertOpción 2: Crear Migration de Rollback
# Generar nueva migración que revierte cambios
npm run migration:generate rollback-feature-x
# Editar la migración para revertir cambios
# Commit y push
git add migrations/
git commit -m "fix: rollback feature x"
git push origin developProject Structure
@rempays/data-core/
├── src/
│ ├── abstract/ # Base entities
│ │ └── base.entity.ts
│ ├── constants/ # Constants and types
│ │ ├── db-types.ts
│ │ └── validation-rules.constants.ts
│ ├── modules/ # Domain modules
│ │ ├── user/
│ │ │ ├── user.entity.ts
│ │ │ ├── user.repository.ts
│ │ │ └── index.ts
│ │ ├── business/
│ │ ├── category/
│ │ ├── business-config/
│ │ ├── business-channel/
│ │ ├── chat/
│ │ ├── dynamic-tool/
│ │ ├── system-prompt-template/
│ │ └── validation-rule/
│ ├── seeders/ # Data seeders
│ │ ├── index.ts
│ │ ├── 001-categories.seeder.ts
│ │ ├── 002-validation-rules.seeder.ts
│ │ └── 003-system-prompt-templates.seeder.ts
│ ├── connection-manager.ts # Connection singleton
│ ├── data-core.module.ts # NestJS module
│ ├── data-source.ts # TypeORM config
│ └── index.ts # Main exports
├── migrations/ # Database migrations
├── scripts/ # Utility scripts
├── examples/ # Usage examples
├── dist/ # Compiled output
├── .env # Environment variables
├── .env.example # Environment template
├── .npmignore # NPM ignore rules
├── docker-compose.yml # Local PostgreSQL
├── init-db.sql # Database initialization
├── tsconfig.json # TypeScript config
├── package.json # Package configuration
├── README.md # This file
├── CHANGELOG.md # Version history
├── PUBLISHING.md # Publishing guide
└── LICENSE # License fileTroubleshooting
Database Connection Issues
# Check if Docker is running
docker ps
# Check PostgreSQL logs
npm run db:logs
# Restart database
npm run db:resetMigration Errors
# Revert last migration
npm run migration:revert
# Check migration status
docker exec rempays-postgres psql -U postgres -d rempays_dev -c "SELECT * FROM migrations;"
# Fresh start
npm run db:reset
npm run migration:runBuild Errors
# Clean build
rm -rf dist node_modules
npm install
npm run buildSeeder Issues
# Check seeder files
ls -la src/seeders/
# Run specific seeder
npm run seed:specific categories
# Check database
docker exec rempays-postgres psql -U postgres -d rempays_dev -c "SELECT * FROM categories;"Contributing
- Create a feature branch
- Make your changes
- Generate migrations if schema changed
- Test locally with Docker
- Update CHANGELOG.md
- Submit PR
License
UNLICENSED - Proprietary software for RemPays platform.
Support
For issues and questions:
- GitHub Issues: [repository-url]/issues
- Team Contact: [contact-info]
Version: 1.0.0
Last Updated: 2024-02-14