Skip to content

Commit df793e9

Browse files
committed
Merge branch 'main' into chore/award-static-analysis
chore: address lint issues
2 parents 213da8f + dcf4d56 commit df793e9

7 files changed

Lines changed: 142 additions & 29 deletions

File tree

.github/workflows/docker-compose-integration.yml

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,8 @@ jobs:
2323

2424
- name: Wait for services to be healthy
2525
run: |
26-
echo "Waiting for all services to be healthy..."
27-
# Wait for services with health checks to be healthy (7 services) and all services to be up
28-
# Increased timeout to 10 minutes for CI environment
29-
timeout 600 bash -c 'while true; do
30-
echo "=== Detailed Service Status ==="
31-
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Health}}"
32-
echo "=== Unhealthy Services ==="
33-
unhealthy_services=$(docker compose ps --format "{{.Name}} {{.Health}}" | grep -v healthy | grep -v "^[[:space:]]*$" || echo "")
34-
if [ -n "$unhealthy_services" ]; then
35-
echo "$unhealthy_services"
36-
echo "=== Logs for unhealthy services ==="
37-
for service in $(echo "$unhealthy_services" | awk "{print \$1}"); do
38-
echo "--- Logs for $service ---"
39-
docker compose logs --tail=10 "$service" || echo "No logs for $service"
40-
done
41-
else
42-
echo "All services healthy or no health check"
43-
fi
44-
healthy_count=$(docker compose ps --format "{{.Health}}" | grep -c "healthy" || echo "0")
45-
up_count=$(docker compose ps --format "{{.Status}}" | grep -c "Up" || echo "0")
46-
echo "Progress: $healthy_count/7 healthy, $up_count services up"
47-
if [ "$healthy_count" -ge 7 ] && [ "$up_count" -ge 7 ]; then
48-
echo "All services are healthy!"
49-
break
50-
fi
51-
sleep 10
52-
done'
26+
echo Pausing for 60s to allow services to start
27+
sleep 60
5328
docker compose ps
5429
5530
- name: Test dashboard endpoints
@@ -61,8 +36,7 @@ jobs:
6136
run: |
6237
# Test sticker award API with sample user data
6338
curl -f -X GET "http://localhost:8080/api/award/v1/users/user-001/stickers" || exit 1
64-
# TODO!
65-
# curl -f -X GET "http://localhost:8080/api/users/v1/health" || exit 1
39+
curl -f -X GET "http://localhost:8080/api/users/v1/health" || exit 1
6640
6741
- name: Show service logs on failure
6842
if: failure()

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ As a reference application, Stickerlandia showcases **platform adaptability** by
2727

2828
Comprehensive documentation is available in the [docs](./docs/README.md).
2929

30+
For deployment options and platform-specific configurations, see the [deployment guide](./docs/deploy.md).
31+
3032
## High-Level Architecture
3133

3234
Stickerlandia follows a microservice architecture that can run in various configurations across different types of modern infrastructure:

docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,28 @@ version: '3.8'
1212
# - Traefik Dashboard: http://localhost:8081/dashboard/
1313
# - Redpanda Console: http://localhost:8082
1414
#
15+
#
16+
# Signing Up
17+
# ---------
18+
# curl -X POST http://localhost:8080/api/users/v1/register \
19+
# -H "Content-Type: application/json" \
20+
# -d '{
21+
# "firstName": "John",
22+
# "lastName": "Doe",
23+
# "emailAddress": "john.doe@example.com",
24+
# "password": "ValidPass123!"
25+
# }'
26+
#
27+
#
28+
# Logging In
29+
# ----------
30+
# curl -X POST http://localhost:8080/api/users/v1/login \
31+
# -H "Content-Type: application/x-www-form-urlencoded" \
32+
# -d "grant_type=password&username=john.doe@example.com&password=ValidPass123!&client_id=user-authentication&client_secret=388D45FA-B36B-4988-BA59-B187D329C207"
33+
34+
#
35+
36+
1537
services:
1638
traefik:
1739
image: traefik:v3.0

