DuOrigin v2 - React + NestJS + Prisma + EUDR API Integration
This commit is contained in:
133
backend/prisma/schema.prisma
Normal file
133
backend/prisma/schema.prisma
Normal file
@@ -0,0 +1,133 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
OPERADOR
|
||||
}
|
||||
|
||||
enum StatusAvaliacao {
|
||||
RASCUNHO
|
||||
EM_ANALISE
|
||||
APROVADA
|
||||
REPROVADA
|
||||
}
|
||||
|
||||
enum NivelRisco {
|
||||
BAIXO
|
||||
MEDIO
|
||||
ALTO
|
||||
CRITICO
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
password String
|
||||
nome String
|
||||
role Role @default(OPERADOR)
|
||||
ativo Boolean @default(true)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
avaliacoes Avaliacao[]
|
||||
documentos Documento[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Empresa {
|
||||
id Int @id @default(autoincrement())
|
||||
razaoSocial String @map("razao_social")
|
||||
nomeFantasia String? @map("nome_fantasia")
|
||||
cnpj String @unique
|
||||
inscricaoEstadual String? @map("inscricao_estadual")
|
||||
atividadeAgricola String? @map("atividade_agricola")
|
||||
endereco String?
|
||||
cidade String?
|
||||
estado String?
|
||||
cep String?
|
||||
telefone String?
|
||||
email String?
|
||||
responsavel String?
|
||||
ativo Boolean @default(true)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
propriedades Propriedade[]
|
||||
|
||||
@@map("empresas")
|
||||
}
|
||||
|
||||
model Propriedade {
|
||||
id Int @id @default(autoincrement())
|
||||
nome String
|
||||
empresaId Int @map("empresa_id")
|
||||
codigoCar String? @map("codigo_car")
|
||||
areaHa Float? @map("area_ha")
|
||||
latitude Float?
|
||||
longitude Float?
|
||||
bioma String?
|
||||
endereco String?
|
||||
cidade String?
|
||||
estado String?
|
||||
nivelRisco NivelRisco @default(BAIXO) @map("nivel_risco")
|
||||
flagDesmatamento String? @map("flag_desmatamento")
|
||||
geojson String? @db.Text
|
||||
ativo Boolean @default(true)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
empresa Empresa @relation(fields: [empresaId], references: [id], onDelete: Cascade)
|
||||
avaliacoes Avaliacao[]
|
||||
documentos Documento[]
|
||||
|
||||
@@map("propriedades")
|
||||
}
|
||||
|
||||
model Avaliacao {
|
||||
id Int @id @default(autoincrement())
|
||||
propriedadeId Int @map("propriedade_id")
|
||||
userId Int @map("user_id")
|
||||
referencia String @unique
|
||||
status StatusAvaliacao @default(RASCUNHO)
|
||||
nivelRisco NivelRisco @default(BAIXO) @map("nivel_risco")
|
||||
dataAvaliacao DateTime? @map("data_avaliacao")
|
||||
dataSubmissao DateTime? @map("data_submissao")
|
||||
observacoes String? @db.Text
|
||||
resultadoDds String? @map("resultado_dds") @db.Text
|
||||
referenciaEu String? @map("referencia_eu")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
propriedade Propriedade @relation(fields: [propriedadeId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
documentos Documento[]
|
||||
|
||||
@@map("avaliacoes")
|
||||
}
|
||||
|
||||
model Documento {
|
||||
id Int @id @default(autoincrement())
|
||||
nome String
|
||||
tipo String?
|
||||
tamanho Int?
|
||||
mimeType String? @map("mime_type")
|
||||
path String
|
||||
propriedadeId Int? @map("propriedade_id")
|
||||
avaliacaoId Int? @map("avaliacao_id")
|
||||
userId Int @map("user_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
propriedade Propriedade? @relation(fields: [propriedadeId], references: [id], onDelete: Cascade)
|
||||
avaliacao Avaliacao? @relation(fields: [avaliacaoId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@map("documentos")
|
||||
}
|
||||
328
backend/prisma/seed.ts
Normal file
328
backend/prisma/seed.ts
Normal file
@@ -0,0 +1,328 @@
|
||||
import { PrismaClient, Role, NivelRisco, StatusAvaliacao } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Seeding database...');
|
||||
|
||||
// Create users
|
||||
const adminPassword = await bcrypt.hash('DuoDemo2026', 10);
|
||||
const operadorPassword = await bcrypt.hash('DuoDemo2026', 10);
|
||||
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: 'demo@duorigin.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'demo@duorigin.com',
|
||||
password: adminPassword,
|
||||
nome: 'Administrador Demo',
|
||||
role: Role.ADMIN,
|
||||
ativo: true,
|
||||
},
|
||||
});
|
||||
|
||||
const operador = await prisma.user.upsert({
|
||||
where: { email: 'operador@duorigin.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'operador@duorigin.com',
|
||||
password: operadorPassword,
|
||||
nome: 'Operador Demo',
|
||||
role: Role.OPERADOR,
|
||||
ativo: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Users created:', { admin: admin.email, operador: operador.email });
|
||||
|
||||
// Create empresas
|
||||
const empresas = await Promise.all([
|
||||
prisma.empresa.upsert({
|
||||
where: { cnpj: '12.345.678/0001-90' },
|
||||
update: {},
|
||||
create: {
|
||||
razaoSocial: 'Fazenda Bom Sucesso Ltda',
|
||||
nomeFantasia: 'Fazenda Bom Sucesso',
|
||||
cnpj: '12.345.678/0001-90',
|
||||
inscricaoEstadual: '123.456.789.012',
|
||||
atividadeAgricola: 'Soja, Milho',
|
||||
endereco: 'Rodovia BR-050, Km 45',
|
||||
cidade: 'Uberlândia',
|
||||
estado: 'MG',
|
||||
cep: '38400-000',
|
||||
telefone: '(34) 99999-0001',
|
||||
email: 'contato@bomsucesso.com.br',
|
||||
responsavel: 'João Silva',
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
prisma.empresa.upsert({
|
||||
where: { cnpj: '23.456.789/0001-01' },
|
||||
update: {},
|
||||
create: {
|
||||
razaoSocial: 'Agropecuária São José S.A.',
|
||||
nomeFantasia: 'São José Agro',
|
||||
cnpj: '23.456.789/0001-01',
|
||||
inscricaoEstadual: '234.567.890.123',
|
||||
atividadeAgricola: 'Café, Pecuária',
|
||||
endereco: 'Estrada Municipal SP-123, Km 10',
|
||||
cidade: 'Ribeirão Preto',
|
||||
estado: 'SP',
|
||||
cep: '14000-000',
|
||||
telefone: '(16) 99999-0002',
|
||||
email: 'contato@saojoseagro.com.br',
|
||||
responsavel: 'Maria Santos',
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
prisma.empresa.upsert({
|
||||
where: { cnpj: '34.567.890/0001-12' },
|
||||
update: {},
|
||||
create: {
|
||||
razaoSocial: 'Cooperativa Agrícola Vale Verde',
|
||||
nomeFantasia: 'Coop Vale Verde',
|
||||
cnpj: '34.567.890/0001-12',
|
||||
inscricaoEstadual: '345.678.901.234',
|
||||
atividadeAgricola: 'Soja, Algodão, Milho',
|
||||
endereco: 'Av. Principal, 1000',
|
||||
cidade: 'Rondonópolis',
|
||||
estado: 'MT',
|
||||
cep: '78700-000',
|
||||
telefone: '(66) 99999-0003',
|
||||
email: 'contato@valeverde.coop.br',
|
||||
responsavel: 'Carlos Oliveira',
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log('✅ Empresas created:', empresas.length);
|
||||
|
||||
// Create propriedades
|
||||
const propriedades = await Promise.all([
|
||||
prisma.propriedade.create({
|
||||
data: {
|
||||
nome: 'Fazenda Primavera',
|
||||
empresaId: empresas[0].id,
|
||||
codigoCar: 'MG-3170206-A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6',
|
||||
areaHa: 1500.5,
|
||||
latitude: -18.9186,
|
||||
longitude: -48.2772,
|
||||
bioma: 'Cerrado',
|
||||
endereco: 'Zona Rural, Lote 45',
|
||||
cidade: 'Uberlândia',
|
||||
estado: 'MG',
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
flagDesmatamento: 'clean',
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
prisma.propriedade.create({
|
||||
data: {
|
||||
nome: 'Sítio Esperança',
|
||||
empresaId: empresas[0].id,
|
||||
codigoCar: 'MG-3170206-B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7',
|
||||
areaHa: 320.0,
|
||||
latitude: -18.8500,
|
||||
longitude: -48.3000,
|
||||
bioma: 'Cerrado',
|
||||
cidade: 'Uberlândia',
|
||||
estado: 'MG',
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
prisma.propriedade.create({
|
||||
data: {
|
||||
nome: 'Fazenda São José',
|
||||
empresaId: empresas[1].id,
|
||||
codigoCar: 'SP-3543402-C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8',
|
||||
areaHa: 850.75,
|
||||
latitude: -21.1767,
|
||||
longitude: -47.8108,
|
||||
bioma: 'Mata Atlântica',
|
||||
cidade: 'Ribeirão Preto',
|
||||
estado: 'SP',
|
||||
nivelRisco: NivelRisco.MEDIO,
|
||||
flagDesmatamento: 'under_review',
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
prisma.propriedade.create({
|
||||
data: {
|
||||
nome: 'Fazenda Pioneira',
|
||||
empresaId: empresas[2].id,
|
||||
codigoCar: 'MT-5107602-D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9',
|
||||
areaHa: 5200.0,
|
||||
latitude: -16.4673,
|
||||
longitude: -54.6372,
|
||||
bioma: 'Cerrado',
|
||||
cidade: 'Rondonópolis',
|
||||
estado: 'MT',
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
prisma.propriedade.create({
|
||||
data: {
|
||||
nome: 'Fazenda Horizonte',
|
||||
empresaId: empresas[2].id,
|
||||
codigoCar: 'MT-5107602-E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0',
|
||||
areaHa: 3800.25,
|
||||
latitude: -16.5000,
|
||||
longitude: -54.7000,
|
||||
bioma: 'Cerrado',
|
||||
cidade: 'Rondonópolis',
|
||||
estado: 'MT',
|
||||
nivelRisco: NivelRisco.ALTO,
|
||||
flagDesmatamento: 'flagged',
|
||||
ativo: true,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log('✅ Propriedades created:', propriedades.length);
|
||||
|
||||
// Create avaliacoes
|
||||
const generateRef = () => {
|
||||
const timestamp = Date.now().toString(36).toUpperCase();
|
||||
const random = Math.random().toString(36).substring(2, 6).toUpperCase();
|
||||
return `DUO-${timestamp}-${random}`;
|
||||
};
|
||||
|
||||
const avaliacoes = await Promise.all([
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[0].id,
|
||||
userId: admin.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.APROVADA,
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
dataAvaliacao: new Date('2024-01-15'),
|
||||
dataSubmissao: new Date('2024-01-20'),
|
||||
observacoes: 'Propriedade em conformidade com EUDR.',
|
||||
referenciaEu: 'EU-ABC123',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[0].id,
|
||||
userId: operador.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.EM_ANALISE,
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
dataAvaliacao: new Date('2024-06-01'),
|
||||
observacoes: 'Aguardando documentação adicional.',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[1].id,
|
||||
userId: admin.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.RASCUNHO,
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
dataAvaliacao: new Date(),
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[2].id,
|
||||
userId: operador.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.EM_ANALISE,
|
||||
nivelRisco: NivelRisco.MEDIO,
|
||||
dataAvaliacao: new Date('2024-05-10'),
|
||||
dataSubmissao: new Date('2024-05-15'),
|
||||
observacoes: 'Área com histórico de desmatamento em análise.',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[2].id,
|
||||
userId: admin.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.REPROVADA,
|
||||
nivelRisco: NivelRisco.ALTO,
|
||||
dataAvaliacao: new Date('2024-03-01'),
|
||||
dataSubmissao: new Date('2024-03-10'),
|
||||
observacoes: 'Documentação irregular. Necessário revisão.',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[3].id,
|
||||
userId: admin.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.APROVADA,
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
dataAvaliacao: new Date('2024-02-20'),
|
||||
dataSubmissao: new Date('2024-02-25'),
|
||||
referenciaEu: 'EU-DEF456',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[3].id,
|
||||
userId: operador.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.RASCUNHO,
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
dataAvaliacao: new Date(),
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[4].id,
|
||||
userId: admin.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.EM_ANALISE,
|
||||
nivelRisco: NivelRisco.ALTO,
|
||||
dataAvaliacao: new Date('2024-06-05'),
|
||||
dataSubmissao: new Date('2024-06-10'),
|
||||
observacoes: 'Área com risco alto de desmatamento identificado.',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[4].id,
|
||||
userId: operador.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.REPROVADA,
|
||||
nivelRisco: NivelRisco.CRITICO,
|
||||
dataAvaliacao: new Date('2024-04-01'),
|
||||
dataSubmissao: new Date('2024-04-05'),
|
||||
observacoes: 'Desmatamento ilegal detectado. Propriedade bloqueada.',
|
||||
},
|
||||
}),
|
||||
prisma.avaliacao.create({
|
||||
data: {
|
||||
propriedadeId: propriedades[1].id,
|
||||
userId: operador.id,
|
||||
referencia: generateRef(),
|
||||
status: StatusAvaliacao.APROVADA,
|
||||
nivelRisco: NivelRisco.BAIXO,
|
||||
dataAvaliacao: new Date('2024-01-05'),
|
||||
dataSubmissao: new Date('2024-01-10'),
|
||||
referenciaEu: 'EU-GHI789',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log('✅ Avaliacoes created:', avaliacoes.length);
|
||||
|
||||
console.log('🎉 Seed completed successfully!');
|
||||
console.log('\n📝 Login credentials:');
|
||||
console.log(' Admin: demo@duorigin.com / DuoDemo2026');
|
||||
console.log(' Operador: operador@duorigin.com / DuoDemo2026');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('❌ Seed error:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user