📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados em Módulo 08: Bancos de Dados SQL e NoSQL. Recomendado revisar antes de começar.

🏪 Modelagem Visual EER & Stored Procedures Transacionais no MySQL

v1.0 — Normalização Formal (1FN a 3FN), Bloqueio Pessimista e Controle de Crediário

Trilha de Engenharia de Dados & Bancos de Dados — Projeto 5 de 10

🎓 Nível Profissional Simulado: Desenvolvedor Pleno / Especialista SQL. No comércio varejista de bairro com crediário próprio (caderneta/fiado), a gestão de débitos e amortizações precisa de garantia transacional absoluta com bloqueio de concorrência (SELECT ... FOR UPDATE), evitando amortizações duplicadas ou saldos negativos.


🎯 Objetivo

Modelar um esquema visual EER para controle de vendas a prazo e amortização de fiado no MySQL 8.0, aplicando decomposição formal até a Terceira Forma Normal (3FN) e construindo uma Stored Procedure Transacional (sp_registrar_pagamento_fiado) com controle explícito de START TRANSACTION, COMMIT, ROLLBACK e bloqueio de linha.


🏗️ Diagrama de Entidade-Relacionamento Estendido (EER)

erDiagram
    CLIENTES ||--o{ VENDAS : "compra (1:N)"
    CLIENTES ||--o{ RECIBOS_PAGAMENTO : "amortiza (1:N)"
    VENDAS ||--|{ ITENS_VENDA : "possui (1:N)"
    PRODUTOS ||--o{ ITENS_VENDA : "vendido_em (1:N)"

    CLIENTES {
        int id PK
        string nome
        string cpf UK
        decimal saldo_devedor "CHECK >= 0"
        decimal limite_credito
    }

    PRODUTOS {
        int id PK
        string codigo_barras UK
        string nome
        decimal preco_venda "CHECK > 0"
        int estoque_atual "CHECK >= 0"
    }

    VENDAS {
        int id PK
        int cliente_id FK
        datetime data_venda
        enum forma_pagamento "A_VISTA|CREDIARIO_FIADO|CARTAO"
        decimal valor_total
    }

    RECIBOS_PAGAMENTO {
        int id PK
        int cliente_id FK
        decimal valor_pago "CHECK > 0"
        datetime data_pagamento
    }

🧑‍💼 Fase 1 — Levantamento de Requisitos

O Briefing do Cliente (Dono do Supermercado de Bairro)

“No nosso mercado, muitos clientes compram fiado e pagam aos poucos todo sábado. Tivemos casos em que dois caixas registraram o pagamento ao mesmo tempo e o saldo do cliente ficou negativado, ou o sistema caiu no meio do processo e o dinheiro sumiu do caixa sem dar baixa na conta do cliente. Precisamos de uma rotina blindada que bloqueie a conta durante o pagamento e garanta que o recibo só seja emitido se o débito for abatido com sucesso.”

Requisitos Funcionais (RF) e Não-Funcionais (RNF)

ID Tipo Descrição Origem no Briefing
RF01 Funcional Permitir amortização parcial ou total do saldo devedor do cliente via Stored Procedure. “pagam aos poucos todo sábado”
RF02 Funcional Impedir pagamentos com valor superior ao saldo devedor atual (valor_pago <= saldo_devedor). “saldo do cliente ficou negativado”
RF03 Funcional Gerar recibo histórico atômico com data e valor no mesmo momento do abatimento. “recibo só emitido se abatido”
RNF01 Não-Funcional Bloqueio pessimista de linha (FOR UPDATE) para evitar concorrência entre caixas. Atomicidade de Caixa
RNF02 Não-Funcional Engine transacional InnoDB com rollback automático em caso de falha de hardware/rede. Confiabilidade ACID

📋 Fase 2 — Backlog & User Stories

ID User Story Prioridade
US01 Como operador de caixa, quero amortizar o fiado do cliente chamando uma Stored Procedure segura. Alta
US02 Como cliente, quero receber o recibo comprovando o valor pago e o novo saldo devedor. Alta
US03 Como gerente, quero que tentativas de pagamento inválidas disparem rollback sem afetar os dados. Alta

🌿 Fase 3 — Engenharia em Equipe (Git Flow & Setup)

# Branch da funcionalidade
git checkout -b feature/US01-mysql-stored-procedure

# Subir o MySQL isolado via Docker
docker-compose up -d

# Conectar via MySQL Client
docker exec -it db_mysql_varejo mysql -u lojista -plojistapassword varejo_db

🛠️ Fase 4 — Implementação Passo a Passo (sql/02_procedure_pagamento.sql)

DELIMITER $$
CREATE PROCEDURE sp_registrar_pagamento_fiado(
    IN p_cliente_id INT,
    IN p_valor_pago DECIMAL(10,2),
    OUT p_status_mensagem VARCHAR(100)
)
BEGIN
    DECLARE v_saldo_devedor DECIMAL(10,2);
    
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        SET p_status_mensagem = 'ERRO: Falha ao processar a transação.';
    END;

    START TRANSACTION;
        SELECT saldo_devedor INTO v_saldo_devedor 
        FROM clientes 
        WHERE id = p_cliente_id FOR UPDATE;

        IF v_saldo_devedor IS NULL THEN
            SET p_status_mensagem = 'ERRO: Cliente inexistente.';
            ROLLBACK;
        ELSEIF p_valor_pago > v_saldo_devedor THEN
            SET p_status_mensagem = 'ERRO: Pagamento maior que o débito.';
            ROLLBACK;
        ELSE
            UPDATE clientes 
            SET saldo_devedor = saldo_devedor - p_valor_pago 
            WHERE id = p_cliente_id;

            INSERT INTO recibos_pagamento (cliente_id, valor_pago, data_pagamento)
            VALUES (p_cliente_id, p_valor_pago, NOW());

            SET p_status_mensagem = 'SUCESSO: Pagamento amortizado.';
            COMMIT;
        END IF;
END$$
DELIMITER ;

🧭 Decisões Técnicas (ADRs)


🚀 Como Executar no Laboratório

1. Abra o terminal na pasta deste projeto

No seu editor/IDE, abra a pasta deste projeto (File > Open Folder) ou navegue via terminal:

cd db_sql_05_mysql_eer_procedures

2. Execute a aplicação ou testes

docker-compose up -d
# Executar a suíte de testes automatizados:
python -m unittest tests/test_mysql_procedures.py

[!TIP] Dica para execução a partir da raiz do repositório: Se você abriu o repositório completo no VS Code, basta navegar até a pasta antes de executar: cd catalogo_projetos/db_sql_05_mysql_eer_procedures


🧪 Testes de Validação & Asserções

-- 1. Executar a Stored Procedure para amortizar R$ 150.00
CALL sp_registrar_pagamento_fiado(1, 150.00, @msg);
SELECT @msg AS resultado_operacao;

-- 2. Validar que o saldo devedor baixou para R$ 200.00
SELECT id, nome, saldo_devedor FROM clientes WHERE id = 1;
SELECT * FROM recibos_pagamento WHERE cliente_id = 1;


🏛️ Arquitetura Visual & Engenharia de Dados

A arquitetura abaixo demonstra o fluxo de persistência, otimização e isolamento dos componentes na subpasta sql/:

Arquitetura do Banco de Dados

flowchart TD
    subgraph DDL["Modelagem & Schema (DDL)"]
        S1["Tabelas / Coleções"] --> S2["Constraints & Índices"]
    end
    subgraph DML["Regras & Automação (DML / PL)"]
        R1["Triggers / Aggregations"] --> R2["Procedimentos Transacionais"]
    end
    subgraph Perf["Otimização & Armazenamento"]
        P1["Planos EXPLAIN / Partições"] --> P2["Garantia de ACID / TTL"]
    end
    subgraph Homolog["Homologação & Qualidade"]
        Q1["Docker Compose & Scripts"] --> Q2["Checkpoints CP-01..05 PASS"]
    end

    DDL --> DML
    DML --> Perf
    Perf --> Homolog

    style DDL fill:#e3f2fd,stroke:#1976d2,stroke-width:1.5px
    style DML fill:#fffde7,stroke:#fbc02d,stroke-width:1.5px
    style Perf fill:#e8f5e9,stroke:#388e3c,stroke-width:1.5px
    style Homolog fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1.5px

🎯 Engenharia de Requisitos & Modelagem Formal

👤 User Stories (Histórias de Usuário)

ID Persona História de Usuário Critério de Aceite Prioridade
US-01 Arquiteto de Dados Desejo modelagem EER para gestão de estoque e vendas de varejo Diagrama visual com herança, subtipos e cardinalidades estritas no MySQL Alta
US-02 Desenvolvedor Backend Desejo Stored Procedure para processamento de checkout com controle transacional START TRANSACTION, COMMIT e ROLLBACK em handlers de SQLEXCEPTION Alta
US-03 DBA MySQL Desejo triggers de auditoria registrando histórico de alterações de preços Tabela de log populada automaticamente em eventos BEFORE/AFTER UPDATE Alta
US-04 Operador Financeiro Desejo funções determinísticas (UDF) para cálculo de descontos progressivos Function MySQL reutilizável em consultas SELECT e relatórios Média
US-05 Auditor de Sistemas Desejo testes comprovando que falhas no meio do checkout não deixam dados órfãos Bateria de testes simulando erros de concorrência e rollback automático Média

⚙️ Requisitos Funcionais (RF)

ID Descrição do Requisito Criticidade
RF-01 Modelo relacional EER completo com chaves primárias e estrangeiras Alta
RF-02 Stored Procedures de checkout com tratamento de exceções (DECLARE HANDLER) Alta
RF-03 Triggers de auditoria e versionamento de dados sensíveis Alta
RF-04 Funções customizadas para cálculo de impostos e tarifas no banco Média
RF-05 Scripts SQL organizados e suíte de testes de estresse transacional Média

🛡️ Requisitos Não-Funcionais (RNF)

ID Especificação Arquitetural Criticidade
RNF-01 Isolamento transacional REPEATABLE READ nativo do motor InnoDB Alta
RNF-02 Bloqueios pessimistas (SELECT … FOR UPDATE) prevenindo venda sem estoque Alta
RNF-03 Compatibilidade total com MySQL 8.0+ Média
RNF-04 Execução reprodutível via Docker Compose Média
RNF-05 Estruturação dos artefatos na pasta sql/ Alta

🔗 Matriz de Rastreabilidade (RTM)

User Story Requisito Funcional Requisito Não-Funcional Módulo / Artefato de Código Status de Homologação
US-01 RF-01 RNF-01, RNF-03 sql/01_eer_schema.sql Testado
US-02 RF-02 RNF-01, RNF-02 sql/02_procedures.sql Testado
US-03 RF-03 RNF-01, RNF-04 sql/03_triggers.sql Testado
US-04 RF-04 RNF-02, RNF-03 sql/04_functions.sql Testado
US-05 RF-05 RNF-01, RNF-05 tests/test_procedures.py Testado

🏁 Checkpoints de Qualidade & Homologação

Checkpoint Escopo da Validação Artefato Verificado Status
CP-01 Subida Conteinerizada do Ambiente docker-compose.yml PASS ✅
CP-02 Criação de Estrutura & Schemas sql/ PASS ✅
CP-03 Automação Transacional & Regras Triggers / Queries PASS ✅
CP-04 Otimização de Performance & Índices Indexes / Tuning PASS ✅
CP-05 Homologação com Suíte de Testes tests/ PASS ✅