gerenciador de entregas fotográficas

Lumina.

Plataforma segura para entrega de galerias com marca d'água e liberação controlada de arquivos originais em alta resolução.

Kotlin Spring Boot Rust Apache Kafka PostgreSQL Nginx Jaspr MinIO Docker
01

O Problema Real

A Lumina nasce de uma dor concreta: a fotógrafa finaliza as fotos no seu PC e precisa apresentá-las ao cliente de forma profissional — mas com segurança total contra roubo antes do pagamento.

📸
A Dor
Print de tela e "salvar imagem como" são ameaças reais. O cliente vê, gosta e pode roubar o trabalho antes do pagamento final. A fotógrafa não tem controle.
🎯
O Objetivo
Entregar uma experiência de visualização premium, garantir que nenhuma original seja baixada sem permissão, e liberar os arquivos de forma automatizada e temporária no momento certo.
Mapa Mental do Domínio
interativo
Lumina Plataforma de Entregas Regras de Negócio Core Imutabilidade da Origem Proteção Obrigatória Trava de Download Efemeridade Arquitetura Técnica Open-Source Kotlin · Cérebro API PostgreSQL · Estado Kafka · Mensageria Rust · Worker Jaspr · Frontend Atores Usuários Fotógrafa (Admin) → Faz upload → Gerencia projetos → Libera downloads Cliente (Visualizador) → Acessa link mágico → Vê galeria c/ marca Fluxo de Valor Jornada Criação do Ensaio Upload Massivo Processamento Async Link Público Liberar Download Expiração + Limpeza
02

Atores do Sistema

Dois perfis completamente separados, com papéis e permissões distintos. Apenas a fotógrafa tem conta no sistema.

📸
Fotógrafa
Admin · Dona
  • Controle absoluto sobre o sistema
  • Cria projetos (ensaios) e sobe as fotos
  • Gera e envia o Link Mágico ao cliente
  • Aciona "Liberar Download" no painel admin
👤
Cliente
Espectador · Passivo
  • Sem login ou senha no sistema
  • Acessa exclusivamente via Link Mágico com token secreto
  • Visualiza as fotos com marca d'água aplicada
  • Quando liberado, baixa o .zip com as originais
03

Jornada de Valor

Clique em cada etapa para ver os detalhes. O fluxo é linear, sem fricção e seguro do início ao fim. (Auto-avança a cada 3s)

01
Criação do Projeto
A fotógrafa cria um novo ensaio no painel admin. Ex: "Casamento Guaramiranga – João e Maria". Define o título e as configurações de entrega.
painel admin
02
Upload em Massa
A fotógrafa seleciona as fotos finais já tratadas e faz upload em alta resolução. O Spring Boot salva os originais no Object Storage e persiste os metadados.
spring boot + minio
03
Processamento Assíncrono
Spring Boot publica evento no Kafka. O Rust Worker consome, redimensiona e aplica a marca d'água. Ao concluir, publica evento de conclusão de volta.
kafka + rust worker
04
Envio do Link Mágico
A fotógrafa gera o Link Mágico (URL com public_token) e envia ao cliente. Ele acessa sem criar conta e visualiza as fotos com marca d'água.
public_token na URL
05
Liberação do Download
Após acerto financeiro externo, a fotógrafa clica em "Liberar Download". allow_download=true no banco. O link ganha botão para baixar .zip com as originais.
allow_download = true
06
Expiração e Limpeza
Após o prazo definido, o link expira. Os originais em alta resolução são deletados fisicamente. O projeto permanece no painel apenas como histórico com as previews.
efemeridade
Fluxograma do Sistema
Passo 1 de 6
Fotógrafa faz Login painel admin Cria Novo Projeto (Ensaio) projects table · DB Upload Fotos Alta Resolução spring boot → storage original upload ok? Não Sim Kafka → Rust Worker processa resize · aplica marca d'água Fotógrafa gera Link Mágico public_token · envia ao cliente Cliente acessa galeria visualiza com marca d'água
04

Regras de Negócio

As "Leis do Sistema" — princípios inegociáveis. Toda decisão de arquitetura respeita estas regras.

🔏

Marca d'Água Obrigatória

Nenhuma imagem exibida na galeria web do cliente será o arquivo original limpo. O sistema sempre exibirá uma versão reduzida com a logo da fotógrafa. Inviabiliza roubo por print de tela.

preview_file_path
🧊

Imutabilidade da Origem

O arquivo original em altíssima resolução nunca é alterado. O sistema só cria cópias "sujas" para exibição. O arquivo de 30MB permanece intacto no Object Storage.

