From 9a815014481518b7b424e65f0a5149e5687d302f Mon Sep 17 00:00:00 2001 From: Cole Michaels Date: Thu, 23 Apr 2026 15:26:10 +0900 Subject: [PATCH 1/6] Added x-ray to each service, enabled x-ray in terraform, added logging to presence, faced websocket bug and wanted more visibility. --- .idea/workspace.xml | 27 +- ApiServer/main.py | 15 +- ApiServer/requirements.txt | 1 + ChatInfra/main.tf | 5 + ChatInfra/modules/ecs/main.tf | 123 +++++++++ ChatInfra/modules/ecs/outputs.tf | 20 ++ ChatInfra/modules/ecs_services/main.tf | 239 ++++++++++++------ ChatInfra/modules/ecs_services/variables.tf | 20 ++ ChatServer/build.gradle.kts | 5 + ChatServer/src/main/kotlin/Main.kt | 2 + .../main/kotlin/data/registry/UserRegistry.kt | 24 +- ChatServer/src/main/kotlin/di/AppModule.kt | 4 + ChatServer/src/main/kotlin/plugins/Sockets.kt | 11 +- ChatServer/src/main/kotlin/plugins/XRay.kt | 22 ++ PresenceServer/app/repos/presence.py | 5 + PresenceServer/app/routers/presence.py | 7 + PresenceServer/main.py | 21 +- PresenceServer/requirements.txt | 1 + 18 files changed, 447 insertions(+), 105 deletions(-) create mode 100644 ChatServer/src/main/kotlin/plugins/XRay.kt diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 1aa3f63..6b0bccc 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -3,6 +3,9 @@ + + + - { - "keyToString": { - "Gradle./home/cole/Projects/ChatSystem/ChatServer [ktlintFormat].executor": "Run", - "Gradle./home/cole/Projects/ChatSystem/ChatServer [test clean].executor": "Run", - "ModuleVcsDetector.initialDetectionPerformed": "true", - "RunOnceActivity.ShowReadmeOnStart": "true", - "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", - "RunOnceActivity.git.unshallow": "true", - "git-widget-placeholder": "feature/cleanup-codebase-for-stability", - "kotlin-language-version-configured": "true", - "last_opened_file_path": "/home/cole/Projects/ChatSystem" + +}]]> diff --git a/ApiServer/main.py b/ApiServer/main.py index e7d5287..29b41ef 100644 --- a/ApiServer/main.py +++ b/ApiServer/main.py @@ -3,7 +3,8 @@ import sys from contextlib import asynccontextmanager -from fastapi import FastAPI +from aws_xray_sdk.core import xray_recorder, patch +from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import text @@ -20,6 +21,8 @@ ) logger = logging.getLogger(__name__) +patch(["sqlalchemy"]) + MAX_RETRIES = 10 RETRY_DELAY = 2 @@ -48,6 +51,16 @@ async def lifespan(app: FastAPI): app = FastAPI(title="ChatSystem API", lifespan=lifespan) + +@app.middleware("http") +async def xray_middleware(request: Request, call_next): + xray_recorder.begin_segment(f"{request.method} {request.url.path}") + try: + return await call_next(request) + finally: + xray_recorder.end_segment() + + app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins_list, diff --git a/ApiServer/requirements.txt b/ApiServer/requirements.txt index 0be7091..815794a 100644 --- a/ApiServer/requirements.txt +++ b/ApiServer/requirements.txt @@ -1,4 +1,5 @@ annotated-doc==0.0.4 +aws-xray-sdk annotated-types==0.7.0 anyio==4.13.0 asyncpg==0.31.0 diff --git a/ChatInfra/main.tf b/ChatInfra/main.tf index 97721ed..f3f4b71 100644 --- a/ChatInfra/main.tf +++ b/ChatInfra/main.tf @@ -78,6 +78,8 @@ module "ecs_services" { execution_role_chatserver_arn = module.ecs.execution_role_chatserver_arn execution_role_presenceserver_arn = module.ecs.execution_role_presenceserver_arn chatserver_task_role_arn = module.ecs.chatserver_task_role_arn + apiserver_task_role_arn = module.ecs.apiserver_task_role_arn + presenceserver_task_role_arn = module.ecs.presenceserver_task_role_arn private_subnet_ids = module.vpc.private_subnets ecs_tasks_sg_id = module.security_groups.ecs_tasks_sg_id chatserver_nlb_dns_name = module.alb.chatserver_nlb_dns_name @@ -92,5 +94,8 @@ module "ecs_services" { apiserver_log_group = module.ecs.apiserver_log_group chatserver_log_group = module.ecs.chatserver_log_group presenceserver_log_group = module.ecs.presenceserver_log_group + apiserver_xray_log_group = module.ecs.apiserver_xray_log_group + chatserver_xray_log_group = module.ecs.chatserver_xray_log_group + presenceserver_xray_log_group = module.ecs.presenceserver_xray_log_group cloudfront_domain = module.static_site.cloudfront_domain } diff --git a/ChatInfra/modules/ecs/main.tf b/ChatInfra/modules/ecs/main.tf index e69ad7a..b6c4500 100644 --- a/ChatInfra/modules/ecs/main.tf +++ b/ChatInfra/modules/ecs/main.tf @@ -219,3 +219,126 @@ resource "aws_iam_role_policy" "chatserver_sqs" { }] }) } + +resource "aws_iam_role_policy" "chatserver_xray" { + name = "${var.project_name}-chatserver-xray" + role = aws_iam_role.chatserver_task.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Action = [ + "xray:PutTraceSegments", + "xray:PutTelemetryRecords", + "xray:GetSamplingRules", + "xray:GetSamplingTargets", + "xray:GetSamplingStatisticSummaries", + ] + Resource = "*" + }] + }) +} + +# --- ApiServer task role --- + +resource "aws_iam_role" "apiserver_task" { + name = "${var.project_name}-apiserver-task" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { Service = "ecs-tasks.amazonaws.com" } + Action = "sts:AssumeRole" + Condition = { + ArnLike = { + "aws:SourceArn" = "arn:aws:ecs:${var.region}:${data.aws_caller_identity.current.account_id}:*" + } + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + } + }] + }) +} + +resource "aws_iam_role_policy" "apiserver_xray" { + name = "${var.project_name}-apiserver-xray" + role = aws_iam_role.apiserver_task.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Action = [ + "xray:PutTraceSegments", + "xray:PutTelemetryRecords", + "xray:GetSamplingRules", + "xray:GetSamplingTargets", + "xray:GetSamplingStatisticSummaries", + ] + Resource = "*" + }] + }) +} + +# --- PresenceServer task role --- + +resource "aws_iam_role" "presenceserver_task" { + name = "${var.project_name}-presenceserver-task" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { Service = "ecs-tasks.amazonaws.com" } + Action = "sts:AssumeRole" + Condition = { + ArnLike = { + "aws:SourceArn" = "arn:aws:ecs:${var.region}:${data.aws_caller_identity.current.account_id}:*" + } + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + } + }] + }) +} + +resource "aws_iam_role_policy" "presenceserver_xray" { + name = "${var.project_name}-presenceserver-xray" + role = aws_iam_role.presenceserver_task.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Action = [ + "xray:PutTraceSegments", + "xray:PutTelemetryRecords", + "xray:GetSamplingRules", + "xray:GetSamplingTargets", + "xray:GetSamplingStatisticSummaries", + ] + Resource = "*" + }] + }) +} + +# --- X-Ray daemon log groups --- + +resource "aws_cloudwatch_log_group" "apiserver_xray" { + name = "/ecs/${var.project_name}/apiserver-xray" + retention_in_days = 365 +} + +resource "aws_cloudwatch_log_group" "chatserver_xray" { + name = "/ecs/${var.project_name}/chatserver-xray" + retention_in_days = 365 +} + +resource "aws_cloudwatch_log_group" "presenceserver_xray" { + name = "/ecs/${var.project_name}/presenceserver-xray" + retention_in_days = 365 +} diff --git a/ChatInfra/modules/ecs/outputs.tf b/ChatInfra/modules/ecs/outputs.tf index 237b0c2..2c01bb5 100644 --- a/ChatInfra/modules/ecs/outputs.tf +++ b/ChatInfra/modules/ecs/outputs.tf @@ -18,6 +18,14 @@ output "chatserver_task_role_arn" { value = aws_iam_role.chatserver_task.arn } +output "apiserver_task_role_arn" { + value = aws_iam_role.apiserver_task.arn +} + +output "presenceserver_task_role_arn" { + value = aws_iam_role.presenceserver_task.arn +} + output "apiserver_log_group" { value = aws_cloudwatch_log_group.apiserver.name } @@ -29,3 +37,15 @@ output "chatserver_log_group" { output "presenceserver_log_group" { value = aws_cloudwatch_log_group.presenceserver.name } + +output "apiserver_xray_log_group" { + value = aws_cloudwatch_log_group.apiserver_xray.name +} + +output "chatserver_xray_log_group" { + value = aws_cloudwatch_log_group.chatserver_xray.name +} + +output "presenceserver_xray_log_group" { + value = aws_cloudwatch_log_group.presenceserver_xray.name +} diff --git a/ChatInfra/modules/ecs_services/main.tf b/ChatInfra/modules/ecs_services/main.tf index 7c45ec2..2770f87 100644 --- a/ChatInfra/modules/ecs_services/main.tf +++ b/ChatInfra/modules/ecs_services/main.tf @@ -9,37 +9,63 @@ resource "aws_ecs_task_definition" "apiserver" { cpu = 256 memory = 512 execution_role_arn = var.execution_role_api_arn + task_role_arn = var.apiserver_task_role_arn - container_definitions = jsonencode([{ - name = "apiserver" - image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/chatsystem/apiserver:latest" - essential = true - - portMappings = [{ - containerPort = 8000 - protocol = "tcp" - }] - - environment = [ - { name = "CHAT_SERVER_URL", value = "http://${var.chatserver_nlb_dns_name}" }, - { name = "CORS_ORIGINS", value = "https://${var.cloudfront_domain}" }, - ] - - secrets = [ - { name = "DATABASE_URL", valueFrom = "${var.db_secret_arn}:database_url::" }, - { name = "SECRET_KEY", valueFrom = var.jwt_secret_arn }, - { name = "INTERNAL_API_KEY", valueFrom = var.internal_api_key_arn }, - ] - - logConfiguration = { - logDriver = "awslogs" - options = { - awslogs-group = var.apiserver_log_group - awslogs-region = var.region - awslogs-stream-prefix = "apiserver" + container_definitions = jsonencode([ + { + name = "apiserver" + image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/chatsystem/apiserver:latest" + essential = true + + portMappings = [{ + containerPort = 8000 + protocol = "tcp" + }] + + environment = [ + { name = "CHAT_SERVER_URL", value = "http://${var.chatserver_nlb_dns_name}" }, + { name = "CORS_ORIGINS", value = "https://${var.cloudfront_domain}" }, + ] + + secrets = [ + { name = "DATABASE_URL", valueFrom = "${var.db_secret_arn}:database_url::" }, + { name = "SECRET_KEY", valueFrom = var.jwt_secret_arn }, + { name = "INTERNAL_API_KEY", valueFrom = var.internal_api_key_arn }, + ] + + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-group = var.apiserver_log_group + awslogs-region = var.region + awslogs-stream-prefix = "apiserver" + } + } + }, + { + name = "xray-daemon" + image = "public.ecr.aws/xray/aws-xray-daemon:latest" + essential = false + + portMappings = [{ + containerPort = 2000 + protocol = "udp" + }] + + environment = [ + { name = "AWS_REGION", value = var.region }, + ] + + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-group = var.apiserver_xray_log_group + awslogs-region = var.region + awslogs-stream-prefix = "xray" + } } } - }]) + ]) } resource "aws_ecs_service" "apiserver" { @@ -71,35 +97,61 @@ resource "aws_ecs_task_definition" "presenceserver" { cpu = 256 memory = 512 execution_role_arn = var.execution_role_presenceserver_arn + task_role_arn = var.presenceserver_task_role_arn + + container_definitions = jsonencode([ + { + name = "presenceserver" + image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/chatsystem/presenceserver:latest" + essential = true + + portMappings = [{ + containerPort = 8000 + protocol = "tcp" + }] + + environment = [ + { name = "REDIS_URL", value = "rediss://${var.redis_address}:6379" } + ] + + secrets = [ + { name = "SECRET_KEY", valueFrom = var.jwt_secret_arn }, + { name = "INTERNAL_API_KEY", valueFrom = var.internal_api_key_arn }, + ] - container_definitions = jsonencode([{ - name = "presenceserver" - image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/chatsystem/presenceserver:latest" - essential = true - - portMappings = [{ - containerPort = 8000 - protocol = "tcp" - }] - - environment = [ - { name = "REDIS_URL", value = "rediss://${var.redis_address}:6379" } - ] - - secrets = [ - { name = "SECRET_KEY", valueFrom = var.jwt_secret_arn }, - { name = "INTERNAL_API_KEY", valueFrom = var.internal_api_key_arn }, - ] - - logConfiguration = { - logDriver = "awslogs" - options = { - awslogs-group = var.presenceserver_log_group - awslogs-region = var.region - awslogs-stream-prefix = "presenceserver" + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-group = var.presenceserver_log_group + awslogs-region = var.region + awslogs-stream-prefix = "presenceserver" + } + } + }, + { + name = "xray-daemon" + image = "public.ecr.aws/xray/aws-xray-daemon:latest" + essential = false + + portMappings = [{ + containerPort = 2000 + protocol = "udp" + }] + + environment = [ + { name = "AWS_REGION", value = var.region }, + ] + + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-group = var.presenceserver_xray_log_group + awslogs-region = var.region + awslogs-stream-prefix = "xray" + } } } - }]) + ]) } resource "aws_ecs_service" "presenceserver" { @@ -133,35 +185,60 @@ resource "aws_ecs_task_definition" "chatserver" { execution_role_arn = var.execution_role_chatserver_arn task_role_arn = var.chatserver_task_role_arn - container_definitions = jsonencode([{ - name = "chatserver" - image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/chatsystem/chatserver:latest" - essential = true - - portMappings = [{ - containerPort = 8080 - protocol = "tcp" - }] - - environment = [ - { name = "PRESENCE_SERVER_URL", value = "http://${var.internal_alb_dns_name}" }, - { name = "CORS_ORIGINS", value = "https://${var.cloudfront_domain}" }, - ] - - secrets = [ - { name = "JWT_SECRET", valueFrom = var.jwt_secret_arn }, - { name = "INTERNAL_API_KEY", valueFrom = var.internal_api_key_arn }, - ] - - logConfiguration = { - logDriver = "awslogs" - options = { - awslogs-group = var.chatserver_log_group - awslogs-region = var.region - awslogs-stream-prefix = "chatserver" + container_definitions = jsonencode([ + { + name = "chatserver" + image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/chatsystem/chatserver:latest" + essential = true + + portMappings = [{ + containerPort = 8080 + protocol = "tcp" + }] + + environment = [ + { name = "PRESENCE_SERVER_URL", value = "http://${var.internal_alb_dns_name}" }, + { name = "CORS_ORIGINS", value = "https://${var.cloudfront_domain}" }, + ] + + secrets = [ + { name = "JWT_SECRET", valueFrom = var.jwt_secret_arn }, + { name = "INTERNAL_API_KEY", valueFrom = var.internal_api_key_arn }, + ] + + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-group = var.chatserver_log_group + awslogs-region = var.region + awslogs-stream-prefix = "chatserver" + } + } + }, + { + name = "xray-daemon" + image = "public.ecr.aws/xray/aws-xray-daemon:latest" + essential = false + + portMappings = [{ + containerPort = 2000 + protocol = "udp" + }] + + environment = [ + { name = "AWS_REGION", value = var.region }, + ] + + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-group = var.chatserver_xray_log_group + awslogs-region = var.region + awslogs-stream-prefix = "xray" + } } } - }]) + ]) } resource "aws_ecs_service" "chatserver" { diff --git a/ChatInfra/modules/ecs_services/variables.tf b/ChatInfra/modules/ecs_services/variables.tf index b9995c5..e8648d1 100644 --- a/ChatInfra/modules/ecs_services/variables.tf +++ b/ChatInfra/modules/ecs_services/variables.tf @@ -26,6 +26,14 @@ variable "chatserver_task_role_arn" { type = string } +variable "apiserver_task_role_arn" { + type = string +} + +variable "presenceserver_task_role_arn" { + type = string +} + variable "private_subnet_ids" { type = list(string) } @@ -86,3 +94,15 @@ variable "cloudfront_domain" { type = string description = "CloudFront domain used as CORS allowed origin for ApiServer and ChatServer" } + +variable "apiserver_xray_log_group" { + type = string +} + +variable "chatserver_xray_log_group" { + type = string +} + +variable "presenceserver_xray_log_group" { + type = string +} diff --git a/ChatServer/build.gradle.kts b/ChatServer/build.gradle.kts index fcc545c..d92929a 100644 --- a/ChatServer/build.gradle.kts +++ b/ChatServer/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { val koinVersion = "3.5.6" val awsSdkVersion = "2.28.0" + val xrayVersion = "2.15.3" val mockkVersion = "1.13.10" testImplementation(kotlin("test")) @@ -51,6 +52,10 @@ dependencies { implementation("io.ktor:ktor-client-cio:$ktorVersion") implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + // X-Ray + implementation("com.amazonaws:aws-xray-recorder-sdk-core:$xrayVersion") + implementation("com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2:$xrayVersion") + // Logging implementation("ch.qos.logback:logback-classic:1.4.14") diff --git a/ChatServer/src/main/kotlin/Main.kt b/ChatServer/src/main/kotlin/Main.kt index 4a05032..f365037 100644 --- a/ChatServer/src/main/kotlin/Main.kt +++ b/ChatServer/src/main/kotlin/Main.kt @@ -11,10 +11,12 @@ import org.chatserver.plugins.configureRouting import org.chatserver.plugins.configureSerialization import org.chatserver.plugins.configureSockets import org.chatserver.plugins.configureSqs +import org.chatserver.plugins.configureXRay fun main() { embeddedServer(CIO, port = 8080) { configureDI() + configureXRay() configureCors() configureSerialization() configureSqs() diff --git a/ChatServer/src/main/kotlin/data/registry/UserRegistry.kt b/ChatServer/src/main/kotlin/data/registry/UserRegistry.kt index 71e7d2f..6f76fd7 100644 --- a/ChatServer/src/main/kotlin/data/registry/UserRegistry.kt +++ b/ChatServer/src/main/kotlin/data/registry/UserRegistry.kt @@ -73,13 +73,21 @@ class UserRegistry( return connected } - fun deregister(userId: String) { - dynamoClient.deleteItem( - DeleteItemRequest.builder() - .tableName(tableName) - .key(mapOf("userId" to AttributeValue.fromS(userId))) - .build(), - ) - logger.info("User $userId deregistered from server $serverId") + fun deregister(userId: String): Boolean { + return try { + dynamoClient.deleteItem( + DeleteItemRequest.builder() + .tableName(tableName) + .key(mapOf("userId" to AttributeValue.fromS(userId))) + .conditionExpression("serverId = :sid") + .expressionAttributeValues(mapOf(":sid" to AttributeValue.fromS(serverId))) + .build(), + ) + logger.info("User $userId deregistered from server $serverId") + true + } catch (e: software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException) { + logger.info("User $userId already claimed by another server, skipping deregister") + false + } } } diff --git a/ChatServer/src/main/kotlin/di/AppModule.kt b/ChatServer/src/main/kotlin/di/AppModule.kt index 427293d..e10fb29 100644 --- a/ChatServer/src/main/kotlin/di/AppModule.kt +++ b/ChatServer/src/main/kotlin/di/AppModule.kt @@ -12,7 +12,9 @@ import org.chatserver.services.sqs.SqsQueueManager import org.chatserver.session.SessionStore import org.koin.core.qualifier.named import org.koin.dsl.module +import com.amazonaws.xray.interceptors.TracingInterceptor import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration import software.amazon.awssdk.regions.Region import software.amazon.awssdk.services.dynamodb.DynamoDbClient import software.amazon.awssdk.services.sqs.SqsClient @@ -29,6 +31,7 @@ val appModule = DynamoDbClient.builder() .region(Region.US_WEST_1) .credentialsProvider(DefaultCredentialsProvider.create()) + .overrideConfiguration(ClientOverrideConfiguration.builder().addExecutionInterceptor(TracingInterceptor()).build()) .apply { if (endpoint != null) endpointOverride(URI.create(endpoint)) } .build() } @@ -38,6 +41,7 @@ val appModule = SqsClient.builder() .region(Region.US_WEST_1) .credentialsProvider(DefaultCredentialsProvider.create()) + .overrideConfiguration(ClientOverrideConfiguration.builder().addExecutionInterceptor(TracingInterceptor()).build()) .apply { if (endpoint != null) endpointOverride(URI.create(endpoint)) } .build() } diff --git a/ChatServer/src/main/kotlin/plugins/Sockets.kt b/ChatServer/src/main/kotlin/plugins/Sockets.kt index b46efad..74909e9 100644 --- a/ChatServer/src/main/kotlin/plugins/Sockets.kt +++ b/ChatServer/src/main/kotlin/plugins/Sockets.kt @@ -1,5 +1,6 @@ package org.chatserver.plugins +import com.amazonaws.xray.AWSXRay import io.ktor.server.application.Application import io.ktor.server.application.install import io.ktor.server.auth.authenticate @@ -49,8 +50,10 @@ fun Application.configureSockets() { } logger.info("User $userId connected") + AWSXRay.beginSegment("ws-connect $userId") userRegistry.register(userId) sessionStore.add(userId, this) + AWSXRay.endSegment() try { val groupmates = conversationRegistry.getGroupmates(userId) @@ -80,9 +83,13 @@ fun Application.configureSockets() { } } } finally { + AWSXRay.beginSegment("ws-disconnect $userId") sessionStore.remove(userId) - userRegistry.deregister(userId) - broadcastPresence(userId, online = false, serverRegistry, sqsClient) + val deregistered = userRegistry.deregister(userId) + if (deregistered) { + broadcastPresence(userId, online = false, serverRegistry, sqsClient) + } + AWSXRay.endSegment() logger.info("User $userId disconnected") } } diff --git a/ChatServer/src/main/kotlin/plugins/XRay.kt b/ChatServer/src/main/kotlin/plugins/XRay.kt new file mode 100644 index 0000000..fcb45dd --- /dev/null +++ b/ChatServer/src/main/kotlin/plugins/XRay.kt @@ -0,0 +1,22 @@ +package org.chatserver.plugins + +import com.amazonaws.xray.AWSXRay +import io.ktor.server.application.Application +import io.ktor.server.application.createApplicationPlugin +import io.ktor.server.application.install +import io.ktor.server.request.httpMethod +import io.ktor.server.request.path + +val XRayPlugin = createApplicationPlugin("XRay") { + onCall { call -> + val segmentName = "${call.request.httpMethod.value} ${call.request.path()}" + AWSXRay.beginSegment(segmentName) + } + onCallRespond { _ -> + AWSXRay.endSegment() + } +} + +fun Application.configureXRay() { + install(XRayPlugin) +} diff --git a/PresenceServer/app/repos/presence.py b/PresenceServer/app/repos/presence.py index 1bc0742..c933879 100644 --- a/PresenceServer/app/repos/presence.py +++ b/PresenceServer/app/repos/presence.py @@ -1,9 +1,14 @@ +import logging + from redis.asyncio import Redis from app.config import settings +logger = logging.getLogger(__name__) + async def set_online(user_id: str, redis: Redis) -> None: + logger.info("set_online user_id=%s ttl=%ds", user_id, settings.heartbeat_ttl_seconds) await redis.set(f"presence:{user_id}", "1", ex=settings.heartbeat_ttl_seconds) diff --git a/PresenceServer/app/routers/presence.py b/PresenceServer/app/routers/presence.py index 1dc7a15..26cf514 100644 --- a/PresenceServer/app/routers/presence.py +++ b/PresenceServer/app/routers/presence.py @@ -1,3 +1,5 @@ +import logging + from fastapi import APIRouter, Depends from redis.asyncio import Redis @@ -6,6 +8,8 @@ from app.repos.presence import set_online, is_online, are_online from app.schemas.presence import HeartbeatRequest, PresenceResponse, BatchPresenceRequest, BatchPresenceResponse +logger = logging.getLogger(__name__) + router = APIRouter(prefix="/presence", tags=["presence"]) @@ -15,6 +19,7 @@ async def heartbeat( redis: Redis = Depends(get_redis), _: None = Depends(verify_internal_key), ): + logger.info("heartbeat user_ids=%s", payload.user_ids) for user_id in payload.user_ids: await set_online(user_id, redis) @@ -26,6 +31,7 @@ async def get_presence_batch( _: None = Depends(verify_internal_key), ): presence = await are_online(payload.user_ids, redis) + logger.info("batch presence check user_ids=%s result=%s", payload.user_ids, presence) return BatchPresenceResponse(presence=presence) @@ -36,4 +42,5 @@ async def get_presence( _: str = Depends(get_current_user_id), ): online = await is_online(user_id, redis) + logger.info("presence check user_id=%s online=%s", user_id, online) return PresenceResponse(user_id=user_id, online=online) diff --git a/PresenceServer/main.py b/PresenceServer/main.py index d55021d..36fc1ad 100644 --- a/PresenceServer/main.py +++ b/PresenceServer/main.py @@ -1,11 +1,30 @@ -from fastapi import FastAPI +import logging + +from aws_xray_sdk.core import xray_recorder, patch +from fastapi import FastAPI, Request from app.routers import presence +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)s %(name)s: %(message)s", +) + +patch(["redis"]) + app = FastAPI() app.include_router(presence.router) +@app.middleware("http") +async def xray_middleware(request: Request, call_next): + xray_recorder.begin_segment(f"{request.method} {request.url.path}") + try: + return await call_next(request) + finally: + xray_recorder.end_segment() + + @app.get("/health") async def health(): return {"status": "ok"} diff --git a/PresenceServer/requirements.txt b/PresenceServer/requirements.txt index 023c142..19387dc 100644 --- a/PresenceServer/requirements.txt +++ b/PresenceServer/requirements.txt @@ -3,3 +3,4 @@ uvicorn[standard] pydantic-settings redis[asyncio] python-jose[cryptography] +aws-xray-sdk From 452130a7d830f75e7a9c9424e2ffeed5e1aaa2d1 Mon Sep 17 00:00:00 2001 From: Cole Michaels Date: Thu, 23 Apr 2026 15:27:19 +0900 Subject: [PATCH 2/6] only run CI against PRs. --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4941698..c2840dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,6 @@ name: CI on: - push: pull_request: jobs: From 76bdd04ee5534a030fe482a9247cb493e1bfab3e Mon Sep 17 00:00:00 2001 From: Cole Michaels Date: Fri, 24 Apr 2026 22:32:46 +0900 Subject: [PATCH 3/6] cleaned up git, updated diagram for xray, fixed infra scripts. --- .gitignore | 3 + .idea/ChatSystem.iml | 11 -- .idea/modules.xml | 8 -- .idea/vcs.xml | 6 - .idea/workspace.xml | 108 ------------------ ApiServer/.idea/.gitignore | 3 - ApiServer/.idea/ApiServer.iml | 10 -- .../inspectionProfiles/profiles_settings.xml | 6 - ApiServer/.idea/misc.xml | 7 -- ApiServer/.idea/modules.xml | 8 -- ApiServer/.idea/vcs.xml | 6 - ApiServer/__pycache__/main.cpython-314.pyc | Bin 3948 -> 0 bytes .../app/__pycache__/__init__.cpython-314.pyc | Bin 155 -> 0 bytes .../__pycache__/chat_client.cpython-314.pyc | Bin 4350 -> 0 bytes .../app/__pycache__/config.cpython-314.pyc | Bin 1736 -> 0 bytes .../app/__pycache__/database.cpython-314.pyc | Bin 753 -> 0 bytes .../__pycache__/dependencies.cpython-314.pyc | Bin 2453 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 162 -> 0 bytes .../models/__pycache__/group.cpython-314.pyc | Bin 2501 -> 0 bytes .../models/__pycache__/user.cpython-314.pyc | Bin 1722 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 163 -> 0 bytes .../routers/__pycache__/auth.cpython-314.pyc | Bin 5397 -> 0 bytes .../__pycache__/conversations.cpython-314.pyc | Bin 1016 -> 0 bytes .../__pycache__/groups.cpython-314.pyc | Bin 10902 -> 0 bytes .../__pycache__/presence.cpython-314.pyc | Bin 1880 -> 0 bytes .../routers/__pycache__/users.cpython-314.pyc | Bin 2864 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 163 -> 0 bytes .../schemas/__pycache__/group.cpython-314.pyc | Bin 1749 -> 0 bytes .../__pycache__/presence.cpython-314.pyc | Bin 747 -> 0 bytes .../schemas/__pycache__/token.cpython-314.pyc | Bin 726 -> 0 bytes .../schemas/__pycache__/user.cpython-314.pyc | Bin 1333 -> 0 bytes ApiServer/main.py | 4 +- .../__pycache__/__init__.cpython-314.pyc | Bin 157 -> 0 bytes .../conftest.cpython-314-pytest-9.0.2.pyc | Bin 3514 -> 0 bytes .../test_auth.cpython-314-pytest-9.0.2.pyc | Bin 6952 -> 0 bytes ...conversations.cpython-314-pytest-9.0.2.pyc | Bin 4854 -> 0 bytes .../test_groups.cpython-314-pytest-9.0.2.pyc | Bin 25070 -> 0 bytes ...resence_proxy.cpython-314-pytest-9.0.2.pyc | Bin 4632 -> 0 bytes .../test_users.cpython-314-pytest-9.0.2.pyc | Bin 9735 -> 0 bytes .../dev}/.terraform.lock.hcl | 0 .../deploy-client-dev.sh} | 12 +- ChatServer/.idea/.gitignore | 3 - .../.idea/codeStyles/codeStyleConfig.xml | 5 - ChatServer/.idea/gradle.xml | 17 --- ChatServer/.idea/kotlinc.xml | 7 -- ChatServer/.idea/misc.xml | 7 -- ChatServer/.idea/vcs.xml | 6 - PresenceServer/.idea/.gitignore | 3 - PresenceServer/.idea/PresenceServer.iml | 10 -- .../inspectionProfiles/profiles_settings.xml | 6 - PresenceServer/.idea/misc.xml | 7 -- PresenceServer/.idea/modules.xml | 8 -- PresenceServer/.idea/vcs.xml | 6 - .../__pycache__/main.cpython-314.pyc | Bin 580 -> 0 bytes .../app/__pycache__/__init__.cpython-314.pyc | Bin 160 -> 0 bytes .../app/__pycache__/config.cpython-314.pyc | Bin 994 -> 0 bytes .../__pycache__/dependencies.cpython-314.pyc | Bin 2082 -> 0 bytes .../app/__pycache__/redis.cpython-314.pyc | Bin 672 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 166 -> 0 bytes .../__pycache__/presence.cpython-314.pyc | Bin 2032 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 168 -> 0 bytes .../__pycache__/presence.cpython-314.pyc | Bin 2633 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 168 -> 0 bytes .../__pycache__/presence.cpython-314.pyc | Bin 1912 -> 0 bytes PresenceServer/main.py | 4 +- .../__pycache__/__init__.cpython-314.pyc | Bin 162 -> 0 bytes .../conftest.cpython-314-pytest-9.0.2.pyc | Bin 3179 -> 0 bytes ...test_presence.cpython-314-pytest-9.0.2.pyc | Bin 17740 -> 0 bytes diagram.svg | 2 +- 69 files changed, 13 insertions(+), 270 deletions(-) create mode 100644 .gitignore delete mode 100644 .idea/ChatSystem.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml delete mode 100644 ApiServer/.idea/.gitignore delete mode 100644 ApiServer/.idea/ApiServer.iml delete mode 100644 ApiServer/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 ApiServer/.idea/misc.xml delete mode 100644 ApiServer/.idea/modules.xml delete mode 100644 ApiServer/.idea/vcs.xml delete mode 100644 ApiServer/__pycache__/main.cpython-314.pyc delete mode 100644 ApiServer/app/__pycache__/__init__.cpython-314.pyc delete mode 100644 ApiServer/app/__pycache__/chat_client.cpython-314.pyc delete mode 100644 ApiServer/app/__pycache__/config.cpython-314.pyc delete mode 100644 ApiServer/app/__pycache__/database.cpython-314.pyc delete mode 100644 ApiServer/app/__pycache__/dependencies.cpython-314.pyc delete mode 100644 ApiServer/app/models/__pycache__/__init__.cpython-314.pyc delete mode 100644 ApiServer/app/models/__pycache__/group.cpython-314.pyc delete mode 100644 ApiServer/app/models/__pycache__/user.cpython-314.pyc delete mode 100644 ApiServer/app/routers/__pycache__/__init__.cpython-314.pyc delete mode 100644 ApiServer/app/routers/__pycache__/auth.cpython-314.pyc delete mode 100644 ApiServer/app/routers/__pycache__/conversations.cpython-314.pyc delete mode 100644 ApiServer/app/routers/__pycache__/groups.cpython-314.pyc delete mode 100644 ApiServer/app/routers/__pycache__/presence.cpython-314.pyc delete mode 100644 ApiServer/app/routers/__pycache__/users.cpython-314.pyc delete mode 100644 ApiServer/app/schemas/__pycache__/__init__.cpython-314.pyc delete mode 100644 ApiServer/app/schemas/__pycache__/group.cpython-314.pyc delete mode 100644 ApiServer/app/schemas/__pycache__/presence.cpython-314.pyc delete mode 100644 ApiServer/app/schemas/__pycache__/token.cpython-314.pyc delete mode 100644 ApiServer/app/schemas/__pycache__/user.cpython-314.pyc delete mode 100644 ApiServer/tests/__pycache__/__init__.cpython-314.pyc delete mode 100644 ApiServer/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc delete mode 100644 ApiServer/tests/__pycache__/test_auth.cpython-314-pytest-9.0.2.pyc delete mode 100644 ApiServer/tests/__pycache__/test_conversations.cpython-314-pytest-9.0.2.pyc delete mode 100644 ApiServer/tests/__pycache__/test_groups.cpython-314-pytest-9.0.2.pyc delete mode 100644 ApiServer/tests/__pycache__/test_presence_proxy.cpython-314-pytest-9.0.2.pyc delete mode 100644 ApiServer/tests/__pycache__/test_users.cpython-314-pytest-9.0.2.pyc rename ChatInfra/{ => environments/dev}/.terraform.lock.hcl (100%) rename ChatInfra/{deploy-client.sh => scripts/deploy-client-dev.sh} (57%) delete mode 100644 ChatServer/.idea/.gitignore delete mode 100644 ChatServer/.idea/codeStyles/codeStyleConfig.xml delete mode 100644 ChatServer/.idea/gradle.xml delete mode 100644 ChatServer/.idea/kotlinc.xml delete mode 100644 ChatServer/.idea/misc.xml delete mode 100644 ChatServer/.idea/vcs.xml delete mode 100644 PresenceServer/.idea/.gitignore delete mode 100644 PresenceServer/.idea/PresenceServer.iml delete mode 100644 PresenceServer/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 PresenceServer/.idea/misc.xml delete mode 100644 PresenceServer/.idea/modules.xml delete mode 100644 PresenceServer/.idea/vcs.xml delete mode 100644 PresenceServer/__pycache__/main.cpython-314.pyc delete mode 100644 PresenceServer/app/__pycache__/__init__.cpython-314.pyc delete mode 100644 PresenceServer/app/__pycache__/config.cpython-314.pyc delete mode 100644 PresenceServer/app/__pycache__/dependencies.cpython-314.pyc delete mode 100644 PresenceServer/app/__pycache__/redis.cpython-314.pyc delete mode 100644 PresenceServer/app/repos/__pycache__/__init__.cpython-314.pyc delete mode 100644 PresenceServer/app/repos/__pycache__/presence.cpython-314.pyc delete mode 100644 PresenceServer/app/routers/__pycache__/__init__.cpython-314.pyc delete mode 100644 PresenceServer/app/routers/__pycache__/presence.cpython-314.pyc delete mode 100644 PresenceServer/app/schemas/__pycache__/__init__.cpython-314.pyc delete mode 100644 PresenceServer/app/schemas/__pycache__/presence.cpython-314.pyc delete mode 100644 PresenceServer/tests/__pycache__/__init__.cpython-314.pyc delete mode 100644 PresenceServer/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc delete mode 100644 PresenceServer/tests/__pycache__/test_presence.cpython-314-pytest-9.0.2.pyc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ffe7c5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +__pycache__/ +*.pyc diff --git a/.idea/ChatSystem.iml b/.idea/ChatSystem.iml deleted file mode 100644 index 50e439f..0000000 --- a/.idea/ChatSystem.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 655edb9..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 6b0bccc..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - { - "associatedIndex": 6 -} - - - - - - - - - - - true - true - false - false - false - false - false - - - - - - - - true - true - false - false - false - false - false - - - - - - - - - - - - - 1775100397928 - - - - \ No newline at end of file diff --git a/ApiServer/.idea/.gitignore b/ApiServer/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/ApiServer/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/ApiServer/.idea/ApiServer.iml b/ApiServer/.idea/ApiServer.iml deleted file mode 100644 index 0f7c2b7..0000000 --- a/ApiServer/.idea/ApiServer.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/ApiServer/.idea/inspectionProfiles/profiles_settings.xml b/ApiServer/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/ApiServer/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/ApiServer/.idea/misc.xml b/ApiServer/.idea/misc.xml deleted file mode 100644 index 790b6cf..0000000 --- a/ApiServer/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ApiServer/.idea/modules.xml b/ApiServer/.idea/modules.xml deleted file mode 100644 index 39b73b1..0000000 --- a/ApiServer/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/ApiServer/.idea/vcs.xml b/ApiServer/.idea/vcs.xml deleted file mode 100644 index 6c0b863..0000000 --- a/ApiServer/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ApiServer/__pycache__/main.cpython-314.pyc b/ApiServer/__pycache__/main.cpython-314.pyc deleted file mode 100644 index 2203fe278ea656c212fda694dfe0de563364cfab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3948 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 A=l}o! diff --git a/ApiServer/app/__pycache__/__init__.cpython-314.pyc b/ApiServer/app/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 88c15126c4f486960a60361240517e369f7e09e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 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 diff --git a/ApiServer/app/__pycache__/database.cpython-314.pyc b/ApiServer/app/__pycache__/database.cpython-314.pyc deleted file mode 100644 index f7fe46d85e61bc7c9be94927ddda7118fd719ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 753 zcmYjO&ubGw6rR~1Nj8mbQ`?GQ2}KZ6Aq%yjh$vMl2}miMOD^d!-AH&Txp=9Jw7pjEq83KzhXHeQ z^I$sB!2}(m0Jl&R18!PiHEpnKhO=5u(*<`H+pR*g2*n!eTAQd_JXoHW`hV`|F2=y? z+B(MzoWQ+pfyJP3fSE{>$a-w%5fUDnUoPv)#Xqy3XD)g z5|;L&l&O^r$t)+K&zPuVwe*;UF%=Y|5qn4_(^N?^fGF+BJq?!G*&q^(@RWo+Ng@a{ z0h!Nrqv^WF6Vye30|eG#8SDUq6IfcKtsGPM4cf1}szgXi6Gn(C6O!=bVQk_GA*Vwc z=Qm4)oJ2xGtW~F6U#}4&K`RUi1rX8E5SS!HEa;w7qeI>C`#fQO$YbUo2>z6XApJ*u z3hl83miW7asLjNP37-xI{xJo5q!l#=V__COb0&~xxzEuTrzEO#e!pH(>+&?FaoA_c zxWUe#F&kvWh1rF0j580_;)OIW5>YT@S$AxNJUxkeqG*W9ygeC;SQYZ+R4?xD2@h$U zNi%=U#H^UdrF+@T?u)A$n(52C+WodM#@|rq9Cf~;t)Hm&-MjX(^J!!Id}I5AcWYAk cyn5r+=&k#4b?-f@{wZMWy?F2!>0?&=AD`04Qvd(} diff --git a/ApiServer/app/__pycache__/dependencies.cpython-314.pyc b/ApiServer/app/__pycache__/dependencies.cpython-314.pyc deleted file mode 100644 index 593214e9f9f19f6dfa9ca5f928270c7960a68631..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2453 zcmZWqO>7&-6@Ifz?o#|0MTt%HL)sE-P-#S2wV^a|TdpHtwZ=vjgch+S9+iZ%z|nvqILS#|%E??#3Z0bq z?`_bN#_WBpcqI1k6$Lo;PSxfuGW>}J?UFgF_?g2C;?{FBz&+K9*1<~f!H7| zJL)`b(0bK&Lb+0@u&`dC4Q^O!c;0_xhm$7vYR&9aFh0H%Jk{|)6m<4d!4D@p zOJNlcHUfr}gi$=1_=&a8$)jM9GqOR_WRV5Y7o$_{PNHma_>^-tQ?u4+rec{iQ()Fr zOq`vWtLgm0hRx|(CfhJBPu2SJ(jV6~@Q@CJqlU zHTNT_oyc+g--{f-v)T?1{xbAPhUj=lc{u*h&fcER?h=rbG$Ad9I1N6Q5fY-R!98GHfO94%}m6N zc~w>{wx)A8t;bnREDUOzUawmSXsT&!7*!%q_6ZzX@CXJ;^r0B;2f}+Y&j0kq_q;eC zD4_Tss>to5CsYm(h=K_2r}*su6~jG>!Y@N990r2ET|%^xqLd*;dA5tVhBORiv7<`` zf$$@A4AWP3JCZOI1cZ*zV^)!fBQ!;dp2N4v7v)0#5eF2D-d@LOcrJQY+-tfh)yOcE zNMZ2n{^dkZSN=wi>+MhwNj^efdKE^Fm{2Tvp2=bTcEQt|&p}c7O4WKx-a_*0t9w=6 zP)bVYY6_u}x~7{(6#;yUuQ>$22R97k24bxF;RIgGd+NfVQS1o4n z+M11^ZC+VSN0~qe^WxwPitekOo<5~5EoPTWxtEIhA1%x?0R^#{*pvl?;I}EBh-@i;+@f&2*K3qfM>48T%*KYRGtH_~&0<;|=d{X(gsZqt zXYjFbHG23pP#gM&Y3Wr*ZDOO=a3ichyJ>RABNVoH^NABFL7kF|iiT8aGKQJbgbSNN z7q{#-krA!wzz3s~_v26Q#HY97)9py6-9LWk(q?q(K=q6&o1Q23{EBzter)j8 zm)^L!l&cgE6!t&<)rF*d-{#$q<`i;3WHoY}A{pa|Hi9aPiI=6LdZhLHgdthNFw9tCK9q8W) zOl$=vwgV?x^KCV7^R;$(eA74H4n$fn{`(*T!T13X??gwtCnNjchYEzBC;zc0F{qo# zxntz_+0a}V?q;$Q3ZI@Lb4kyqGb6}<77ovi$e)dPkY7v>IqHgzh-ny1G=ayE5bf%x z@S>ZDmklO5gX6hsVHQQ6JD?b{e{AYzrAF5_rsz7K(#5yeu-sONAUQO;FhKA%8dDXk zzGAF)U=$Pz#J7G$$8AI64H2PQL!g=VlzU^Mk2oPqe3NH1TfB<89~k#4-vcJ9xO3aS zv$(El((khGpib1V{Q?e{B0@fgnJt*vg;Sry*e+ytVe|_~?!x3Qr2ZbAcz5ky^lU5i jFGV6l4}%bU;`Zov|H;24#%^DG^Cyo)7j|2-`>y{3>y#q_ diff --git a/ApiServer/app/models/__pycache__/__init__.cpython-314.pyc b/ApiServer/app/models/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 92930282ea8e92f12ce750819649896f691a7192..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmdPq9Mqe;W^65hVUZ~!aY@3kcO|(5$GF32^GR2NXM93n zLc-152@mr)ej({ih)hiQn9muzlm0}21rC#aq?1UVHX?a5fj-z18w)yK5xl+zZ%E?0 zN!0%smkdWaThtV$vs_+}3btpI(OluCEnWrR82D`eK#}UXn}xUZd0Ut%71XH9_FPlu z=5);t<(*zui$*D5fKb9^#ne>{TyLJ5vGpw&3M8B%jFSj+P5Bw$N{Wy^6Ef~jlJQ6` ziHD;K=jzAz*8FbCbIw(b!^EmDbjo(=584M%yKHyO2sQYoj|Zp6N2vV|Yp{qfmiUXMf7_4o)a z-qKZO#;?pOY;@jadOrT9+qGUxh_Ilf`ewJWB8b8rvt$9Q+P3$8#YD98qt>c9+5 z&d%@H3R~u>2n%Th0UsigWTr^-3bRA9tQv}GYB`n3vWWq^EV>suJ1EOap-^NHQI_qN z>UA{wP)5ulfWJN_ACOHC@kKs07XxKsdecidZc`+I=A}K0J!RqIrVkx{(%iOWegP{| zn*nqL(eeJnrXyuRdlCYVbCa|MVh%@JY*CgmFWB8L%kWZ42HJ40J0-=a%|v8*CPz(X zg{&Qy;{lc!RVPp$ox-(2an4N4)?xUnssukD}GwkRwV8#M}p^fjZ<= zSz#bS*%H%DaKp;&;;Fh}$nr8rUxFAWKAkt5GSVQJ4mjmX!3fG_kstPUSl51O?Y=v( zDwGH0O6# z1H7i^vpTgyj$p`nXJjt;oFUSBEXvU~*oYzx=>dd;059fq0cQRuKJVtN!)M4tphsX+ zTdbZRnCnGBlELuZD#8=i;Dym+uq5iDNb~A*YM>=Of#0_`6eHH~US(85^8!GflaYN( zql>r8Lb}e$@ZO~>i>b13qt3~u)}`5pk;7#{eS)NHq+l~WiD&3RIEC;sLJVPtR}P!b zqYwApp%jhd@KuCfgwqIT5Y7TLQsfnMA~>fX1EWTfZlFj<^xpB6ldGxqGs(4gQk9Oh zmDo6N;$G{@{?(!N(}Qc*Co2bTSc4l~@fGp@(Ms>&+C=)%#PoxS>Gg?hrAxJv&oHez zH*lM1m^R^-sD-xQykjVaI;-dBt2*Imf|HaZ4B?&m7-(iyN-=vo2tQyk`1eG~!v7T% z>0KqelMZTFwUmySiv3mnxe?y4&= diff --git a/ApiServer/app/models/__pycache__/user.cpython-314.pyc b/ApiServer/app/models/__pycache__/user.cpython-314.pyc deleted file mode 100644 index 0650e2a43517caa977ee74cd33da796770e1d432..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1722 zcmaJ>O>7%g5T5m}?e%{XnuI_~nwmzkpm9+x1u0PkEmTgcny_gjMTxW7?7rZo>$UUt zZA&<+P0B+-eI$;Rg2YwJV1(IqQjmFU zo>ALt38b`>$MtoyE6i164IquC@D&(y=WZZ;gh?xMSL-tdUojop>8-eK<^Dh9Sv z1tw|0A}dKI4?+VQV@fqT2Gy7r(PS)7ncOcfet<`{*a52kCz|M?Q7t}+WQvC+Lo9`D zM>KU(>Y~;3+%sM6s2qb*@2DjX{Id&iPSTP?;HWI8rP#3rV0~H|3CnQhnnx&)`Y64t z|LR!5K-hu0H-kz5%e}k+%e}e)=EQ#XbG&i|A?HKhn z%b4LA(aOaBF@ur4r%(j&mD$!79%{??wdDueO1q-de#CM9sV24S2Hn)JlT9AC$hzS> z?4no<-?cY&BwPjBhe;}hey-}e=oza?>N+l(?+6|1-0%&jXUXaMx=lUi*e-D!XvPki z*paTCsu+uk>C@+g7!~5A5Mx4!3z5c9aM^9#q^E?|ccf`?GhxgDqzZYlO=K5uuQi_$ z4`KZ00huOo99_r7d>&(XV(nfDX{9MtLlN>PzG>tyfbWh!8(jHmFn{~vU8QwVZx5~p z=XXa6pN-!=elOY{sRZTS;qluy?pQn5+QXNF*LU-0?+osoZs*Iv8>oNz^iHY$Qu&+3 z>cd6j{-W_<(QN0f;L=}$#rL7hqexvy)10V4>;X@D8;;?aHB#T~a&p*z_RutetJ2*d zK^{-zXFh=!xUq(}FinVHVNYU8-8|v?sMFmE&Cqjb5CnLqQT!%LlJq^Ket;9d!kHGF X`4P_k0w?~6#U&zrSo#yhI}Gy=v&fcL diff --git a/ApiServer/app/routers/__pycache__/__init__.cpython-314.pyc b/ApiServer/app/routers/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index d4bfcf93d0675ff63bbf510876cc3762baa8b7bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 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 diff --git a/ApiServer/app/routers/__pycache__/conversations.cpython-314.pyc b/ApiServer/app/routers/__pycache__/conversations.cpython-314.pyc deleted file mode 100644 index d26e67531658c55e2da19a30a9bb292125b95141..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1016 zcmZ8f-Afcv6hC)ncJ|XVrKzt}Jch9shV@J-t&dh6U-*R%`weBXP{`JFQs?Fs>&2d{UW_XOaZR656Z zAhh0~(11lSNe;3^kgOtTZBIE545MeVs0;$NZ)KiKZoSMs- z)w-a}_1~m5S}F2P;+|fn!YWiN4=LleaH5-u|&ldK1s8mhI3zoJG;|H~VL3d-0I1qb5g`U`^<@{a%j diff --git a/ApiServer/app/routers/__pycache__/groups.cpython-314.pyc b/ApiServer/app/routers/__pycache__/groups.cpython-314.pyc deleted file mode 100644 index 0ab15380c2f07615f29aae4a78431aa4967fcca4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10902 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 diff --git a/ApiServer/app/routers/__pycache__/presence.cpython-314.pyc b/ApiServer/app/routers/__pycache__/presence.cpython-314.pyc deleted file mode 100644 index d867a00f29490a63e5368f1aea1aa647138e415a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1880 zcmZ7%O-~y~^v&*iz5c-KBz#nYfB`ksLfCBrB2k(TplOVRh`UKq)Ie6-^?)}uwmUPf zfD`?YnyQteo|sg|8Oy~*ya(o#Ua-QJks(%ORB7HLTIO2vCxgph?pAb|G`Tso7v_wB zJ438k2UzhAC?!i|_`pDz7U_p{%QMMOr&T{PmY=jLH9?slevejZxxoFF+>IOgD@!h| z3a?U56W`!e2(P@rkxnj9VY@ZPXj#}bP8rIy51V`IxFg(Ro>5NAF16^VHOj?GBwIa@ z_(njb6<&+Q-UAxa7_MaevI@RYeI|K7Ty>U96{p}6JFTz?ikN{2z1HU|Y|#;1Uf1Ve&K4_+H0xGM zG@ECYJJc0CJ5hAR^<^&TVs@^=dww-dhA{;?&o1MU~ zCUEgCM62)u;-q6wq9-lAyDIK~hGTmn-1kur?xF9sqS5M+0 z3B3^H_dK!Hno?73C6HVt7Tm#zEs<4qDinpPGNa^!+HIOQ@T?v%d3pa4h+}o1RxD)( z@{NvoU7aPC`ig!0b*<#^gf=R3iEtH;c%)h=v0ymRE3fN&;HH|Fp*#Wu2mAu+x?uKL zpteGmZiR!sDUumAFOzWug81}97^c3%bp_XG3I^e-yk83<7KSJs-h{F50#E6Ilb99x zH#L1;JqaEeQ9Y72rdQ0vifGoeZ^#z0y#ilJEDd>O?6a~{8v2ATV+Uw=c%|%zi_|Gl z#=Ym5?Ugs)cf1lUq(mh(Pq86VuXId|V{O&A?N$oZ*9%nO(R9=g6@{oS`LQv+Ty`f) z9yX@0RV!RDnNr_$v50N-0&CZ#G}_k=yk-3;Y{A7JB6@}u{BIPJZQEw*k(t^y`|y9u z?E7(kr>*mcTi@S$Vs>ns1DobRJ@M9>S&yIHIo@@DVY@rC*`28$%kH$j`Cw^#;PU3c z<$CMbZW!8o_d#oqz5p#5y{o-YA=!^#+>Jv#dGFG_OLs3lNp!BM_2KEQ#I?F{Z6{{l zJNM1GZ_n4Y_Pt|xcuzsYzzi)PnSK9p7d`!=Z{h@bK*rxO9;!&KjfKWXL+e9i{EV@l z(IkC3hVu0bWPC(hzu1QKMr*gkX9#LHMu?z{idsB)Ru@p)?Ba5st z*8El}co)A_E76N=5M^>E@;stll@Rh9 z#Q%noO&IwLdY;12Q%F69k>4Z7?+>nhv^KRBIk&3s>Yx~3cYfY^_vT~LzNdrPUT;73 UI5F_NG2>KFI{r~`+BI(cA3+kK&Hw-a diff --git a/ApiServer/app/routers/__pycache__/users.cpython-314.pyc b/ApiServer/app/routers/__pycache__/users.cpython-314.pyc deleted file mode 100644 index d8e61de2404a71c774c2c841612a7894384f4d35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2864 zcmcgu-EUMy6rZ{G?(W@>-hQ{x7D_){T)x!^A{hOzeNqW-*1E5;U49Z(D01ym`*uy)Cpo;nrln@F;}na*WH)C%;9$!zi@6QVqK3udsS8ImmbS!TvlZ(23TljEGT ztQj8{jNhP^avC^VBiEV8=dyxLxg)qNESJsDMV_io3a6DGpp6xHGC+~fy*lRiFzOf@`zBnVG+qS(`HNXnb=1|0SAWpKKzz6Af2S$ zK3*5uE2n9Q4&H!xIr_4L4e~}1%Qui=9B~)GH9wFCVED7Yc~)tDEEJeul3jGl6A>)I zlVeXM(+#V3G7o_8Z^_i9;Yv9HxaDE=Y>$WxNmh6rOe_`eHJivVO9EWb_zl^Tg~>T? z#4$EFLj$mK!tFEIiLwcL5J4cAEtPgIB3aOCOEU1^)P|A^_+M_K1{OUa@n%p>V))MR zf?y}G0q(PsKpJz9<7fdNUbb2}hEtz0&l8FjaYZYpu3e4c!B!0&kQpF4*(E!E9Uena ztQu#QyN;uE96IAUh;o7!ta_ChOr5?It6hJsi+IS1P8&v&MV}iCc`Xl{ zU`ecdJgj{&mh0^?#u;ye50)!!q|YS7lU@*9)jLbk8Zgx8md>bfYgyK99#Ahi$8k)Y`|JnWpRr|#JI54la%&9Hc_I!Qt ztAq2c;knlE&DxtiH@DsDoxWIXJzP{@nOFPg)czlNQGInumKxlTh@`m-{UtXE)O~vB z@}Z)?b>81T=Wj3iJ7$%RMGq`L7Ko`!y&XqXI@3juxRsgiE|8~uk#`WO@pS6l|F$4J zm2Fn?#oHmIe<}k^>T(%)Y0V-5vQSl1l7ZW00K8HLAgwI}EH=9g{s7_sD}y1@69qt4 z%FW>bWU>ax&nOrN$a!T**$Q#vI17!ijSMdrj81h)m!0Q&j1DO_w71*PRtD2wz}{2Z zX}H)e(1y2+=Ek!rcw_tmTJpGvC*d)%+$m-z(niR`yI_YE{PS*@T2eY?)s^8M&t+LW z$KzSx9RIh3Tzm(bEF+(X&_ux-7N~&Wub^MW7ZDfuZdgDI@dl8mkbiCTn^RYf`OQ1$ zHt+nd;rr%qn{OSTd+}&-^RZ%m-+WbHq5qD*cHZAT=kG51gN0-F{nZOv>$E((=h$tn zZ&vNQt!iM8eR%)6n4(|MwGC{m-~r&09=n7><~W) z-w30;i+#{i1ymeQepWZsX@wRt&!3}LfQa@~YujQk@ z>pKc9MH;yqd|@_xs2Du_5Fh0wnMgZJ5=bT0(Hyv*nm+JTum{y&UUZWU?N=^*e(|o> oINKB~YFi)TBZPMQOA<(>Cdcl?bQ_wy^ehu7STx!9r{t9G->q~k2><{9 diff --git a/ApiServer/app/schemas/__pycache__/__init__.cpython-314.pyc b/ApiServer/app/schemas/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 7d4dc5b4b157f62042cf7530230b37a0fd31c8e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmdPq)m8G*`{eyD72+gr4>yrK@XK$Dxilps0rYpUaDqr?AgSX*Is63 zk#gIGO1<{Lfg{)aF-Y`?B@PI2sJL{K6>#J|d(%21R1uc^=FOX#_r96$n|Zg@Yyf`a zKYonAV*tNV=kT+q&cT=H3}F*|whDJa!+G+JRd(0V#(7wTi{P6};9C!kYi7Adn?=;d zs8fkrMYM)dw-UAe`X%Tzp3~9}%iSo@LdQLUe*NP>iM1>eNmwQ>tugH!TtO#5Y!5** zAGERQX!8tYa39`hK3jss)s}B)`#xyLH?fM9&)kvOpnqEmtPeG?cvz!2=gdZ(7VoD*)$ z(%`(8MT3NV%>UIONTwrmoOffXbP}f`&2YF~DbgLJA%+%lZwMz2d7!n7w+33Ma^}n3 zhayQh-(zx?V9|+xD4S>{!7NOHw}w5$`ve|?oIe~np80Dye1!Q%$-K{e!(-Yi6o9Hk z1=zl&9aKQgw~;a@Zx(0f3)Rn3CGxqh%z72*UmUNBPq5%gR54YEK?<4r=G14X9E*H} zVM`aC+=wGtC#Mk>ij4Ty?khjgdxoS7DoL0fL(Y(2oM9=Z@(^2;;Ef}@I-&*2px#4M zYQdcu-5HY>ekE0mZS=+tv`>#d9oNWrp?&t5wY*=)PDw)>*RJom@)Wjmfy`+#i)iv$ zRE|h^n5Er#Tb`l#5}9Q(XVFyYev^V^3P>~sAr0ZhEG%CBLI1RHWq9weCYJqn%0Ep# zA^!^}=6|6$sWs8t67o<5@*GzB59V*-(Enhb*e;l-XQyP_-KJa2<0!8Ul#t}qA7yy8 zBGjL}h;?4i@r7fMA7PrfQKYbv=~jERRx;h3AKg1-dVcwtwX{!ESJ;)8aMi!~qEwPh zk@yu~jS62g6~1WdddDf`n!EkoC`j>Lko2^cSG^EGk(D%6)~AOccW;(2&@H)wU3wvu thvtRJ82bg@`W@b$IE=NPb|zS^HE|ub@^p0q*i25@Y~}mTpMXt~@E?q{eb4{^ diff --git a/ApiServer/app/schemas/__pycache__/presence.cpython-314.pyc b/ApiServer/app/schemas/__pycache__/presence.cpython-314.pyc deleted file mode 100644 index 56403167cc46e2d78bb2e42ac013b22637432da0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 747 zcmZuv&1(}u6o0e3Nn>fMmDUsyr3&I==^iSgSftjA9xQbOy+|{TvlFtiU!8d?0Y+w(xw{`@6>sc@{uGB^9Nd7gapKI7*>gL>sApxOGC2iIr8hIi>!b*( zdjQB{K(7~|e+f$1hfNl<4rDD1Vhx8`NYp`=!nW+BWAh6UHQ|M9z&%x<0bo(V)y#B+E=id%AqBB%0{)Kwx)hQ0391 zD(x!$M(IdYRb=Eq<-$bOY^RNCXcssaMNy(a#kpPk-_9FnA#P{0OybWmyoIle7vFEb zOFspjpFS`)CO>?H-EhvfI4?x*YR+?>mr0#Dow^;?BAZ3dbKXz2!7MFQQBrv6Os9Tb zNOG;vvNT*Oxj@wEs~VM=BLAI3sx0F?WO~8P<{oETw@GUEPff&R=sB`z=wmnnec?2+ z8~V0Y4HHpN3+*0rnziJ#3CdNnt*z+_54C$m*J5&mA3kI38(jU>WNh`r{oizg)k)T0 D?GL-v diff --git a/ApiServer/app/schemas/__pycache__/token.cpython-314.pyc b/ApiServer/app/schemas/__pycache__/token.cpython-314.pyc deleted file mode 100644 index 6b1c5dd5238e195b1f31335b4d33fb2295d58422..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 726 zcmYjP&1(}u6o0e3Nn=Q~t&If{MFnwDx}Y8etN4Ln4_4hsFVYO-WJ0#xFK1qa+@cif zAK*XXpX1R14y0Q{}+cUKYD5my9yqaTL&T159raTW1qW?|HZP z0QzJ-2QS!=MbKrh;EorwD-<)wp2JksKX3!tmXJ~z!_hUc%}Q__mx>ng4eHRd^+BOC zfws-LOocK1L?Y+LrC*xZyV0=7R3wX3MbCAyqa>Q>(NJJ_Y*1yR`;^}wKe%A<1 z$qS!gGhDC@&U2BuQccdYqCZLk%q5i#)mlsnV45km;72&^^n2-6pQx_o-Ml`T}V*`abM|UOe<{hQ4i-QwJd_A(=+OobA|AXM6V#(sGpnxP&4KxMb@ijFx_^CSbYvLtdu3jyhZw*|>iqiL zzOi`~jUFsR$gaR;&@fB3b%kBFv^5J8updHu3PR_uHD_0Av|V~#^m+qcC#)TWrvI5H zHJR~~NDG~|1=>RwA|)1zL}YQbMWt51vw0Ma2(!2gnuVaPWl!6aP{3_C$wD>-nXjGD z((Y~0UT9+!#|+<6LSB>tgTz=H&`+O(Kjpc37G<9GaF1o{)H*D$(TZIew=K2wIq?_#JtY766vc9dqu??g&HE@XnG*-Fc%WxQ4)+mSXSoW~iC zCTXlWSG4{>&&&raMOy@Mk%{2CEFOqhtKi~Fq?cBe7VY4CCtVWqk&r>u=>#fX!8j_Q zu*W;Arp|ek=Y_^nIX6>(3O_zL;9)3r2<68!cmnT6$JQ1$Y+&rew$Zh#8!lQK9yG?+ z7QWWd-o%OU5*C{^<8w~M;nu^Pw~M5kk&QtgcB8C6(%`(6N~NC2ti$_bK5k|`8Z zM_@$8<05aR_vJMCXGnID>_!>9<-O!2DN~}!m{JeE)M4WA3;kxt(cZQ1BN+B+|JrHl zV$&_F$49rCL^4{gwlp9idRicEF@#ias&q{g>#F#pW^2KJ1y@$P@VBeN!v+?IM TTY$}0-DAg|pZ*5el$-nnPBSYR diff --git a/ApiServer/main.py b/ApiServer/main.py index 29b41ef..655219e 100644 --- a/ApiServer/main.py +++ b/ApiServer/main.py @@ -3,7 +3,7 @@ import sys from contextlib import asynccontextmanager -from aws_xray_sdk.core import xray_recorder, patch +from aws_xray_sdk.core import xray_recorder from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import text @@ -21,8 +21,6 @@ ) logger = logging.getLogger(__name__) -patch(["sqlalchemy"]) - MAX_RETRIES = 10 RETRY_DELAY = 2 diff --git a/ApiServer/tests/__pycache__/__init__.cpython-314.pyc b/ApiServer/tests/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index f433eb82e32cfabb93a8af486498f5e1cf43d1e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmdPq>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%St~ZKQ~oB zIX@>=KcFZ-D>b>KSl>A#u_U;%xFj`K-?1PwIJKxOwMf4twHPQBAD@|*SrQ+wS5SG2 f!zMRBr8Fniu80+A6v(n-5aSawBO_xGGmr%UC`ly( diff --git a/ApiServer/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc b/ApiServer/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index 6f828a5f05a1a2a9c8eceff232ff539d5d61a997..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3514 zcmb7GZEPGz8J^jXyS)#e&)<$eY9~%oJC5%tu}S0vlWWe6k2=<|cHL4gzHaU&@j7?A z$LwBXTa{%}-kBA4MYn5*ZX)@q>4E zZ*9j!D9qi?yz|b?J2UUc^GG zk!wRkf+@B+BOcRZk9bWlv|K_O@|nINzv;Kf`9xqSXa~{z_9m)_YRnp&mJ+o?b!HvN_9hRytG8O&*MNG@+({(srUpneLfRg4=B0 zp$+=%*IPd4Np9zOs=}2t4vr-AhszG23**8eEDK;ZslbhMsgOG_8Fs0yHdXD?`+-Q+ zxxG}wCbhX<77v#-D0^hDyWbONiy!CvglRO7pWs%TyFKo-$zATLwp!OlZOp38TYQ&t z#~-KR4&+6{e~0h4@V(oPx{o07sAL`>(+$GJn7~jsRCh1mG-J$xU(P)33kh&nP*A`F8uf)gPVI^CX(lb0nIi`V`5SM)bs_ zVvf!jCdo%*1$C6rR|$)Y@e|Ks z@uvYGuH!!8=UyOwjiLIDCsyVAJ&vK!`+lI7d>pF-J{Y225HcH>G|d7So}C<2;xk=b zwWKouf9WF4b%iLX8Cl{P0?2Afw5X*S(o!GeN_k=`S;bT=zYD{;9A$V#87x_~SyCWc zmS~xow0miTGIXL$(UjTS5;HlXP|KTD0n-6=Maxr$aRJn-Q3f0qr(`HY6@v+HhjN@& zF}}yqEp3Mm!ztqvsBArcR?%MC{k2;a$LF70udG{m?ec32a|?4noLj724^=PZFX!Kk zzjf-3Q)?}~D=odZLVaseUrFi%ZHJ#)nEQtZ)$U(Bd!x8oGdMr|Pk|Gg?n|ii@TC)L zLd%NK^5*!8u=lgdrngVOXRPi!`ayoJat!_-SB{lldU-t*z9KO}FJRz-C{c1&tqFTp zggvXm-gSR?A#yo#%ipvnH2pD-rn4OVeSWWUp%ZY3ji6bm1AE#kdWB?x$!Hw z-^I?sM*J?0*GkuUpnlO4ZxWYUaJ*hxY84p0I{@sZgE-zOEcL|dptH>3_*bN5p3PtO zc;fxya*$10Zou&)!g6CD&^IgaV7+iNN5kdS!9?Eq^hs>ez2*b>-kZY#a+TwQ?l{=XhCvUIS? zJrhC&QTECHaWRO#%thh-20$HyZ?6rxf!R=0DVmc}3LpabNofbHqi7R_>PF`W zCqH_jG&WIsWwO+xe!u&ce`-ybDhX5TRSj30f82cS^e+$GnEc3J8cUU)IsK#NTU8Tl zfr!Kdd3*MrU1E-V%o&y`vur9iYKL?3vOcpl#lOnh#zSNL~Z zWBc%1IJR3@d}YWpz;;p1nW|=3!Q+LQ^k#2Yx-es>Cvbg2 zncgClT%hm(uzZ^=%j@#|u$WCx11xj8VTIf-Lw;4aM3y(Ew?TM4ydjiaW|HJ*B4pZ( z*w1fOw^N6m4lFOxUR9~CS$>0=1fa~fYh8!5rk)Vgjt&<9w)hkZI+urRN^EK z%X?OxhOh;bgJx_CQTCLh-K?^6f^;meXNx&9KnH=x0>F3)s{1^~_%1@1&_&-TsO~O0 zco%*BQ^bAG{~iAts#`&IrTWg&fv>Kjfxn^JJE-*z>bUPgTzCyPtl)+RTorEK;1Sn& NpHUAx-GH}u{ttCY0^k4u diff --git a/ApiServer/tests/__pycache__/test_auth.cpython-314-pytest-9.0.2.pyc b/ApiServer/tests/__pycache__/test_auth.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index 4deed8f22034aa157c487e49aa86784cc3f318e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6952 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 diff --git a/ApiServer/tests/__pycache__/test_groups.cpython-314-pytest-9.0.2.pyc b/ApiServer/tests/__pycache__/test_groups.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index b230a30abd4bd4089da255a423d136bce4376cce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25070 zcmeHPeQXqGdY{>y{hVE|*I)Ppe__I5z+NymA8|}#z#o7iW@6S!Fl>yym?gG%J+lUE zL`un3;XbO6UV6t#_Xj7ns$Hoq7o93}*Q;Vk2yHoai33Zfk*;^@sk%y6rO<0-lt21B z@9exYyUen?1Y%BQ?0x2W=lz(OcV>Ri$NRkR>O8lTf$i$K+o7f^h8e`mR~NmDh`%|$KMN{%&Zg&flkTem%G?{-8Tid_ zwy$LbPOxlbl_P?63Dca&jJgHe5+<4_*nxTk2he=M3Dhg_KnnyH&_cltv`EMUS}b^g zmI(Pkmk3^I{4l7!+k7cs-dq25_iNf z0yAL36X7PX8xwph8(=3*ljZ=u-)emw(?irTXIn?$PB5q0YV3LVYc?y_mQA{jsbN+# zUsEbDBXBQEnGn1Mm2l7a*R!nET*-vk45b>fDJ5`qj8d+}9AfJ&(<=rekw!5*3C~1o z904XGH4cfv!Duir6dpeYM+c*!@Hjjq*Ld)FU}$i3bnwthdRsL#eR|7d`H4#LElh#H0bLU!$*TdQOURM$YAuP zDR`a6eC?6YOF+kcBjmxShz9oIeJyVPFW#2ZlyN!SSewZ;|HO*qxY7h_cKhjUayZk`ffS;NNUUVSK^NTTaNyJvAh4*%s5|Wk?tdOFMGq$ z`|pl^C~!|X3Ka>rmxTsnj@~b%U2vi^KoYwXmS)vonTL!dn`^S!upwB?C+FKFe8TeSU)RRHzxA$t84O`dbyN}kc^lQ z{=>vJKewryVJ7y`H~S-evj?nd`ChxqX?s8}uivts6$<*B*PEIXZ3{NRK0pu^OZK|7 z@+wzLzxd5?XrwabOnGWKZC}gyP0fiuRIhM&NlLwZt-Q+V>+NO*yWr5>k#TvmdLF@< zu`H*S^_kbuo`N2=3cTR*TYYTOQQJVFdR@Afi_~M<90o>QlF+vaz81-r!O_rA z@LnF-y@0UPI20b+bI;~e&`IXT2gicq()Fn6nN^^RzyDgOa^rmc3_cYnx@K*JGuoddYb* z!PK;ocGlKQjZ$*^)-XfqsjiTI7mTqG<-WnNcV zcD@jqA}~BC%3dNk0%9;C!rey(#h~nh?7*SP&}cL?F3Hx>Fo+gOE)7UW!jq%Jq-bDd zG<;}qG=M!MI|9<+;UKmk=e3ht2eH&4ieXVM3>*%NV}R|!6OqxuaU!rp{4nZWvNeJC z_)Ul7RtS zCGUgS0>?e@lX$=;luMr#t+;S(=6GyV_k7Wgc;1fFUAMhUzE|;1#raoe4qqINHEg@q zf39NQyD!e~JH7oj?}_sjH~5Mex9q$`$PIp3oJ;)AbIW3U1x-@sY%^s)=9a0cTe{Mp zV0*NXo`DK**0(o*WAnFK&mFtTSH-x-3u_3u!8gXa#Q!|k7~`vyfJ7ZZ*d?X8Cn~*1X{I(SFVIQDkQ`fSgN#>_QEJb{9AU=Xrd^|_Q zN3D(N`5Z;aY=P*84iK^P_lSrLBKE%MMS{I5n?l3)>-NVu8@Ga_%*l(SW28i4VzIAQI}U6b={HJ<-!-1FKE&ujCZL$RTeo1P=5yAd?Y-zh(TfRb$ln)kCNpno}PfmEd$t>!?IK$;eS@5kN5@j!JtvN96;pF-MX$W=>;`IsIm0 zjhO^Kts=zvIYVpABDf}kek*a99an9gk?gFoLca~Hv7&yz&Kh%r8|=|rWAwXMuP{q% zjMf8d3~VHwie_w$Q434R&sf%~+Da*kkX`T!1%7*qHRi~{8gr;EtNVmA&jQxiF{%jd zCDz#Ugf0iA=q^!;igiknY(5k|bk7BZdiRXXG;tGrG$LyGieB`c9P}b_J5;N85*G&gMvm;e1P6A-i*}vfefvJsEP$rjYw`To;-14dJcs8! zM`EF|o1SsSG)scJF@(FGIN!5qaOYr(ds(??mz@9Fr+m+XGIrzb@S%0KoO`zjxEZ$N zYus!laC26+V-+`NYeIfA+tI+yJqwnakG--IEHxkd;n!HCs|amCY7Cxx0NiqQPLxFShS-3Rd?DBIiMsO2|=E#UunmdYE z{1!uqw!(M1dJ7IHt?+xyoS=sIJV@=){s>-P-4iUTTOAW<)VJh@`_1| zqsB51(uE?v6%*iL%L3|gkXwWL1lD^9*5g>ca$BMwN;Sbxss)*p2H#6p&1|^Xa;b5? zbVs~k$LU?Si^{*Z^PQdNPhQ-0Zs&Z_3-P=c;_l8H?#_94_qC#%?meeFa}@zNq;X=# zeqs7z*`*DaR>mr~T|0mS8~fw@{zVf6JP`y1JLJ3BMP zkQz&e?>?0d(DBOFoY)JGSUOZQk59e`c@HgLiivzFNs=#!;!mc0$EeJ`Hi#;G<%P#?u3=zI6 z1>pmOqY%+GJf#Bu%TN^5<_s7nzo_F@e zxxN_Jrw(&JaWcW3Bokz=?^AyN!rd@*D2z`#P%LZ$u>c&1g;o#?z@b>!f?@&r4Qv;S zVgYy%3tb$Dg&N?mxY;fncO?(TvmNXQ&$YL~?rJNGbPLjtSVB2MZAhOA3Vk434#vut zHY13jz(LHE4MMbXF+}J%x7JL=dhmK$K|zPSdMWg4H6e5^ogqTU>w68y;Z<>}8@boc zl);CSVu)z<&+z6fp3 z=II8xG~1v9vU2lJr^o*Sg8zvK+k}!o0PW*Bo_x%wuAqyXFZnNZ$ErK7okEAufjEC) z(d+;N%s;Roz5*SZ1j1-Tz6rm(--glPr@kEM3D{J4c`Vwx(SU#g!g)>Rhx7zpOAEjh zu#IDog$kmnFMX=1Cq>>mgvY9>gGUczP*b*vpK3AT5!*n8nytk_M_dO@6QB9r#OL>) zsvzrNN5Dq}aq5|$bsl*AD*Jz~^ZI#&;+(9q+LSXHisu0;lvF>Mdac87S4mfDD6H?V z4_?4x0p|4Nbgd8xk#sJ@Yt;liy+#N?OR8shjaogpwtQiUuJ?`0(^%|WEJ&d!W4kW3 zkA>2VW!-97pEc=y_XuS|x!;rG`OMG3^O>)I=?e)gmS1z7e@gUq;y;pP3ihXcE+=nEyPgZQge$mCCCxXkB-r20r*`&nCD>3Nn z)+MFZOBevE^X)33<@&JlQJ83#u=pi$1WKd!DOq7)WRZNl*_r$_Nb{mSwsiCRZ5ULw zH_q=}6x9!7+dYMEPkm!5#?_pi`qoLw zGv3`Ccr1FFz+(a24BOKJ9t+^WW6`q-Jr>AsV0&88V*xyPEPA$p$D#`OD?GcK<*vBe z8zAw)v)eYq?pkv@Hu;a%t$6Ty3yX9Up{;~&LHctRX_D%U)-+L_cP@(RoH>Ss*!)K7 zCdQw@Fc%D@rj0)#bq!_&2o_LLo#}>OBN*LJ!%Crl659i#`{}f+UaG*T^)R|iC??VU zB}vi!7(=gF*M`1@=0qbpAAxoz>R-^GNeg&QQ3bSm#wrAz6#%M$3u4eRm8bD15EYZD zEcHL63|896JsS^~l<-8ktE`C-`$GzAsqy z5lMSYyI=-@gQ;R7&WJ;>P5jjF#HTQEUG3MA9}yKxyLaO!zr^nXg|)Q*Cpv}ItGh4b zr=e4{gu=)0mQde{dN+w7ZS8K1uZz}$x1=y-s-Ihc$?JZ1iUMXE$o^?kUsAFHCjOn^ zApH-H^PKy?jP!r`)Ba}|-CJk;HKp%=Wtyd_=L@3T{s*D|Oz4jZ{Q)kZFlmZ7LJU!S zD~uIi^wf}MaC5o;XfO4`0Cn`!wQ!hbN)vLHL zSqG-lYZEC$<7D0?D6jSGJu5_>*O2@Yb)uzmgqG02^H!cY1v zhXE)>eLNR}*^sAVE85;ag=0ng;@rL%x9_$t^JHvA>-+mLb8np68{_t>Q-5~MoI+)? zEzY+snlf3l{4X3obo?1V?^^Ri{`|VL$KHPB>?=RyPj|#zYi{$UF|PJ}#|^$V&L#fm zx!SXBO6sP@((GGUo~AxdO3}l>K+bKxB*xX958mMG;#}f?o~t|Cs-$jeEX}@!VW9qO1ct*Hn&&@l@ja1J;Koa=#U zO*Xirf1d5B;4U-m4Uo9fxYY%_51;k+RB>1N_7+H7W4AsJyMJQaJ+Ql8 zz#=Usw3N^aLaQur+*rwc0~EQ(=bufA$^-Q(cfxtVHX93Inln8U0OEC}!cuqUvahqU%J@pTQ~!*-vAo3SqKpgnlXUJdMix zJ_uvB=Pg1f2|Yk)gBmq4TV^PjWy{c@7#^L@BRegmI+tJyaVK<-^Yy)0BDVOeTa22M0nBCL-=g~RZZHe@dkm5^(F5H<$f9ewBM zg^G(~=Z?;oY>($}k9&6B@a&xT^jzz^=@B5*I>)eVeN5h_ORHj)9oJ4SdQ2W2iz|9j z&fl(v<&8oAL0DcJ#$T+#u)H>mzwmLh$o-7%Y~udD9JskswzGwsD{BJ&GLNAemt8Hu zUtuv=>)f60-tu~oMypMAcSX>*Z`mlh$o^j$rFM0K817RCTT_e4MdoxwT-+1suZ`cnWpd7Xha0>{e$j+J!=iu7w%klhV3Zf=2pP0ms0jh5zKliWj`!rk(MAehRUZA&G7alHWkz! zON>P3K(zsZ$^jR{D)3hES1 zf&SzfGuZ{IiTk1H2Sgb!xj)J*AO%Mci#V=y9Dcu-p=KvB)NE0woKW?aOgTw}7vCRh zM#sypK6Pb$)vgR!_A#AvCT(PJZq5)RzT4xB=myKN;s#wxFL$otx zaB8GDL$rFvphy8U;S9-CUhfRaRF-PQDS(^K8InEVX6Fp~3DLD@2>mXhZxFhN&xK5D`3(3KBv2jG6jb`^r#0XT3wbb*Fk)&xAb9lFZU?EpNu9lDl++o1;eWo%b9 zccl&{fYh=ddSL=cE&EYEi?oo?5<<%eT}o&*Qe*Aa@j{#e&d5Apng#)tRl5-Q{upaMI^&#TQf&QevFgFt>n9M9rsDk66JVTA zEr=)KcIzu;ySkh%S+P+r3n&ZlHY%}&uv~7V7(6b9qOh1QJtW%_$H;n*vQ?=fyC=s( zQS9bMTsfUA#ZDGwm&r1Xuta=#{4i!KtN+>#hfYK%#UNQ#oh)HXmTx2rsEM6$abyh< zGSOVb$%i7&Mj~x$^KT=nX2>LCv4?^nK(A@u9-1aeU99nJdX7t usk@VB2I3-|1-N`GkOCW!B0}tJ?VS<_yZlZmNs@AebFg*)T?$EZZT|;sMLz5R diff --git a/ApiServer/tests/__pycache__/test_presence_proxy.cpython-314-pytest-9.0.2.pyc b/ApiServer/tests/__pycache__/test_presence_proxy.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index a730c962bf6d1da43885dcd61450fda8030ef19a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4632 zcmeHLO-vlg6|U;(`R!r&F#%)1j3LYJtYOB$jKRW0#>O_R4MAmRoJeF_5++ zOJeOMr<8}+ud3dARrTui`(FEKtRX_6eSdRX{f9_M9y?AGY-VQ_moO)1u+;!5LvDFda04(;*`?9X7(&7@dh25t#GMNYhax+C#n_nLp$h-+eN%ouuuq z5o7*#Vl=V<&?ZLvNFw+N&dnu!W_VIxE9PfQ`M1pQY;H-dv3@OQK4^FCY zMV~XW5Oz4%9^D_@WCPbIeZRoF3J_7%!~5PT%oMo>d$Ffl9$SGlX}uo zOD-FRwwkme;7mbPipE?b%yCO*MAc=zoX;z|Zi?6SQjudwb98_ik>wo7LQKeJ82MGz z09MpWy20@(6N1^W0ud#{_Owz_S4_$3=B+h!G!l=SXH(0i6(yA~6_nIGFI`vihMqdJ zoHH)1LBOq~CN=ev!fz@(WhgpKA(fr215;XEOKNLoN6j?o$>0MJcV+kiSSSR4`cHs- z0-^b|wfoM6%ItPeUuAYv?Am^HXnpz*i}$BLQmP}DtNq`o%x;No8)Dn0*!Q%h^Ul%A zg(uzp>lZe=PgO2#iie(by|SL!>^gy+jwkK$4^}qYPhzL_X*gDG9KHY6R+xPpX4|pO ztyp{`7T<~uZo~#3h6X?Lk;o+qv+#QuX8+O;!;WrGj-O7`KTdRpSObz1PQ@c;Ct}5^EdEs{c8r{3t7YorSp(CuEQO!(u(h*KSDGCLema2H03mW z{g|HxlK2V=EI4Y*d_mur_3anhn)v2NH!f%WW7CA(xaNlKhZwdCZrIPG|LfWj!oHFX zj8N8gsE^Gr;+ug?d0I>aIw8kuj#+* z%~BR-5zmSCmlvINnDkOvzayLS4Y-~nL<_PgYsdyubkAsL0pr+e9?PxH*zWTP$%Y)u z&T|=3?KsuMamp3AM>uZww@tee2*nzB6=gsJs@MhGp>^yC6hQXV^`BL5t z)OoY@|K23T>rE!~ksvuMT>O?rPg)SyVfu3gHLu)?S&vhQ0Lgr5W$r~|$^nAZRjgFZ z5CWjAF6tb^kYm0~2pp4$8C+I!ivWA3Pg^@?iik+cF3uL&JLcaOdhCMNFDTO+7DoX{iRv6=XUW$su)PwGa_DC=^*w5UYB z8=t66WD+_6w4egL)q*-h2|cdrmQot#q8!T@-iW)GJQmEzDQ(Sy!5lZ6<$SJC0EpE% zxJ1iw#f-wVe6_3=47I46fkFu+bn~FBFPF-NMN3p(DwM9~3UV>Gq5yd7xoZkqFk_R} z3Dr{ZEaxR|9+0n<_zGaEvZ@tw#hd{%mOB#-W}t@S7QFIdJWgd#@ zeXVEK{Z$c(l-UyP-y<<&S;y{U55I|mu9TO7ndi-<@eTT100(}qBaqx~o*AZh=*)ol zvmW4nM`u#v?*ua57o`?O8eGBS?VB@vqQVO+11;>DsuIpx(Tw-!pr0ZXC0`~UMA~S zTy@orpGBCI_1EEXVD}@-V;NuKx(3yai}cQJ070O#(V)WNXPAfxa`EpLa>RHWsB?VV zEkH<6D|yYS??IgK4jjgu#XFI7A%SX=aIDICFOshUNkps^%=>Ww9n4=tl0fo0lA}ll zkPIS80!ajU3VF-=G317j3?msqg5{PT1Y#$xTE6PrCtu0sVy=D96tt}+F0^8Y$JLEie*N1|V+pX=!P+lQvY z^p|uhDE?}45ZDLOF8UadXFf{lpW(lD$QH?Lkj!65!(YkZvj7o7KREo(;ZFsLCU<;9 VXnKa+^R6&G{?CH~?c--b`QQ4*be8}C diff --git a/ApiServer/tests/__pycache__/test_users.cpython-314-pytest-9.0.2.pyc b/ApiServer/tests/__pycache__/test_users.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index b730b654d981411eac6714e1e08a065d546cdf9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9735 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 lny@BxtviX>yw6PG_{|8fx6I%cP diff --git a/ChatInfra/.terraform.lock.hcl b/ChatInfra/environments/dev/.terraform.lock.hcl similarity index 100% rename from ChatInfra/.terraform.lock.hcl rename to ChatInfra/environments/dev/.terraform.lock.hcl diff --git a/ChatInfra/deploy-client.sh b/ChatInfra/scripts/deploy-client-dev.sh similarity index 57% rename from ChatInfra/deploy-client.sh rename to ChatInfra/scripts/deploy-client-dev.sh index 840750c..263603a 100755 --- a/ChatInfra/deploy-client.sh +++ b/ChatInfra/scripts/deploy-client-dev.sh @@ -3,14 +3,16 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + echo "Reading Terraform outputs..." -API_URL=$(terraform -chdir="$SCRIPT_DIR" output -raw apiserver_url) -WS_URL=$(terraform -chdir="$SCRIPT_DIR" output -raw chatserver_ws_url) -BUCKET=$(terraform -chdir="$SCRIPT_DIR" output -raw chatclient_bucket) -DIST_ID=$(terraform -chdir="$SCRIPT_DIR" output -raw chatclient_distribution_id) +TF_DIR="$SCRIPT_DIR/../environments/dev" +API_URL=$(terraform -chdir="$TF_DIR" output -raw apiserver_url) +WS_URL=$(terraform -chdir="$TF_DIR" output -raw chatserver_ws_url) +BUCKET=$(terraform -chdir="$TF_DIR" output -raw chatclient_bucket) +DIST_ID=$(terraform -chdir="$TF_DIR" output -raw chatclient_distribution_id) echo "Building ChatClient..." -cd "$SCRIPT_DIR/../ChatClient" +cd "$SCRIPT_DIR/../../ChatClient" VITE_API_BASE=$API_URL VITE_WS_URL=$WS_URL npm run build echo "Syncing to S3..." diff --git a/ChatServer/.idea/.gitignore b/ChatServer/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/ChatServer/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/ChatServer/.idea/codeStyles/codeStyleConfig.xml b/ChatServer/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a1..0000000 --- a/ChatServer/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/ChatServer/.idea/gradle.xml b/ChatServer/.idea/gradle.xml deleted file mode 100644 index 2a65317..0000000 --- a/ChatServer/.idea/gradle.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/ChatServer/.idea/kotlinc.xml b/ChatServer/.idea/kotlinc.xml deleted file mode 100644 index 739bc36..0000000 --- a/ChatServer/.idea/kotlinc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/ChatServer/.idea/misc.xml b/ChatServer/.idea/misc.xml deleted file mode 100644 index 5cd9a10..0000000 --- a/ChatServer/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/ChatServer/.idea/vcs.xml b/ChatServer/.idea/vcs.xml deleted file mode 100644 index 6c0b863..0000000 --- a/ChatServer/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/PresenceServer/.idea/.gitignore b/PresenceServer/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/PresenceServer/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/PresenceServer/.idea/PresenceServer.iml b/PresenceServer/.idea/PresenceServer.iml deleted file mode 100644 index 4fe5e42..0000000 --- a/PresenceServer/.idea/PresenceServer.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/PresenceServer/.idea/inspectionProfiles/profiles_settings.xml b/PresenceServer/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/PresenceServer/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/PresenceServer/.idea/misc.xml b/PresenceServer/.idea/misc.xml deleted file mode 100644 index 41fe1e0..0000000 --- a/PresenceServer/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/PresenceServer/.idea/modules.xml b/PresenceServer/.idea/modules.xml deleted file mode 100644 index be67521..0000000 --- a/PresenceServer/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/PresenceServer/.idea/vcs.xml b/PresenceServer/.idea/vcs.xml deleted file mode 100644 index 6c0b863..0000000 --- a/PresenceServer/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/PresenceServer/__pycache__/main.cpython-314.pyc b/PresenceServer/__pycache__/main.cpython-314.pyc deleted file mode 100644 index 3eed7b0d62d82f41e3316575aa3b958c5ee36440..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 580 zcmYLGO-my|5Urk`Orr6NCJ(Cr{N zf-P`K1=fiqMU9P$u}&o|LY4f4xdBz0Rny7F4U$-;&PbBQXpZy|_As6CxSB+l#thfY zCmIeOztg zdQmjX!?t8xa7|MbD{3rg`HgmsZTGK~HHdVV$(~m4 I)~F}(A8d>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%T_-lKQ~oB zIX@>=KcFZ-D>b>KSl>A#u_U;%xFj_fD3)5BnwOj!oLW?tTBM&?P@o?lpP83g5+AQu iP58Yu%i59)h3Csje;1(HX*Wn%uyb*|f>mT$dTf+1-H``G2tV|zbaC$q@vunwEfgO30uijKhx zR%S(5V=rOB3D^zFXamTiIrzMl`KV?*HmnBT82s@e=YY+ZY{*-(= zk#lWHr|V{+SWYXl7^bl-K3C~08KN#eDGOZN(e%1ySTo!RQ1 z>Ec`@Ns0m`=Vs_~va{`BJ3_rg=HDkcfFC{m`>PEX82i;bu>Y))A=Jpi$n_&{w9#Q5 zA9@Flys<{7b#gE^dF0LfxkkWQ$(KJorGvtx*I-L42JYHWpo|-xIMvn(4zGe>xZq}dv&6BbZpoTB2 zRtui#tL~LVV(E43Z&3CUHg`4tRcyq@nuV6w_=^{lc%-JuwH@hkGN&$M>?hnl&t}=J U&+pHHUX6a}8vOF`z;BlS2feNXQvd(} diff --git a/PresenceServer/app/__pycache__/dependencies.cpython-314.pyc b/PresenceServer/app/__pycache__/dependencies.cpython-314.pyc deleted file mode 100644 index 5005d63d5de0a1909b4caeac1ae26ca32dc96b8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2082 zcmah~O>7fK6rS;}cOC!5grwmoadaiAfom$pd`cH{;JJ zOv$KB6}B`J$aJudOppbIEzg89VHO@h^Xd>f*<6-I=J61kkDSDffpM()dy%H}qH?T^ zS#(|=LYlhE8vt)d)7z;9<0uh&&Zj11Pn{+eVwUv6s z7$%_!pV!9&QdL%RsCCcaLFXwkiOnpd?0P}&ogxMmv4M;ExiqB?^`x73SOR+imoR48 zi*Avhxp{5`xFL?!_82rPD2J~5PJN7!31fZeJzT;XE`X;Yny=t%=}8~lL3++@FI3!h z422R_rFOzcRqm5qMqzhl!J$hAbNRl9y;QQ~ERkfmM)4i}PCxhDu%?kPxMe*wMKphlkrg>7 zFNinJ`ARq^$I&1vbhpA4WWxRW0E;>BTIh^)2w8YSvT#DV*MHurmd!zce(<(YwoG_{ z!CmivFP6{e-{d6ayexv(Q<|idyikMEdeJdq*d)xb%AQ&h{C0sQL8H6~+-9XE7l>26 zkqA)^1m$Q`KQvwsC%Jxd>@EH3Z0hP<=CU^PL3)~UK>31vVH)B_&?Rsxrr#pVUPpUb zPg*35c0fSFFP8TF%(+EuuV>d4bkfd2wPGxn9mDk0s!OPDnJz!YkwFmJ#kbiD>*>WR zrEpul8AD$Ok6_~`pgadc)x*8(;rMDezLMVPOKfx>SnnQN?H;RlChL3RkFM2Xqc2qX zkW!QPZw6KW@J3h9!{c8Z|N82;nf2kx)#1rsuC1r@tLc1g`r2C8`=6@y-u{R8KfnKI z;%RRJtWeiy@6@}F*1|{Yov(cw{c9t%_XWcK;d(S)3&b}iQ2%ic!C4-ROhxhcsc7mP zdU6(n{^VSADkS|Jl0YB*@4|2l=KX(R&?He1WEz2RFM3zEY(}VUl=%bDP8gg`V9I$5 z-5%%~l|XPty&Xa;CnN#Qar665F7(l6a?ZW!q&7 z+)X)k2g)3ji#}A~vxOAe$((H`Ys-faPwUC%N>CV~0E(25yp9VFy;jp)J0%KEX?>ao2~j7i&64A(yIz_|L(ef(9sy@iTP#DLVZOrJtexKhVH$ mu>)U*S0Y;qx&%L^nx;R!_+g{YA4U^rejNYd(r(I#J^lr6^T^x) diff --git a/PresenceServer/app/__pycache__/redis.cpython-314.pyc b/PresenceServer/app/__pycache__/redis.cpython-314.pyc deleted file mode 100644 index 6fc09fe771cdba90a9d679cc570c56e97e251768..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 672 zcmYLHPm9w)6n~R!(sXxQyNLE81b0OU!saB(B7*2)7es1SJh>Y}GHtUonKCn7>@BD# zFZu!e0{aQ{TgZYS3<`pH=uPQi@#cG}r4Q!!{>^*uH!r!>Zmk2#dH6a1i25fvOL6`i z^FA6C97DtoV4rE`lWiSX`?j`yIAT3-S+dgC;mGdQy;m`^B0E~UV=ZFZjhrq-ZWl%! z-G~}H5O_06oiXD?Jj+$UjHkHPc{xze(CK766&a5uS7T8su2P2A>5x!c8_)a(LIuy^ z*t+`$Aj8--c*=$>VlObWkdWaxYeqH3m0V9`DXAEzxP2juL@VmMZT7;UD0rBP5f6J( zobXhu@Zm7ghf}3_fibRlnesy}Pq_?}@i>&keRn)Hn{k|!rO=7yaV$5nAFWDVMyTKd z7~A?o@Zn0W<`{;QU@64zHJ;Q;$3Y*}{u*1Hm*0T;rmU ziQGcJ9!wu(hE2Y0bgIXH)f&358cpornbv}IqNZh<3rQ)nj*r<*McK~>lKuwc^`$7{ zi5!_`eVt5s2{ZKw*&%Diz`Iw7Y%=2aCDEsCs+$PEZN}Jl@PC2-!)v{3ziq#N`L!FI TcY{xlzIYER=fcIE)P4Q|Bm<8> diff --git a/PresenceServer/app/repos/__pycache__/__init__.cpython-314.pyc b/PresenceServer/app/repos/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 0fbea16ddc0764b9a3034fdd65ab5b5fb2bb67b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmdPqZkEGePuY5CH>>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%UM4oKQ~oB zIX@>=KcFZ-D>b>KSl>A#u_U;%xFj_fD3)5BnwOj!oLW?tTBM&?P@rFwT999?A0MBY omst`YuUAlci^C>2KczG$)vkyYXeP+kVi4mKGb1Bo5i^hl0Ns2jr~m)} diff --git a/PresenceServer/app/repos/__pycache__/presence.cpython-314.pyc b/PresenceServer/app/repos/__pycache__/presence.cpython-314.pyc deleted file mode 100644 index a7468d369ff2f68702ce15eb6402a809cc55226e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2032 zcmb7FOHUj}5bmCtee(Y7U>#X$lT{%OyAOCjVJoD>M=k`7;oVUCOwgI*&8)S+RNm21j?>ZoC2sON~Gog=9- zM>9Mid!_6#d?5R!>@@-nL=W!cb~<%E2Aebm2!6pF$4pO&Bn1n8NM86<_zt7M=ExWs zS32J(WD;~WWQ0yrgT}y;BSVQ5?g=+Bw1^5PdG=A~`Z9v?xH;*1I3DPFIdd{RJ)|qH zDjd%75V(c+w#8=>j==Nl-JZy_HNzrFE5#zi+`7Y(j)?S3C!Eo&aM%p!m|*E78)f`1 zw-B5wY`zRy*q!#p8)|+Hw*Oi^q8}Y>YvPW?*yV8KHEP{wDcS@<5JjO}X)5 zZ%%&*o+No38BB14_uxBB0jnor%nThafsLGSiG#fkGzdA_)5s)n2glL;VAN!Cdw& zW;dSKS31@^cRNNlJ4WX9?Vz!%89SPBBygj9dX#=i+qE@cl>U7QT?McIS3*U~5g-nCXKhxMpb z@)GbmgF0SDqCN=1e?dK(uL!`Dp2l>Xb`B6CQS~9JfK3@}IfV7kW=-J;UJ3IvFa=Ce zK&b|7G7c$ zu9kw7oCbN)Ogg+8_WCEJ5kAol43YNG0eIxdmz*zpKFuCTc^v>p-8a$4>f<-R3w--p z&gZYt6wH0Up3O0Ztk8J)%Ms*1NemDvlSCt$wfJn7L#BBazqk3u{JZs99MnUv~@491)apfRWs1HwYOOo z+VOy9_=*89Qx!#RX`(8!$gRYOd7M;zC#@*t^xxOFTq7QHFwDs+T`ZwG9KEJg*I^VO{ zyAa+gx&ZU7Q2&P3fAqVD6m>i)Zan%v)PE!{!D;tOyIbh}lJ4``XO$qW)9$eL)pH;{ z@|AYic^_2;QLgg>AJTnpvHT&mCPX%!G_7183Bs?W75e6Fb4oT<*%>)LJdS~_5?La- tsQp)GtjSD@y~;0x37@<`#{-p8`XdSdO2SXQ_>+0+haU6Hj|C@J{|S|ohZ_I@ diff --git a/PresenceServer/app/routers/__pycache__/__init__.cpython-314.pyc b/PresenceServer/app/routers/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index d18eb7fe86d3e76cbadac512bedda2b34447467a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168 zcmdPqZkEGePuY5CH>>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%T+%kKQ~oB zIX@>=KcFZ-D>b>KSl>A#u_U;%xFj_fD3)5BnwOj!oLW?tTBM&?P@rFwUs{q{RIDE# qpP83g5+AQuPMbD^h#PNa*RC6A0f~|P=FQA|Z)V=_ zH*Y-_2?r3guRi&?ta}mqQ4CrQ#_9#1=Vi378a@hv@5cl~XDOM_czpf8qh+8%CQXSV{GrPj7^>LBA5Utxt} ztwf3fco%%6fv&=DUqIbJSI~lT_9KK!Fn0vKftRp}=U~NYrZVRe4IxuCJsEWv-Ss{c zbGEN;tyXGQ$@a?R*tl>htWnu4QC>fUkdB^%`C;TkGlA1;8K*HM$@aUHV^oLe zX%Fp#j)FO&he6oB*188qqoboqIv}R?Ho$ZU#v;`$1>zwbcsGQ42DanFTk+vF-%jMv zdS5e=+V-cu^QZPz)H8D5pZbFdj}M-kz#Di>`!YCzZ)urpf`))q1hOxgSy%?fRQ_Me z&;)D@W zGxj8^F;QPyueu=dpvS=(n12hqOzEL!RbxUG=LeIaKY>v!Jpz|p3k~RpmrR#eTx>9_IjC$<5NK;J1h(Eq{UXN#d1xi z+>S#1oGi&NAAEPpgi%rWsZZGJVomx`zZl1yalOVSTRfD7$+@kdwA~|2SaFFgTOCHC zp2%!CFI!OF)|{ekdmtQ_bxN|?Rv{NM1$U7I(J5*E9F&`t3VDg1250fM*f$_{RgCci zH2OUn`~{r{`2d}}ht54f^(LzSpvTt7?!0wpW=o%HXiy0h|HlKj2iE2`SYx1x$M!TR zh3iwz`0@LZ#Aa{089DKrEc_}`#&;F*F^IK%-rO9W7EZaRIAx)DDlZDBtmD*wyMJwF fGd>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%T+%kKQ~oB zIX@>=KcFZ-D>b>KSl>A#u_U;%xFj_fD3)5BnwOj!oLW?tTBM&?P@rF&oRONFSgao( qpP83g5+AQuPEyZ*$(NF?QWTwns7ry z!ifZL_$Tzw;ij8-FrK(6ZH!0X+ij(grf_kRdHd#@nKy5~`Swlqrn?C=#lN`Il#m}d zXtqSdscnI?OV)`+m&p=U^bQ#!e@FY>g;t5v8pgO20t@@|Mg}iw+ad zREDLg#9N}0mJX4Puz!i$LTzwcS$w;~rE=ib1UohZI^L%C7|a6Qg-Gk#+#VqXKyQ;b zv`F)0mA=DHr*FZcMth=J^d9(=q^g}@exX^BTrjsFt6FGyu2i8emB?vfax)MmTZL)H z9M6`r;5v#iiJK;N!x#BtP~v$f@Ob{U2)4MRWd3>4R;xQw@e*KMa^K;rT)gKZZI?qHOSb>s^Oq6sAMv(MA*(2h5bLNUtF)x=& zlWU91a^OqeUMdga;7(F$N&_VWz81?QrwbD{hN*^3!ernhX*o^wAZ}~~fd_*$UMpfD z7D!A(KQ0-)nBTcq#pv=TnD|xG{U2Wb!Uz4{1Kw!@yqGe4_!Th(R*d477P7|>M1!$J z7EQ!5LRVxteJRU>i?(u#XIJ?zKczsW2&{CSDIIT@%sE=4_ZYxv5fvTSyN`>|L|e|- zL+Fa^WiDlJ=t9Dsgt`C+cM>WJ6uLI6wXbYIT_jnvS!i;4Xkhh<6f5pR_|EK3v`zLL zy%`81N5GubqR+R zqTTqY@i|y?LUSQ5c2C6v7~=mS=fM2bDW%^?ww|PP>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%U(YtKQ~oB zIX@>=KcFZ-D>b>KSl>A#u_U;%xFj_fD3)5BnwOj!oLW?tTBKi+S`3trkI&4@EQycT jE2zB1VUwGmQks)$SHuc54`gF8i1CS;k&&^88OQADfb>YlJp-SY9L{yQV#8*w~&C^AP&4Y>vg^xAs8ob-@NyB=FOYm z{AN#v>H`GYy)U1bCuBmh*zuZBRaSomWtx0Q(lkYE%AZ0~EDLQUDcN$H>rre4JVMHs zRBe^p#FRf7umj1U9prr}RhO){>$xtcLdmclPDbnq?<=W&$^G{JHj?%=5xe1vGJM=i zWBr*{n@Df9Yd7u^DP_4ku$BB-~=yNl|ptP zZyE*LslPCCDK*OUf>kOqdxkoqUMfLQ!&Sr9vSr2~NGn?g)6AUH@QK09@rq^^Y=af_ zymsBF;OH33aP%x)Ul_qsi}1f11))Q+$H=QRO`1qvEzvPdkZ#+WuQ5IXqK|fvHh5=* z93iJglg`kg83O6ad>#wunRd?iOcW=Lo@_C1^bE7&H6v?VJp&WEJyNl3V-jqJWfZc; zh`}K99^0_MpDh-~QHz%meGjoR1rA_=SQGegp;kKxtj^=Q#ygj%FD?bb zw=RSDqWkmiJMl%Sc|mGkvvBmAN83l3|y_2TUt0%%{MKk zr88CgIjRBiltoRbZ4FJ!8@Hw;j){CzDQuFAzuxM`UJ^D(wviWSJB+y8(!5!5Yz~0e z0R&y`X)h z_gu&5jXFGyr;uY#nK^!jToHv}_vo~E$4}ddmAbQ>%C;ZYouUuGpcd{gBJ`JV>)I;9 z<)$d_!bRIN<_BYsGWM-#Mj;1GSgBE)#r!y+4+WNkA)Xl4!jZFiLuWCGpJ;Xv?T64V z=vhv6UG44FYXU~hE&k0JRPo7hQs5j8W zS!piXiTYWJvQHUk^xqfgfE>Cn22c+PC?hI(cV?@>8e9EWhRWdP@Rq^L#?{tYgw$As z0;9Z$MZ`@k0=I6BMMPjAaRZBNirkY$YAokvM`|B2z#`%{77?!jwEi`VNF4C29VTIi zK@7!w>#$}=(acd?!!GLt8(dllMuv3EZ{V&fT*KvpUbZKUoL0qc45Kj$*@|CTC;GQz z^?ygAnm9^l12iG2vq2H{kdjd4*=P{;HkweR+4fG*=M;)kRT78&b0M187n%zPP(LW3 zY{7A2&2Z|=X5KanmQ(j;siM_-2eeX!f9U8IaI0+=3vp(A%1qmE{56x~^K1cl8N)T5 zIU!HQFGaKH?8keae|g1qv&a?q!$3wZn%Y1f(xh${T-u4imt?#~J*Hu;vkfEwK6f0x zgZLTb_{PmCyUYxC`;b%^?#|ZRK<%3>=E`}apPd0O-ltX(#Ii^!eMHD@@_;lxB*!0- z?k6Prh+KR~+Ex^iMwjb|5Lu*6^R(%AL8J#(MItmWqqfNtqMcO_Xv-ZN-chQa6#+Dc G*V8}sx_#>a diff --git a/PresenceServer/tests/__pycache__/test_presence.cpython-314-pytest-9.0.2.pyc b/PresenceServer/tests/__pycache__/test_presence.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index a48026708102bf69755cf5751e2519b99a66eaab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17740 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 -
HTTPS :433
HTTPS :433
Internet
Internet
AWS Cloud
AWS Cloud
x
Public subnet
Public subnet
Private subnet
Private subnet
10.0.1.0/24 - 10.0.2.0/24
10.0.1.0/24 - 10.0.2.0/24
10.0.3.0/24 - 10.0.4.0/24
10.0.3.0/24 - 10.0.4.0/24
Elastic IP
Elastic IP
Elastic Container Service
Elastic Container Service
ChatServer