docs/deploy.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Deployment Targets
2+
3+
This page describes the deployment targets Stickerlandia supports or aims to support. It aims to pull forward any and all details that may impact early-stages implementation.
4+
5+
## Platform Overview
6+
7+
Stickerlandia will support both serverless and container-based platforms, self-hosted, as well as in the cloud.
8+
9+
### Serverless
10+
11+
| Platform | Description | IaC | Messaging | Blob Storage | Database | Ingress | Ingress Features |
12+
|----------|-------------|-----|-----------|--------------|----------|---------|------------------|
13+
| AWS (Serverless) | Containers on Amazon ECS/Fargate & Lambda functions with managed services | CDK | Amazon SQS/SNS/EventBridge | Amazon S3 | Amazon RDS/DynamoDB | API Gateway | Rate limiting, CORS, JWT/OIDC validation, API keys |
14+
| Azure (Serverless) | Azure Container Apps & Azure Functions with managed services | Terraform | Azure Service Bus | Azure Blob Storage | Azure SQL | Azure API Management | Path routing, rate limiting, JWT/OIDC validation |
15+
16+
### Containerised
17+
18+
| Platform | Description | IaC | Messaging | Blob Storage | Database | Ingress | Ingress Features |
19+
|----------|-------------|-----|-----------|--------------|----------|---------|------------------|
20+
| AWS (EKS) | Kubernetes on Elastic Kubernetes Service | K8S Manifests, CDK | Apache Kafka on MSK | Amazon S3 | Amazon RDS | ALB + Ingress Controller | Path routing, SSL termination (No native OIDC) |
21+
| Docker-Compose | Local development environment | docker-compose.yml | Kafka | MinIO | PostgreSQL | Traefik | Path routing, SSL (No native OIDC) |
22+
| Kubernetes | Generic Kubernetes deployment | K8S Manifests | Kafka | MinIO | PostgreSQL | Ingress Controller | SSL termination, path routing (No native OIDC) |
23+
24+
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.datadoghq.stickerlandia.stickeraward.sticker;
2+
3+
import com.datadoghq.stickerlandia.stickeraward.sticker.entity.Sticker;
4+
import io.quarkus.runtime.StartupEvent;
5+
import jakarta.enterprise.context.ApplicationScoped;
6+
import jakarta.enterprise.event.Observes;
7+
import jakarta.inject.Inject;
8+
import jakarta.transaction.Transactional;
9+
import java.io.InputStream;
10+
import org.jboss.logging.Logger;
11+
12+
/**
13+
* Service responsible for seeding sticker images during application startup. This class loads
14+
* default sticker images from the classpath and uploads them to the configured storage service,
15+
* associating them with existing stickers.
16+
*/
17+
@ApplicationScoped
18+
public class StickerImageSeeder {
19+
20+
private static final Logger LOG = Logger.getLogger(StickerImageSeeder.class);
21+
22+
@Inject StickerImageService stickerImageService;
23+
24+
@Inject StickerRepository stickerRepository;
25+
26+
/**
27+
* Handles the startup event to seed sticker images. This method is called during application
28+
* startup and ensures that default sticker images are loaded and associated with existing
29+
* stickers.
30+
*
31+
* @param ev the startup event
32+
*/
33+
@Transactional
34+
public void onStartup(@Observes StartupEvent ev) {
35+
LOG.info("Starting sticker image seeding...");
36+
37+
try {
38+
seedStickerImage("sticker-001", "/stickers/dd_icon_rgb.png", "Datadog Purple Logo");
39+
seedStickerImage("sticker-002", "/stickers/dd_icon_white.png", "Datadog White Logo");
40+
41+
LOG.info("Sticker image seeding completed successfully");
42+
} catch (Exception e) {
43+
LOG.error("Failed to seed sticker images", e);
44+
}
45+
}
46+
47+
private void seedStickerImage(String stickerId, String resourcePath, String description) {
48+
// Check if sticker exists and doesn't already have an image
49+
Sticker sticker = Sticker.findById(stickerId);
50+
if (sticker == null) {
51+
LOG.warnf("Sticker %s not found, skipping image seeding", stickerId);
52+
return;
53+
}
54+
55+
if (sticker.getImageKey() != null && !sticker.getImageKey().isEmpty()) {
56+
LOG.infof(
57+
"Sticker %s already has image key %s, skipping",
58+
stickerId, sticker.getImageKey());
59+
return;
60+
}
61+
62+
try {
63+
// Load image from resources
64+
InputStream imageStream = getClass().getResourceAsStream(resourcePath);
65+
if (imageStream == null) {
66+
LOG.errorf("Could not find image resource: %s", resourcePath);
67+
return;
68+
}
69+
70+
// Get file size for upload
71+
byte[] imageData = imageStream.readAllBytes();
72+
imageStream.close();
73+
74+
// Upload image to our storage service
75+
InputStream uploadStream = getClass().getResourceAsStream(resourcePath);
76+
String imageKey =
77+
stickerImageService.uploadImage(uploadStream, "image/png", imageData.length);
78+
uploadStream.close();
79+
80+
// Update sticker with image key
81+
stickerRepository.updateStickerImageKey(stickerId, imageKey);
82+
83+
LOG.infof(
84+
"Successfully seeded image for sticker %s with key %s (%s)",
85+
stickerId, imageKey, description);
86+
87+
} catch (Exception e) {
88+
LOG.errorf(e, "Failed to seed image for sticker %s from %s", stickerId, resourcePath);
89+
}
90+
}
91+
}
73 KB
Loading
64.1 KB
Loading

0 commit comments

Comments
 (0)