original_file_path
🔒

Trava de Download

Na visualização padrão da galeria é impossível baixar os originais. Apenas o botão "Liberar Download", acionado exclusivamente pela fotógrafa no painel, muda este estado.

allow_download = false

Efemeridade

A plataforma não é um serviço de backup. Links expiram. Quando o download é liberado, o cliente tem um prazo definido para baixar. Depois, o link morre e os originais são deletados do servidor.

deleted_at
05

Arquitetura de Software

Arquitetura orientada a eventos. O processamento pesado de imagens é completamente desacoplado do ciclo HTTP. Clique em cada componente para explorar.

🌐
Jaspr
Frontend Web · Dart
:80
HTTP REST
⚙️
Spring Boot
API Backend · Kotlin
:8080
SQL/JDBC
Publish events
🗄️
PostgreSQL
Estado
📨
Kafka
Mensageria
Consume events
🦀
Rust Worker
Background daemon
S3 SDK
🗃️
MinIO / S3
Object Storage
:9000
Selecione um componente
clique em qualquer bloco à esquerda
A Lumina é composta por 6 peças que se comunicam de forma assíncrona. O Spring Boot é o cérebro: recebe HTTP, persiste dados, publica eventos no Kafka. O Rust Worker consome e processa as imagens de forma independente, sem bloquear a API.
Fluxo de comunicação assíncrona — upload de foto
1. POST /upload
Jaspr → API
2. Salva original
API → DB + Storage
3. Publica evento
API → Kafka
4. Consome
Kafka → Rust Worker
5. Processa + salva
Worker → MinIO
6. Conclusão
Worker → Kafka → API
06

Infraestrutura

Cloud-Native em Docker, VPS único. Todo tráfego externo passa pelo Nginx. Nenhum serviço interno é exposto diretamente para a WAN. Clique nos serviços.

Topologia Docker · lumina-net
clique em um serviço
External Network (WAN)
Nginx :80/:443
proxy_pass
Docker Network · lumina-net · Internal Only
Jaspr UI :80
Spring Boot :8080
Kafka KRaft :9092
PostgreSQL :5432
Rust Worker daemon
MinIO :9000
Mapeamento de Portas
ServiçoPortaProtocoloEscopo
Nginx80, 443HTTP/HTTPSPúblico (WAN)
Jaspr UI80HTTPInterno (lumina-net)
Spring Boot8080HTTPInterno (lumina-net)
Apache Kafka9092TCP (KRaft)Interno (lumina-net)
PostgreSQL5432TCP (JDBC)Interno (lumina-net)
MinIO9000HTTP (S3 API)Interno + proxy RO
Rust WorkerConsumer TCPInterno (daemon)
07

Modelagem de Dados

Três tabelas com relacionamentos em cascata e Soft Delete nas entidades críticas. Os campos destacados implementam as regras de negócio diretamente no schema.

USERS
PKidUuid
NOT NULLnameVarchar
NOT NULLemailVarchar
NOT NULLpasswordVarchar
NOT NULLcreated_atTimestamp
NOT NULLupdated_atTimestamp
SOFT DELdeleted_atTimestamp
PROJECTS
PKidUuid
FKuser_idUuid
NOT NULLtitleVarchar
TOKENpublic_tokenUuid
TRAVAallow_downloadBoolean
NOT NULLcreated_atTimestamp
NOT NULLupdated_atTimestamp
SOFT DELdeleted_atTimestamp
PHOTOS
PKidUuid
FKproject_idUuid
ORIGINoriginal_file_pathVarchar
PREVIEWpreview_file_pathVarchar
NOT NULLstatusVarchar
NOT NULLcreated_atTimestamp
NOT NULLupdated_atTimestamp
Relacionamentos
USERS
1 : N · has
❯❮
PROJECTS
PROJECTS
1 : N · contains
❯❮
PHOTOS
public_token
UUID em PROJECTS que é o segredo do Link Mágico. Gerado aleatoriamente e incluído na URL — sem expor o ID interno. O cliente nunca vê o ID real do projeto.
allow_download
Flag booleana em PROJECTS. Sempre false por padrão. Torna-se true apenas quando a fotógrafa clica em "Liberar Download" no painel.
deleted_at — Soft Delete
Campo nullable em USERS e PROJECTS. Um registro é considerado deletado quando este campo não é nulo — preservando histórico e permitindo auditoria completa.
dual path — Imutabilidade
Cada foto tem original_file_path (intocado) e preview_file_path (com marca d'água). Implementa a Imutabilidade da Origem no nível do schema.
Lumina.
Documentação Técnica Oficial