:8080
ChatServer...
PresenceServer

:8000
PresenceServer...
ApiServer

:8000
ApiServer...
RDS

:5432
RDS...
PresenceServer Internal ALB
PresenceServer Inter...
HTTP /
Websocket :8080
JWT - Websockets
x-internal - HTTP
HTTP /...
ChatServer NLB
ChatServer NLB
HTTP :8000
ecs-tasks-sg
JWT
HTTP :8000...
ApiServer ALB
ApiServer ALB
Redis

:6379
Redis...
Redis Serialization
Protocol
:6379
elasticache-sg
TLS
Redis Serialization...
PostgreSQL :5432
rds-sg
TLS
PostgreSQL :5432...
HTTP :80
internal-alb-sg
x-internal
HTTP :80...
HTTP :80
x-internal
HTTP :80...
SQS calls
DynamoDB calls
ECR calls

HTTPS :433
SQS calls...
HTTP :8000
ecs-tasks-sg
HTTP :8000...
KMS
KMS
KMS
KMS
NAT Gateway
NAT Gateway
ECR calls

HTTPS :433
ECR calls...
VPC
VPC
HTTP :80
alb-sg
HTTP :80...
TCP :80
TCP :80
Internet Gateway
Internet Gateway
Secrets Manager
Secrets Manager
SQS API Endpoint
SQS API Endpoint
SQS
SQS
DynamoDB API Endpoint
DynamoDB API Endpoint
DynamoDB
DynamoDB
ECR
ECR
S3 (ALB logs, CloudTrail, Client)

