Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ A estrutura de pastas do projeto é organizada da seguinte forma:
│ ├── api-gateway/
│ ├── bucket_s3/
│ ├── dynamodb/
│ │ ├── certificates/
│ │ ├── orders/
│ │ ├── participants/
│ │ └── products/
│ │ └── single_table/ # Single-table design
│ ├── lambda/
│ └── sqs/
└── README.md
Expand Down Expand Up @@ -65,19 +62,46 @@ A seguir estão os serviços da AWS criados por este projeto e suas respectivas
- `region`: Região da AWS.
- `lifecycle_rule`: Regras de ciclo de vida dos objetos S3.

### DynamoDB
### DynamoDB Single-Table

- **Descrição**: Cria as tabelas do DynamoDB para a aplicação.
- **Módulos**:
- `certificates`: Tabela de certificados.
- `orders`: Tabela de pedidos.
- `participants`: Tabela de participantes.
- `products`: Tabela de produtos.
- **Variáveis (por módulo)**:
- **Descrição**: Cria a tabela DynamoDB com padrão Single-Table Design.
- **Módulo**: `single_table`
- **Variáveis**:
- `table_name`: Nome da tabela.
- `environment`: Ambiente de deploy.
- `project_name`: Nome do projeto.

#### Estrutura da Tabela

A tabela utiliza um design Single-Table com chaves compostas e 4 Global Secondary Indexes (GSIs).

| Atributo | Tipo | Descrição |
|----------|------|-----------|
| `PK` | String | Chave de Partição principal |
| `SK` | String | Chave de Ordenação principal |
| `GSI1PK`, `GSI1SK` | String | GSI1 - Certificate por UUID |
| `GSI2PK`, `GSI2SK` | String | GSI2 - Orders, Certificates, Participants por email |
| `GSI3PK`, `GSI3SK` | String | GSI3 - Products por nome, Certificates/Orders por product |
| `GSI4PK`, `GSI4SK` | String | GSI4 - Certificados por status de sucesso |

#### GSIs (Global Secondary Indexes)

| GSI | Key Schema | Access Pattern |
|-----|------------|----------------|
| GSI1 | `PK: UUID, SK: CERT#` | Certificate by UUID |
| GSI2 | `PK: email, SK: ENTITY#` | Orders, Certificates, Participants by email |
| GSI3 | `PK: product, SK: ENTITY#` | Products by name, Certificates/Orders by product |
| GSI4 | `PK: SUCCESS#Y/N, SK: CERT#` | Successful/Failed certificates |

#### Entidades Suportadas

| Entidade | PK | SK | GSIs Utilizados |
|----------|----|----|----------------|
| Certificate | `CERTIFICATE#<uuid>` | `CERTIFICATE#<uuid>` | GSI1, GSI2, GSI3, GSI4 |
| Order | `ORDER#<order_id>` | `ORDER#<order_id>` | GSI2, GSI3 |
| Product | `PRODUCT#<product_id>` | `PRODUCT#<product_id>` | GSI3 |
| Participant | `PARTICIPANT#<uuid>` | `PARTICIPANT#<uuid>` | GSI2 |

### Lambda

- **Descrição**: Cria as funções Lambda no formato ZIP e a infraestrutura associada.
Expand Down
34 changes: 5 additions & 29 deletions terraform/env/dev/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,10 @@ module "s3" {
region = var.aws_region
}

# DynamoDB Tables
module "certificates_table" {
source = "../../modules/02.dynamodb/certificates"
table_name = "${var.project_name}-certificates-${var.environment}"
environment = var.environment
project_name = var.project_name
}

module "orders_table" {
source = "../../modules/02.dynamodb/orders"
table_name = "${var.project_name}-orders-${var.environment}"
environment = var.environment
project_name = var.project_name
}

module "participants_table" {
source = "../../modules/02.dynamodb/participants"
table_name = "${var.project_name}-participants-${var.environment}"
environment = var.environment
project_name = var.project_name
}

