@horizon-modules/property-model-v3
Version:
Modelo de propriedades imobiliárias v3 - Sistema de atributos dinâmicos
689 lines (549 loc) • 19.1 kB
Markdown
# @horizon-modules/property-model-v3
Sistema completo para modelagem de propriedades imobiliárias V3 com **atributos dinâmicos**, **validação Zod**, **profiling de dados** e **pipeline de desenvolvimento automatizado**.
## 📦 Instalação
```bash
npm install @horizon-modules/property-model-v3
# ou
pnpm add @horizon-modules/property-model-v3
```
## 🚀 Uso Básico
```typescript
import {
PropertyModel,
PropertyModelSchema,
validatePropertyModel,
safeValidatePropertyModel,
generateFakeProperty,
PropertyModelJsonSchema
} from '@horizon-modules/property-model-v3';
// Exemplo de propriedade V3
const property: PropertyModel = {
reference: "AP001_V3",
title: "Apartamento Premium - 3 qtos, 150m²",
description: "Apartamento moderno com acabamentos de primeira linha...",
attributes: {
tipo: "Apartamento",
operacao: ["venda"],
dormitorios: 3,
banheiros: 2,
area_util: 150,
valor_venda: 850000,
endereco_cidade: "São Paulo",
endereco_bairro: "Vila Madalena"
},
media_assets: {
images: [
{
full: "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=800&q=80",
cover: true
}
]
},
settings: {
currency_unit: "BRL",
area_unit: "m2",
exibir_no_mapa: true
}
};
// Validação com Zod
const validProperty = validatePropertyModel(property);
// Validação safe (nunca lança erro)
const result = safeValidatePropertyModel(property);
if (result.success) {
console.log("Propriedade válida:", result.data);
} else {
console.log("Erros:", result.error.issues);
}
// Gerar dados fake
const fakeProperty = generateFakeProperty("apartamento");
```
## 🏗️ Arquitetura PropertyModel V3
### Estrutura Principal
```typescript
interface PropertyModel {
reference: string // Código único
title: string // Título da propriedade
description: string // Descrição detalhada
attributes: Record<string, any> // Atributos dinâmicos
media_assets: MediaAssets // Fotos, vídeos, tours
settings?: SettingsFormat // Configurações de formato
updated_at?: string // Data de atualização
}
```
### Sistema de Atributos Dinâmicos
O V3 substitui o array de atributos por um **objeto chave-valor** mais flexível:
```typescript
// V2 (antigo)
attributes: [
{ key: "dormitorios", value: 3 },
{ key: "valor_venda", value: 850000, unit: "BRL" }
]
// V3 (novo)
attributes: {
dormitorios: 3,
valor_venda: 850000,
endereco_cidade: "São Paulo",
caracteristicas: ["Churrasqueira", "Piscina"]
}
```
**Benefícios do V3:**
- ✅ Acesso direto: `property.attributes.dormitorios`
- ✅ Menos verboso e mais legível
- ✅ Melhor performance em consultas
- ✅ Compatível com NoSQL (MongoDB, DynamoDB)
- ✅ Validação Zod nativa
### Media Assets
```typescript
interface MediaAssets {
images?: ImageMedia[] // Fotos do imóvel
videos?: VideoMedia[] // Vídeos (YouTube, Vimeo)
virtual_tours?: VirtualTourMedia[] // Tours 360°
documents?: DocumentMedia[] // PDFs, documentos
}
interface ImageMedia {
full: string // URL da imagem completa
md?: string // Versão 640x480
sm?: string // Versão 320x240
cover?: boolean // Se é imagem principal
}
```
## 🎨 Gerador de Dados Fake Avançado
Sistema baseado em **profiling de dados reais** do Arbo CRM com **20+ atributos por imóvel**:
```typescript
import {
generateFakeProperty,
generateFakeProperties,
generateFakePropertyByType,
getAvailablePropertyTypes
} from '@horizon-modules/property-model-v3';
// Gerar uma propriedade aleatória
const property = generateFakeProperty();
// Gerar 50 propriedades
const properties = generateFakeProperties(50);
// Gerar tipo específico
const apartamento = generateFakePropertyByType("apartamento");
const casa = generateFakePropertyByType("casa");
const terreno = generateFakePropertyByType("terreno");
// Ver tipos disponíveis
console.log(getAvailablePropertyTypes());
// ["apartamento", "casa", "sobrado", "terreno", "comercial"]
```
### Características dos Dados Fake
- **📍 Localização brasileira**: 5 cidades + bairros reais
- **💰 Valores realistas**: Baseados em dados reais do Arbo CRM
- **🏠 Atributos contextuais**: 20-30 atributos por tipo de imóvel
- **🖼️ Imagens Unsplash**: URLs funcionais categorizadas por tipo
- **⚡ Performance**: Baseado em profiling estatístico
### Exemplo de Propriedade Fake Gerada
```json
{
"reference": "FAKE_APARTAMENTOS_001",
"title": "Apartamento Premium - 3 qtos, 150m², 3 vagas",
"description": "Apartamento moderno com acabamentos de primeira linha...",
"attributes": {
"tipo": "Apartamento",
"operacao": ["venda"],
"dormitorios": 3,
"banheiros": 2,
"suites": 1,
"vagas": 3,
"area_util": 150,
"area_total": 180,
"valor_venda": 1200000,
"valor_condominio": 800,
"andar": 12,
"endereco_cidade": "São Paulo",
"endereco_estado": "SP",
"endereco_bairro": "Vila Madalena",
"endereco_cep": "05414-000",
"caracteristicas": ["Churrasqueira", "Piscina", "Academia"],
"mobiliado": false,
"aceita_pets": true,
"portao_eletronico": true
},
"media_assets": {
"images": [
{
"full": "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=800&q=80",
"cover": true
}
]
}
}
```
## 📊 ProfilerService - Análise de Dados
Ferramenta para **análise estatística** de datasets PropertyModel:
```typescript
import { ProfilerService, profileProperties } from '@horizon-modules/property-model-v3';
// Análise de arquivos
const profiler = new ProfilerService({
inputDir: './data/properties',
outputDir: './output',
fieldConfigs: {
'attributes.endereco_cidade': { maxExamples: 50 },
'attributes.caracteristicas': { maxExamples: 100 }
}
});
const report = await profiler.profile();
console.log(report);
// {
// "attributes.tipo": ["Casa", "Apartamento", "Terreno"],
// "attributes.endereco_cidade": ["São Paulo", "Rio de Janeiro", ...],
// "attributes.caracteristicas": ["Churrasqueira", "Piscina", ...]
// }
// Análise em memória
const inMemoryReport = await profileProperties(propertyArray);
```
**Características:**
- ✅ **Concatena arrays**: Arrays de strings viram lista única de valores
- ✅ **Objetos aninhados**: Analisa `attributes.endereco_cidade`
- ✅ **Configurável**: Controle de quantos exemplos por campo
- ✅ **Genérico**: Funciona com qualquer estrutura JSON
## 🎨 Property Customizer - Transformação Baseada em Regras
Sistema para aplicar transformações complexas em dados PropertyV3 através de regras declarativas:
```typescript
import {
PropertyCustomizer,
type MapRules
} from '@horizon-modules/property-model-v3';
// Definir regras de transformação
const mapRules: MapRules = {
attributesRules: [
{
key: 'tipo',
condition: { eq: 'Casa de Condomínio' },
rules: [
{ fn: 'upsertAttr', key: 'tipo', value: 'Casa/Sobrado' },
{ fn: 'upsertAttr', key: 'subtipo', value: 'Casa' },
{ fn: 'addToArray', key: 'tags', value: 'em-condominio' }
]
},
{
key: 'caracteristicas',
condition: { has_any: ['Piscina'] },
rules: [
{ fn: 'removeFromArray', key: 'caracteristicas', value: 'Piscina' },
{ fn: 'upsertAttr', key: 'piscina', value: true }
]
}
]
};
// Aplicar transformações
const transformedProperty = PropertyCustomizer(property, mapRules);
```
### Actions Disponíveis
- **upsertAttr**: Criar/atualizar atributo
- **removeAttr**: Remover atributo
- **addToArray**: Adicionar valores a array
- **removeFromArray**: Remover valores de array
### Condições Suportadas
- **Igualdade**: `eq`, `not_eq`
- **Arrays**: `has`, `has_any`, `not_has`
- **Numéricos**: `gt`, `gte`, `lt`, `lte`
- **Texto**: `contains`, `starts_with`, `ends_with`
- **Booleanos**: `is_true`, `is_false`
- **Existência**: `exists`, `not_exists`
### Tags na Description
O sistema processa automaticamente tags especiais na description:
```typescript
const property = {
description: `Casa linda [[description-en]]Beautiful house[[/description-en]]
[[custom-attributes]]
{
"energia_solar": true,
"classificacao": "A+"
}
[[/custom-attributes]]
Com vista para o mar`
};
// Após processamento:
// property.attributes.description_en = 'Beautiful house'
// property.attributes.energia_solar = true
// property.description = 'Casa linda Com vista para o mar'
```
## 🌐 ApiClientService - Cliente HTTP
Cliente para envio de dados PropertyModel para APIs externas:
```typescript
import { ApiClientService } from '@horizon-modules/property-model-v3';
const client = new ApiClientService({
endpoint: 'https://api.imobiliaria.com/properties',
headers: { 'Authorization': 'Bearer token' },
batchSize: 10 // Processa 10 por vez
});
// Enviar uma propriedade
await client.sendProperty(property);
// Enviar múltiplas propriedades
await client.sendProperties([prop1, prop2, prop3]);
// Enviar de pasta com JSONs
await client.sendPropertiesFromDir('./data/fake-properties');
```
**Formatos suportados:**
- Array direto: `[prop1, prop2]`
- Formato data: `{ "data": [prop1, prop2] }`
- Categorizado: `{ "apartamentos": [prop1], "casas": [prop2] }`
## 🔒 Validação com Zod
Sistema robusto de validação em runtime:
```typescript
import {
PropertyModelSchema,
validatePropertyModel,
safeValidatePropertyModel
} from '@horizon-modules/property-model-v3';
// Validação direta (lança erro se inválido)
const property = validatePropertyModel(unknownData);
// Validação safe (nunca lança erro)
const result = safeValidatePropertyModel(unknownData);
if (result.success) {
console.log("✅ Válido:", result.data);
} else {
console.log("❌ Erros:", result.error.issues);
}
// Schema customizado
const StrictSchema = PropertyModelSchema.extend({
reference: z.string().min(5).max(20)
});
```
## 📋 JSON Schema Export
Schemas JSON para validação externa:
```typescript
import {
PropertyModelJsonSchema,
PropertyTypeSchemaJson
} from '@horizon-modules/property-model-v3';
// Usar com validadores JSON Schema
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(PropertyModelJsonSchema);
const isValid = validate(propertyData);
if (!isValid) {
console.log(validate.errors);
}
```
## 🛠️ Scripts de Desenvolvimento
Pipeline completo para desenvolvimento de dados:
### Scripts Principais
```bash
# Baixar dados reais do Arbo CRM
npm run dev:download
# Baixar dados fake do pacote arbo-crm
npm run dev:download-arbo-fake
# Converter dados Arbo para PropertyModel V3
npm run dev:convert
# Fazer profiling dos dados convertidos
npm run dev:profile
# Gerar dados fake baseados no profiling
npm run dev:fake
# Gerar mocks para testes
npm run dev:mocks
# Gerar JSON Schema
npm run dev:json-schema
# Testar JSON Schema
npm run dev:test-json-schema
# Pipeline completo
npm run dev:all
```
### Estrutura de Desenvolvimento
```
__dev__/
├── data/ # Dados temporários (não commitados)
│ ├── arbo-downloads/ # Dados reais do Arbo CRM
│ ├── arbo-fake-data-output/ # Dados fake do arbo-crm package
│ ├── property-v3-converted/ # Dados convertidos para V3
│ ├── property-v3-profiling/ # Relatórios de profiling
│ ├── property-v3-fake-data-output/ # Dados fake gerados
│ ├── property-v3-mock-output/ # Mocks para testes
│ └── json-schema/ # JSON Schema gerado
├── scripts/ # Scripts de desenvolvimento
│ ├── arbo-download-properties.ts # Baixa dados do Arbo
│ ├── arbo-download-fake-data.ts # Baixa fake data do arbo-crm
│ ├── arbo-convert-to-property-v3.ts # Converte para V3
│ ├── profile-properties.ts # Faz profiling
│ ├── generate-fake-data.ts # Gera dados fake
│ ├── generate-mocks.ts # Gera mocks
│ ├── generate-json-schema.ts # Gera JSON Schema
│ └── test-json-schema.ts # Testa JSON Schema
├── services/ # Serviços de desenvolvimento
│ └── MockGeneratorService.ts # Gerador de mocks
└── tests/ # Testes dos serviços dev
└── MockGeneratorService.test.ts
```
### Fluxo de Desenvolvimento
1. **🔄 Download**: `dev:download` → Baixa dados reais do Arbo CRM
2. **📊 Profiling**: `dev:profile` → Analisa padrões estatísticos nos dados
3. **🎨 Fake Data**: `dev:fake` → Gera dados fake baseados no profiling
4. **🧪 Mocks**: `dev:mocks` → Gera mocks para testes unitários
5. **📋 Schema**: `dev:json-schema` → Gera JSON Schema para validação externa
## 🏠 Modelo de Atributos
Sistema com **96 atributos pré-definidos** em 8 categorias:
```typescript
import { PropertyAttributesModel } from '@horizon-modules/property-model-v3';
// Ver todos os atributos disponíveis
console.log(PropertyAttributesModel.length); // 96
// Atributos por categoria
const comerciais = PropertyAttributesModel.filter(attr => attr.cat === "comercial");
const valores = PropertyAttributesModel.filter(attr => attr.cat === "valores");
const dependencias = PropertyAttributesModel.filter(attr => attr.cat === "dependencias");
// Buscar atributo específico
const dormitorios = PropertyAttributesModel.find(attr => attr.key === "dormitorios");
console.log(dormitorios);
// { key: "dormitorios", label: "Dormitórios", type: "Number", cat: "dependencias" }
```
### Categorias de Atributos
1. **comercial** (8): `operacao`, `status_comercial`, `financiavel`, `aceita_permuta`
2. **valores** (12): `valor_venda`, `valor_locacao`, `valor_condominio`, `valor_iptu`
3. **situacoes** (6): `disponivel`, `reservado`, `vendido`, `alugado`
4. **localizacao** (15): `endereco_cidade`, `endereco_bairro`, `latitude`, `longitude`
5. **estrutura** (20): `tipo`, `subtipo`, `area_total`, `area_util`, `conservacao`
6. **dependencias** (8): `dormitorios`, `banheiros`, `suites`, `vagas`
7. **caracteristicas** (15): `mobiliado`, `aceita_pets`, `churrasqueira`, `piscina`
8. **corretor** (12): `corretor_nome`, `corretor_telefone`, `corretor_email`
## 🔧 Utilitários
```typescript
import {
verifyAttrKeyInPropertyV3Model,
mergePropertyAttributesModel,
sortAttributes,
preparaAttrValueLabel,
unitListModel,
formatListModel
} from '@horizon-modules/property-model-v3';
// Verificar se atributo existe
const attr = verifyAttrKeyInPropertyV3Model("dormitorios");
// Mesclar modelos de atributos
const customModel = mergePropertyAttributesModel(
PropertyAttributesModel,
[{ key: "piscina", label: "Piscina", type: "Boolean" }]
);
// Formatar labels de arrays
preparaAttrValueLabel(["venda", "locacao"]);
// Retorna: "venda e locacao"
// Unidades disponíveis
console.log(unitListModel.currency); // [{ key: "BRL", label: "R$" }]
console.log(unitListModel.area); // [{ key: "m2", label: "m²" }]
```
## 🧪 Testes
```bash
# Executar todos os testes
npm run test
# Testes com cobertura
npm run test:coverage
# Testes dos serviços de desenvolvimento
npm run dev:test
# Verificação de tipos
npm run typecheck
# Build
npm run build
```
## 📈 Exemplo Completo
```typescript
import {
generateFakeProperties,
ProfilerService,
ApiClientService,
validatePropertyModel
} from '@horizon-modules/property-model-v3';
async function exemploCompleto() {
// 1. Gerar 100 propriedades fake
console.log('🎨 Gerando dados fake...');
const properties = generateFakeProperties(100);
// 2. Validar todas as propriedades
console.log('🔍 Validando propriedades...');
const validProperties = properties.filter(prop => {
try {
validatePropertyModel(prop);
return true;
} catch {
return false;
}
});
console.log(`✅ ${validProperties.length}/${properties.length} propriedades válidas`);
// 3. Fazer profiling dos dados
console.log('📊 Fazendo profiling...');
const profiler = new ProfilerService({ inputData: validProperties });
const report = await profiler.profile();
console.log('Tipos encontrados:', report['attributes.tipo']);
console.log('Cidades encontradas:', report['attributes.endereco_cidade']);
// 4. Enviar para API (exemplo)
const client = new ApiClientService({
endpoint: 'https://api.exemplo.com/properties',
batchSize: 5
});
console.log('🚀 Enviando para API...');
await client.sendProperties(validProperties.slice(0, 10));
console.log('🎉 Processo concluído!');
}
exemploCompleto().catch(console.error);
```
## 🚀 Integração com Arbo CRM
O projeto integra nativamente com o `@horizon-modules/arbo-crm-integration`:
```typescript
// Os scripts de desenvolvimento usam o arbo-crm-integration
// para baixar dados reais e convertê-los para PropertyModel V3
// Dados reais → Profiling → Fake data realista
// Este processo garante que os dados fake sejam baseados
// em dados reais do mercado imobiliário brasileiro
```
## 📦 Exports Principais
```typescript
// Modelos e Tipos
export type { PropertyModel, MediaAssets, SettingsFormat }
// Schemas Zod
export { PropertyModelSchema, validatePropertyModel, safeValidatePropertyModel }
// JSON Schemas
export { PropertyModelJsonSchema, PropertyTypeSchemaJson }
// Gerador de Dados Fake
export { generateFakeProperty, generateFakeProperties, generateFakePropertyByType }
// Serviços
export { ProfilerService, ApiClientService }
// Property Customizer
export { PropertyCustomizer }
export type { PropertyV3, MapRules, AttributeRule, CustomAction }
// Modelo de Atributos
export { PropertyAttributesModel, unitListModel, formatListModel }
// Utilitários
export { verifyAttrKeyInPropertyV3Model, mergePropertyAttributesModel, sortAttributes }
```
## 🔄 Migração do V2 para V3
### Principais Mudanças
1. **Atributos**: Array → Objeto chave-valor
2. **Media**: `media` → `media_assets` com estrutura tipada
3. **Validação**: Zod schemas obrigatórios
4. **Settings**: Novo campo para configurações de formato
### Exemplo de Migração
```typescript
// V2
const propertyV2 = {
reference: "AP001",
attributes: [
{ key: "dormitorios", value: 3 },
{ key: "valor_venda", value: 850000, unit: "BRL" }
],
media: {
pictures: ["foto1.jpg", "foto2.jpg"]
}
};
// V3
const propertyV3 = {
reference: "AP001",
title: "Apartamento 3 dormitórios",
description: "Descrição do imóvel...",
attributes: {
dormitorios: 3,
valor_venda: 850000
},
media_assets: {
images: [
{ full: "foto1.jpg", cover: true },
{ full: "foto2.jpg", cover: false }
]
},
settings: {
currency_unit: "BRL",
area_unit: "m2"
}
};
```
---
## 📄 Licença
MIT - veja [LICENSE](LICENSE) para detalhes.
**Desenvolvido pela Horizon Modules** 🏗️