S3 (ALB logs, CloudT...
CloudFront
CloudFront
AES-256
AES-256
AWS Account
AWS Account
CloudTrail
CloudTrail
10.0.0.0/16
10.0.0.0/16
VPC Flow Logs
VPC Flow Logs
CloudWatch
CloudWatch
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433

Network/Traffic Diagram

Network/Traffic Diagram

IAM/Permissions Diagram

IAM/Permissions Diagram
ECS TASK STARTUP (Execution Roles)
ECS TASK STARTUP (Execution Roles)
ApiServer
ApiServer
ChatServer
ChatServer
PresenceServer
PresenceServer
ecs-execution-api
ecs-execution-api
ecs-execution-chatserver
ecs-execution-chatse...
ecs-execution-presenceserver
ecs-execution-presen...
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
chatsystem/db
chatsystem/db
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
RUNTIME (Task Roles)
RUNTIME (Task Roles)
ChatServer
ChatServer
chatserver-task
chatserver-task
dynamodb: GetItem, PutItem, DeleteItem, UpdateItem, Query, DescribeTable, Scan
dynamodb: GetItem, PutItem, DeleteIt...
ServerRegistry
ServerRegistry
UserConnections
UserConnections
ConversationMembers
ConversationMembers
Messages
Messages
PendingMessages
PendingMessages
sqs: SendMessage, ReceiveMessage, DeleteMessage, GetQueue, CreateQueue, DeleteQueue
sqs: SendMessage, ReceiveMessage, De...
chat-server-* (wildcard)
chat-server-* (wildcard)
RESOURCE ACCESS POLICIES
RESOURCE ACCESS POLICIES
VPC Flow Logs
VPC Flow Logs
vpc-flow-logs
vpc-flow-logs
logs: CreateLogGroup, CreateLogStream, PutLogEvents, DescribeLogGroups, DescribeLogStream
logs: CreateLogGroup, CreateLogStrea...
*
*
client
client
cloudtrail
cloudtrail
alb-logs
alb-logs
S3 Bucket Policies
S3 Bucket Policies
cloudfront.amazonaws.com
cloudfront.amazonaws.com
cloudtrail.amazonaws.com
cloudtrail.amazonaws.com
ELB Service Account
ELB Service Account
delivery.logs.amazonaws.com
delivery.logs.amazonaws.com
s3: GetObject
s3: GetObject
bucket/*
bucket/*
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket
bucket
bucket/AWSLogs/{account_id}/*
bucket/AWSLogs/{account_id}/*
s3: PutObject
s3: PutObject
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket/*
bucket/*
bucket
bucket
bucket/*
bucket/*
Service
Service
Role
Role
Action
Action
Resource
Resource
Service
Service
Principal
Principal
Action
Action
Resource
Resource
Service
Service
Role
Role
Action
Action
Resource
Resource
ConversationMembers/index/*
ConversationMembers/index/*
Text is not SVG - cannot display
\ No newline at end of file +
HTTPS :433
HTTPS :433
Internet
Internet
AWS Cloud
AWS Cloud
x
Public subnet
Public subnet
Private subnet
Private subnet
10.0.1.0/24 - 10.0.2.0/24
10.0.1.0/24 - 10.0.2.0/24
10.0.3.0/24 - 10.0.4.0/24
10.0.3.0/24 - 10.0.4.0/24
Elastic IP
Elastic IP
Elastic Container Service
Elastic Container Service
ChatServer

:8080
ChatServer...
PresenceServer

:8000
PresenceServer...
ApiServer

:8000
ApiServer...
RDS

:5432
RDS...
PresenceServer Internal ALB
PresenceServer Inter...
HTTP /
Websocket :8080
JWT - Websockets
x-internal - HTTP
HTTP /...
ChatServer NLB
ChatServer NLB
HTTP :8000
ecs-tasks-sg
JWT
HTTP :8000...
ApiServer ALB
ApiServer ALB
Redis

:6379
Redis...
Redis Serialization
Protocol
:6379
elasticache-sg
TLS
Redis Serialization...
PostgreSQL :5432
rds-sg
TLS
PostgreSQL :5432...
HTTP :80
internal-alb-sg
x-internal
HTTP :80...
HTTP :80
x-internal
HTTP :80...
SQS calls
DynamoDB calls
ECR calls

HTTPS :433
SQS calls...
HTTP :8000
ecs-tasks-sg
HTTP :8000...
KMS
KMS
KMS
KMS
NAT Gateway
NAT Gateway
ECR calls
XRAY calls

HTTPS :433
ECR calls...
VPC
VPC
HTTP :80
alb-sg
HTTP :80...
TCP :80
TCP :80
Internet Gateway
Internet Gateway
Secrets Manager
Secrets Manager
SQS API Endpoint
SQS API Endpoint
SQS
SQS
DynamoDB API Endpoint
DynamoDB API Endpoint
DynamoDB
DynamoDB
ECR
ECR
S3 (ALB logs, CloudTrail, Client)

S3 (ALB logs, CloudT...
CloudFront
CloudFront
AES-256
AES-256
AWS Account
AWS Account
CloudTrail
CloudTrail
10.0.0.0/16
10.0.0.0/16
VPC Flow Logs
VPC Flow Logs
CloudWatch
CloudWatch
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433

Network/Traffic Diagram

Network/Traffic Diagram

IAM/Permissions Diagram

IAM/Permissions Diagram
ECS TASK STARTUP (Execution Roles)
ECS TASK STARTUP (Execution Roles)
ApiServer
ApiServer
ChatServer
ChatServer
PresenceServer
PresenceServer
ecs-execution-api
ecs-execution-api
ecs-execution-chatserver
ecs-execution-chatse...
ecs-execution-presenceserver
ecs-execution-presen...
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
chatsystem/db
chatsystem/db
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
RUNTIME (Task Roles)
RUNTIME (Task Roles)
RESOURCE ACCESS POLICIES
RESOURCE ACCESS POLICIES
VPC Flow Logs
VPC Flow Logs
vpc-flow-logs
vpc-flow-logs
logs: CreateLogGroup, CreateLogStream, PutLogEvents, DescribeLogGroups, DescribeLogStream
logs: CreateLogGroup, CreateLogStrea...
*
*
client
client
cloudtrail
cloudtrail
alb-logs
alb-logs
S3 Bucket Policies
S3 Bucket Policies
cloudfront.amazonaws.com
cloudfront.amazonaws.com
cloudtrail.amazonaws.com
cloudtrail.amazonaws.com
ELB Service Account
ELB Service Account
delivery.logs.amazonaws.com
delivery.logs.amazonaws.com
s3: GetObject
s3: GetObject
bucket/*
bucket/*
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket
bucket
bucket/AWSLogs/{account_id}/*
bucket/AWSLogs/{account_id}/*
s3: PutObject
s3: PutObject
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket/*
bucket/*
bucket
bucket
bucket/*
bucket/*
Role
Role
Action
Action
Resource
Resource
Service
Service
Principal
Principal
Action
Action
Resource
Resource
Service
Service
Role
Role
Action
Action
Resource
Resource
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
Service
Service
ChatServer
ChatServer
chatserver-task
chatserver-task
chatserver-xray
chatserver-xray
dynamodb: GetItem, PutItem, DeleteItem, UpdateItem, Query, DescribeTable, Scan
dynamodb: GetItem, PutItem, DeleteIt...
sqs: SendMessage, ReceiveMessage, DeleteMessage, GetQueue, CreateQueue, DeleteQueue
sqs: SendMessage, ReceiveMessage, De...
ServerRegistry
ServerRegistry
UserConnections
UserConnections
ConversationMembers
ConversationMembers
Messages
Messages
PendingMessages
PendingMessages
chat-server-* (wildcard)
chat-server-* (wildcard)
ConversationMembers/index/*
ConversationMembers/index/*
PresenceServer
PresenceServer
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
presenceserver-xray
presenceserver-xray
apiserver-xray
apiserver-xray
ApiServer
ApiServer
*
*
*
*
*
*
Text is not SVG - cannot display
\ No newline at end of file From 2a348ff2c96636e482fbab966cdb4032ea31ef0b Mon Sep 17 00:00:00 2001 From: Cole Michaels Date: Fri, 24 Apr 2026 22:36:42 +0900 Subject: [PATCH 4/6] ran kotlin format --- ChatServer/src/main/kotlin/di/AppModule.kt | 2 +- ChatServer/src/main/kotlin/plugins/XRay.kt | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ChatServer/src/main/kotlin/di/AppModule.kt b/ChatServer/src/main/kotlin/di/AppModule.kt index e10fb29..0899811 100644 --- a/ChatServer/src/main/kotlin/di/AppModule.kt +++ b/ChatServer/src/main/kotlin/di/AppModule.kt @@ -1,5 +1,6 @@ package org.chatserver.di +import com.amazonaws.xray.interceptors.TracingInterceptor import org.chatserver.data.registry.ConversationRegistry import org.chatserver.data.registry.ServerRegistry import org.chatserver.data.registry.UserRegistry @@ -12,7 +13,6 @@ import org.chatserver.services.sqs.SqsQueueManager import org.chatserver.session.SessionStore import org.koin.core.qualifier.named import org.koin.dsl.module -import com.amazonaws.xray.interceptors.TracingInterceptor import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration import software.amazon.awssdk.regions.Region diff --git a/ChatServer/src/main/kotlin/plugins/XRay.kt b/ChatServer/src/main/kotlin/plugins/XRay.kt index fcb45dd..e195a82 100644 --- a/ChatServer/src/main/kotlin/plugins/XRay.kt +++ b/ChatServer/src/main/kotlin/plugins/XRay.kt @@ -7,15 +7,16 @@ import io.ktor.server.application.install import io.ktor.server.request.httpMethod import io.ktor.server.request.path -val XRayPlugin = createApplicationPlugin("XRay") { - onCall { call -> - val segmentName = "${call.request.httpMethod.value} ${call.request.path()}" - AWSXRay.beginSegment(segmentName) +val XRayPlugin = + createApplicationPlugin("XRay") { + onCall { call -> + val segmentName = "${call.request.httpMethod.value} ${call.request.path()}" + AWSXRay.beginSegment(segmentName) + } + onCallRespond { _ -> + AWSXRay.endSegment() + } } - onCallRespond { _ -> - AWSXRay.endSegment() - } -} fun Application.configureXRay() { install(XRayPlugin) From 6fc362351b39ed8919b574f02b8b22e2dbb7e167 Mon Sep 17 00:00:00 2001 From: Cole Michaels Date: Sat, 25 Apr 2026 21:50:17 +0900 Subject: [PATCH 5/6] fixed issue with testing and sockets, need eager dependency inject not lazy. --- ChatServer/src/main/kotlin/plugins/Sockets.kt | 17 +++++++++-------- .../src/test/kotlin/plugins/SocketsTest.kt | 8 ++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ChatServer/src/main/kotlin/plugins/Sockets.kt b/ChatServer/src/main/kotlin/plugins/Sockets.kt index 74909e9..f7839ea 100644 --- a/ChatServer/src/main/kotlin/plugins/Sockets.kt +++ b/ChatServer/src/main/kotlin/plugins/Sockets.kt @@ -23,7 +23,7 @@ import org.chatserver.models.PresenceEvent import org.chatserver.models.SqsEnvelope import org.chatserver.routing.MessageRouter import org.chatserver.session.SessionStore -import org.koin.ktor.ext.inject +import org.koin.ktor.ext.getKoin import org.slf4j.LoggerFactory import software.amazon.awssdk.services.sqs.SqsClient @@ -32,13 +32,14 @@ private val logger = LoggerFactory.getLogger("Sockets") fun Application.configureSockets() { install(WebSockets) - val userRegistry by inject() - val conversationRegistry by inject() - val sessionStore by inject() - val messageRouter by inject() - val pendingMessageRepository by inject() - val serverRegistry by inject() - val sqsClient by inject() + val koin = getKoin() + val userRegistry = koin.get() + val conversationRegistry = koin.get() + val sessionStore = koin.get() + val messageRouter = koin.get() + val pendingMessageRepository = koin.get() + val serverRegistry = koin.get() + val sqsClient = koin.get() routing { authenticate("auth-jwt") { diff --git a/ChatServer/src/test/kotlin/plugins/SocketsTest.kt b/ChatServer/src/test/kotlin/plugins/SocketsTest.kt index d5392e3..e49480c 100644 --- a/ChatServer/src/test/kotlin/plugins/SocketsTest.kt +++ b/ChatServer/src/test/kotlin/plugins/SocketsTest.kt @@ -76,10 +76,10 @@ class SocketsTest { client.webSocket("/ws?token=${token("alice")}") { close() } } - verify { userRegistry.register("alice") } - verify { sessionStore.add(eq("alice"), any()) } - verify { userRegistry.deregister("alice") } - verify { sessionStore.remove("alice") } + verify(timeout = 2000) { userRegistry.register("alice") } + verify(timeout = 2000) { sessionStore.add(eq("alice"), any()) } + verify(timeout = 2000) { userRegistry.deregister("alice") } + verify(timeout = 2000) { sessionStore.remove("alice") } } @Test From 0cdb1d5410ea20e94bf8dd2afc7840df3bf079a1 Mon Sep 17 00:00:00 2001 From: Cole Michaels Date: Sat, 25 Apr 2026 21:51:18 +0900 Subject: [PATCH 6/6] added xray aws service to diagram. --- diagram.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diagram.svg b/diagram.svg index 6ba23ee..559faa1 100644 --- a/diagram.svg +++ b/diagram.svg @@ -1,4 +1,4 @@ -
HTTPS :433
HTTPS :433
Internet
Internet
AWS Cloud
AWS Cloud
x
Public subnet
Public subnet
Private subnet
Private subnet
10.0.1.0/24 - 10.0.2.0/24
10.0.1.0/24 - 10.0.2.0/24
10.0.3.0/24 - 10.0.4.0/24
10.0.3.0/24 - 10.0.4.0/24
Elastic IP
Elastic IP
Elastic Container Service
Elastic Container Service
ChatServer

:8080
ChatServer...
PresenceServer

:8000
PresenceServer...
ApiServer

:8000
ApiServer...
RDS

:5432
RDS...
PresenceServer Internal ALB
PresenceServer Inter...
HTTP /
Websocket :8080
JWT - Websockets
x-internal - HTTP
HTTP /...
ChatServer NLB
ChatServer NLB
HTTP :8000
ecs-tasks-sg
JWT
HTTP :8000...
ApiServer ALB
ApiServer ALB
Redis

:6379
Redis...
Redis Serialization
Protocol
:6379
elasticache-sg
TLS
Redis Serialization...
PostgreSQL :5432
rds-sg
TLS
PostgreSQL :5432...
HTTP :80
internal-alb-sg
x-internal
HTTP :80...
HTTP :80
x-internal
HTTP :80...
SQS calls
DynamoDB calls
ECR calls

HTTPS :433
SQS calls...
HTTP :8000
ecs-tasks-sg
HTTP :8000...
KMS
KMS
KMS
KMS
NAT Gateway
NAT Gateway
ECR calls
XRAY calls

HTTPS :433
ECR calls...
VPC
VPC
HTTP :80
alb-sg
HTTP :80...
TCP :80
TCP :80
Internet Gateway
Internet Gateway
Secrets Manager
Secrets Manager
SQS API Endpoint
SQS API Endpoint
SQS
SQS
DynamoDB API Endpoint
DynamoDB API Endpoint
DynamoDB
DynamoDB
ECR
ECR
S3 (ALB logs, CloudTrail, Client)

S3 (ALB logs, CloudT...
CloudFront
CloudFront
AES-256
AES-256
AWS Account
AWS Account
CloudTrail
CloudTrail
10.0.0.0/16
10.0.0.0/16
VPC Flow Logs
VPC Flow Logs
CloudWatch
CloudWatch
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433

Network/Traffic Diagram

Network/Traffic Diagram

IAM/Permissions Diagram

IAM/Permissions Diagram
ECS TASK STARTUP (Execution Roles)
ECS TASK STARTUP (Execution Roles)
ApiServer
ApiServer
ChatServer
ChatServer
PresenceServer
PresenceServer
ecs-execution-api
ecs-execution-api
ecs-execution-chatserver
ecs-execution-chatse...
ecs-execution-presenceserver
ecs-execution-presen...
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
chatsystem/db
chatsystem/db
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
RUNTIME (Task Roles)
RUNTIME (Task Roles)
RESOURCE ACCESS POLICIES
RESOURCE ACCESS POLICIES
VPC Flow Logs
VPC Flow Logs
vpc-flow-logs
vpc-flow-logs
logs: CreateLogGroup, CreateLogStream, PutLogEvents, DescribeLogGroups, DescribeLogStream
logs: CreateLogGroup, CreateLogStrea...
*
*
client
client
cloudtrail
cloudtrail
alb-logs
alb-logs
S3 Bucket Policies
S3 Bucket Policies
cloudfront.amazonaws.com
cloudfront.amazonaws.com
cloudtrail.amazonaws.com
cloudtrail.amazonaws.com
ELB Service Account
ELB Service Account
delivery.logs.amazonaws.com
delivery.logs.amazonaws.com
s3: GetObject
s3: GetObject
bucket/*
bucket/*
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket
bucket
bucket/AWSLogs/{account_id}/*
bucket/AWSLogs/{account_id}/*
s3: PutObject
s3: PutObject
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket/*
bucket/*
bucket
bucket
bucket/*
bucket/*
Role
Role
Action
Action
Resource
Resource
Service
Service
Principal
Principal
Action
Action
Resource
Resource
Service
Service
Role
Role
Action
Action
Resource
Resource
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
Service
Service
ChatServer
ChatServer
chatserver-task
chatserver-task
chatserver-xray
chatserver-xray
dynamodb: GetItem, PutItem, DeleteItem, UpdateItem, Query, DescribeTable, Scan
dynamodb: GetItem, PutItem, DeleteIt...
sqs: SendMessage, ReceiveMessage, DeleteMessage, GetQueue, CreateQueue, DeleteQueue
sqs: SendMessage, ReceiveMessage, De...
ServerRegistry
ServerRegistry
UserConnections
UserConnections
ConversationMembers
ConversationMembers
Messages
Messages
PendingMessages
PendingMessages
chat-server-* (wildcard)
chat-server-* (wildcard)
ConversationMembers/index/*
ConversationMembers/index/*
PresenceServer
PresenceServer
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
presenceserver-xray
presenceserver-xray
apiserver-xray
apiserver-xray
ApiServer
ApiServer
*
*
*
*
*
*
Text is not SVG - cannot display
\ No newline at end of file +
HTTPS :433
HTTPS :433
Internet
Internet
AWS Cloud
AWS Cloud
x
Public subnet
Public subnet
Private subnet
Private subnet
10.0.1.0/24 - 10.0.2.0/24
10.0.1.0/24 - 10.0.2.0/24
10.0.3.0/24 - 10.0.4.0/24
10.0.3.0/24 - 10.0.4.0/24
Elastic IP
Elastic IP
Elastic Container Service
Elastic Container Service
ChatServer

:8080
ChatServer...
PresenceServer

:8000
PresenceServer...
ApiServer

:8000
ApiServer...
RDS

:5432
RDS...
PresenceServer Internal ALB
PresenceServer Inter...
HTTP /
Websocket :8080
JWT - Websockets
x-internal - HTTP
HTTP /...
ChatServer NLB
ChatServer NLB
HTTP :8000
ecs-tasks-sg
JWT
HTTP :8000...
ApiServer ALB
ApiServer ALB
Redis

:6379
Redis...
Redis Serialization
Protocol
:6379
elasticache-sg
TLS
Redis Serialization...
PostgreSQL :5432
rds-sg
TLS
PostgreSQL :5432...
HTTP :80
internal-alb-sg
x-internal
HTTP :80...
HTTP :80
x-internal
HTTP :80...
SQS calls
DynamoDB calls
ECR calls

HTTPS :433
SQS calls...
HTTP :8000
ecs-tasks-sg
HTTP :8000...
KMS
KMS
KMS
KMS
NAT Gateway
NAT Gateway
ECR calls
XRAY calls

HTTPS :433
ECR calls...
VPC
VPC
HTTP :80
alb-sg
HTTP :80...
TCP :80
TCP :80
Internet Gateway
Internet Gateway
Secrets Manager
Secrets Manager
SQS API Endpoint
SQS API Endpoint
SQS
SQS
DynamoDB API Endpoint
DynamoDB API Endpoint
DynamoDB
DynamoDB
ECR
ECR
S3 (ALB logs, CloudTrail, Client)

S3 (ALB logs, CloudT...
CloudFront
CloudFront
AES-256
AES-256
AWS Account
AWS Account
CloudTrail
CloudTrail
10.0.0.0/16
10.0.0.0/16
VPC Flow Logs
VPC Flow Logs
CloudWatch
CloudWatch
HTTPS :433
HTTPS :433
HTTPS :433
HTTPS :433
X-Ray
X-Ray
HTTPS :433
HTTPS :433

Network/Traffic Diagram

Network/Traffic Diagram

IAM/Permissions Diagram

IAM/Permissions Diagram
ECS TASK STARTUP (Execution Roles)
ECS TASK STARTUP (Execution Roles)
ApiServer
ApiServer
ChatServer
ChatServer
PresenceServer
PresenceServer
ecs-execution-api
ecs-execution-api
ecs-execution-chatserver
ecs-execution-chatse...
ecs-execution-presenceserver
ecs-execution-presen...
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
secretsmanager:GetSecretValue
chatsystem/db
chatsystem/db
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
chatsystem/jwt_secret
chatsystem/jwt_secret
chatsystem/internal_api_key
chatsystem/internal_api_key
RUNTIME (Task Roles)
RUNTIME (Task Roles)
RESOURCE ACCESS POLICIES
RESOURCE ACCESS POLICIES
VPC Flow Logs
VPC Flow Logs
vpc-flow-logs
vpc-flow-logs
logs: CreateLogGroup, CreateLogStream, PutLogEvents, DescribeLogGroups, DescribeLogStream
logs: CreateLogGroup, CreateLogStrea...
*
*
client
client
cloudtrail
cloudtrail
alb-logs
alb-logs
S3 Bucket Policies
S3 Bucket Policies
cloudfront.amazonaws.com
cloudfront.amazonaws.com
cloudtrail.amazonaws.com
cloudtrail.amazonaws.com
ELB Service Account
ELB Service Account
delivery.logs.amazonaws.com
delivery.logs.amazonaws.com
s3: GetObject
s3: GetObject
bucket/*
bucket/*
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket
bucket
bucket/AWSLogs/{account_id}/*
bucket/AWSLogs/{account_id}/*
s3: PutObject
s3: PutObject
s3: GetBucketAcl
s3: GetBucketAcl
s3: PutObject
s3: PutObject
bucket/*
bucket/*
bucket
bucket
bucket/*
bucket/*
Role
Role
Action
Action
Resource
Resource
Service
Service
Principal
Principal
Action
Action
Resource
Resource
Service
Service
Role
Role
Action
Action
Resource
Resource
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
Service
Service
ChatServer
ChatServer
chatserver-task
chatserver-task
chatserver-xray
chatserver-xray
dynamodb: GetItem, PutItem, DeleteItem, UpdateItem, Query, DescribeTable, Scan
dynamodb: GetItem, PutItem, DeleteIt...
sqs: SendMessage, ReceiveMessage, DeleteMessage, GetQueue, CreateQueue, DeleteQueue
sqs: SendMessage, ReceiveMessage, De...
ServerRegistry
ServerRegistry
UserConnections
UserConnections
ConversationMembers
ConversationMembers
Messages
Messages
PendingMessages
PendingMessages
chat-server-* (wildcard)
chat-server-* (wildcard)
ConversationMembers/index/*
ConversationMembers/index/*
PresenceServer
PresenceServer
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
xray: PutTraceSegments, PutTelemetryRecords, GetSamplingRules, GetSamplingTargets, GetSamplingStatisticSummaries
xray: PutTraceSegments, PutTelemetry...
presenceserver-xray
presenceserver-xray
apiserver-xray
apiserver-xray
ApiServer
ApiServer
*
*
*
*
*
*
Text is not SVG - cannot display
\ No newline at end of file