module "products_table" {
source = "../../modules/02.dynamodb/products"
table_name = "${var.project_name}-products-${var.environment}"
# DynamoDB Single Table
module "dynamodb_single_table" {
source = "../../modules/02.dynamodb/single_table"
table_name = "${var.project_name}-${var.environment}"
environment = var.environment
project_name = var.project_name
}
Expand Down Expand Up @@ -63,10 +42,7 @@ module "lambda" {
notification_queue_arn = module.sqs.notification_queue_arn
notification_queue_url = module.sqs.notification_queue_url
dynamodb_table_arns = [
module.certificates_table.table_arn,
module.orders_table.table_arn,
module.participants_table.table_arn,
module.products_table.table_arn
module.dynamodb_single_table.table_arn
]
s3_bucket_arn = module.s3.bucket_arn
s3_bucket_name = module.s3.bucket_name
Expand Down
47 changes: 7 additions & 40 deletions terraform/env/dev/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,15 @@ output "s3_bucket_arn" {
value = module.s3.bucket_arn
}

# Informações das tabelas de certificados
output "certificates_table_name" {
description = "Nome da tabela de certificados"
value = module.certificates_table.table_name
# Informações da tabela única DynamoDB (single-table design)
output "dynamodb_single_table_name" {
description = "Nome da tabela DynamoDB única"
value = module.dynamodb_single_table.table_name
}

output "certificates_table_arn" {
description = "ARN da tabela de certificados"
value = module.certificates_table.table_arn
}

# Informações das tabelas de pedidos
output "orders_table_name" {
description = "Nome da tabela de pedidos"
value = module.orders_table.table_name
}

output "orders_table_arn" {
description = "ARN da tabela de pedidos"
value = module.orders_table.table_arn
}

# Informações das tabelas de participantes
output "participants_table_name" {
description = "Nome da tabela de participantes"
value = module.participants_table.table_name
}

output "participants_table_arn" {
description = "ARN da tabela de participantes"
value = module.participants_table.table_arn
}

# Informações das tabelas de produtos
output "products_table_name" {
description = "Nome da tabela de produtos"
value = module.products_table.table_name
}

output "products_table_arn" {
description = "ARN da tabela de produtos"
value = module.products_table.table_arn
output "dynamodb_single_table_arn" {
description = "ARN da tabela DynamoDB única"
value = module.dynamodb_single_table.table_arn
}

# Informações do SQS
Expand Down
120 changes: 120 additions & 0 deletions terraform/modules/02.dynamodb/single_table/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Single Table Design - DynamoDB
# Baseado no padrão: https://aws.amazon.com/pt/blogs/compute/creating-a-single-table-design-with-amazon-dynamodb/
#
# Entity Patterns:
# PK: EntityType#EntityId (ex: ORDER#123, PRODUCT#1, PARTICIPANT#uuid, CERTIFICATE#123)
# SK: EntityType#EntityId (mesmo formato para acesso direto)
#
# GSIs para padrões de acesso:
# GSI1: Acesso por UUID (certificate by ID)
# GSI2: Acesso por email (orders, certificates, participants)
# GSI3: Acesso por product (products, orders, certificates)
# GSI4: Acesso por success flag (certificates)

resource "aws_dynamodb_table" "single_table" {
name = var.table_name
billing_mode = "PAY_PER_REQUEST"
hash_key = "PK"
range_key = "SK"

attribute {
name = "PK"
type = "S"
}

attribute {
name = "SK"
type = "S"
}

# Atributos base - entidades
attribute {
name = "GSI1PK"
type = "S"
}

attribute {
name = "GSI1SK"
type = "S"
}

attribute {
name = "GSI2PK"
type = "S"
}

attribute {
name = "GSI2SK"
type = "S"
}

attribute {
name = "GSI3PK"
type = "S"
}

attribute {
name = "GSI3SK"
type = "S"
}

attribute {
name = "GSI4PK"
type = "S"
}

attribute {
name = "GSI4SK"
type = "S"
}

# EntityType para identificação rápida do tipo
attribute {
name = "EntityType"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O EntityType tá declarado como attribute mas não é chave de nada — nem hash_key/range_key da tabela, nem de nenhum dos cinco GSIs. Isso quebra o apply no plan, antes de chamar a AWS:

Error: all attributes must be indexed. Unused attributes: ["EntityType"]
  on ../modules/02.dynamodb/single_table/main.tf line 14

Testei o módulo contra o MiniStack variando só esse bloco: com ele dá o erro acima, sem ele a tabela sobe ACTIVE com os 5 GSIs certinhos.

Pode remover — o DynamoDB é schemaless, então a aplicação continua gravando EntityType e usando no filter_expression sem precisar declarar como atributo.

type = "S"
}

# GSI1: CERT# lookups (certificate find_by_id)
global_secondary_index {
name = "GSI1"
hash_key = "GSI1PK"
range_key = "GSI1SK"
projection_type = "ALL"
}

# GSI2: EMAIL# lookups (email lookups across entities)
global_secondary_index {
name = "GSI2"
hash_key = "GSI2PK"
range_key = "GSI2SK"
projection_type = "ALL"
}

# GSI3: PRODUCT# lookups (product lookups)
global_secondary_index {
name = "GSI3"
hash_key = "GSI3PK"
range_key = "GSI3SK"
projection_type = "ALL"
}

# GSI4: SUCCESS# lookups (certificate success flag)
global_secondary_index {
name = "GSI4"
hash_key = "GSI4PK"
range_key = "GSI4SK"
projection_type = "ALL"
}

server_side_encryption {
enabled = true
}

tags = {
Name = var.table_name
Environment = var.environment
Project = var.project_name
Design = "SingleTable"
CostCenter = "low-cost"
}
}
14 changes: 14 additions & 0 deletions terraform/modules/02.dynamodb/single_table/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "table_name" {
value = aws_dynamodb_table.single_table.name
description = "Nome da tabela única"
}

output "table_arn" {
value = aws_dynamodb_table.single_table.arn
description = "ARN da tabela única"
}

output "table_id" {
value = aws_dynamodb_table.single_table.id
description = "ID da tabela única"
}
14 changes: 14 additions & 0 deletions terraform/modules/02.dynamodb/single_table/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
variable "table_name" {
description = "Nome da tabela única"
type = string
}

variable "environment" {
description = "Ambiente de deploy"
type = string
}

variable "project_name" {
description = "Nome do projeto"
type = string
}