@@ -13,12 +13,15 @@ provider:
1313 JAILDATA_TABLE : !Ref JailDataTable
1414 ERROR_CACHE_TABLE : !Ref ErrorCacheTable
1515 SERVICE_NAME : ${self:service}
16+ AWS_ACCOUNT_ID : !Ref "AWS::AccountId"
17+ BATCH_PROCESSING_QUEUE_URL : !Ref BatchProcessingQueue
1618 iam :
1719 role :
1820 statements :
1921 - Effect : Allow
2022 Action :
2123 - dynamodb:BatchGetItem
24+ - dynamodb:BatchWriteItem
2225 - dynamodb:GetItem
2326 - dynamodb:PutItem
2427 - dynamodb:Query
@@ -53,6 +56,16 @@ provider:
5356 Resource :
5457 - !Ref AlertTopic
5558
59+ - Effect : Allow
60+ Action :
61+ - sqs:SendMessage
62+ - sqs:ReceiveMessage
63+ - sqs:DeleteMessage
64+ - sqs:GetQueueAttributes
65+ Resource :
66+ - !GetAtt BatchProcessingQueue.Arn
67+ - !GetAtt BatchProcessingDeadLetterQueue.Arn
68+
5669 apiGateway :
5770 disableDefaultEndpoint : true
5871 apiKeys :
@@ -124,40 +137,32 @@ resources:
124137 TopicArn : !Ref AlertTopic
125138 Endpoint : ${ssm:/jaildata/alert-email}
126139
127- # DynamoDB table for jail data
140+ # DynamoDB table for jail data (single table design)
128141 JailDataTable :
129142 Type : AWS::DynamoDB::Table
130143 Properties :
131144 TableName : jaildata-${self:provider.stage}
132145 BillingMode : PAY_PER_REQUEST
133146 AttributeDefinitions :
134- - AttributeName : detaineeId
147+ - AttributeName : PK
135148 AttributeType : S
136- - AttributeName : timestamp
149+ - AttributeName : SK
137150 AttributeType : S
138- - AttributeName : status
151+ - AttributeName : GSI1PK
139152 AttributeType : S
140- - AttributeName : createdDate
153+ - AttributeName : GSI1SK
141154 AttributeType : S
142155 KeySchema :
143- - AttributeName : detaineeId
156+ - AttributeName : PK
144157 KeyType : HASH
145- - AttributeName : timestamp
158+ - AttributeName : SK
146159 KeyType : RANGE
147160 GlobalSecondaryIndexes :
148- - IndexName : StatusCreatedDateIndex
149- KeySchema :
150- - AttributeName : status
151- KeyType : HASH
152- - AttributeName : createdDate
153- KeyType : RANGE
154- Projection :
155- ProjectionType : ALL
156- - IndexName : CreatedDateTimestampIndex
161+ - IndexName : GSI1
157162 KeySchema :
158- - AttributeName : createdDate
163+ - AttributeName : GSI1PK
159164 KeyType : HASH
160- - AttributeName : timestamp
165+ - AttributeName : GSI1SK
161166 KeyType : RANGE
162167 Projection :
163168 ProjectionType : ALL
@@ -169,6 +174,38 @@ resources:
169174 - Key : Service
170175 Value : JailData
171176
177+ # SQS queue for batch processing (handles inmate data batches)
178+ BatchProcessingQueue :
179+ Type : AWS::SQS::Queue
180+ Properties :
181+ QueueName : jaildata-batch-processing-${self:provider.stage}
182+ VisibilityTimeoutSeconds : 300
183+ MessageRetentionPeriod : 1209600 # 14 days
184+ RedrivePolicy :
185+ deadLetterTargetArn : !GetAtt BatchProcessingDeadLetterQueue.Arn
186+ maxReceiveCount : 3
187+ Tags :
188+ - Key : Name
189+ Value : JailData Batch Processing Queue
190+ - Key : Environment
191+ Value : ${self:provider.stage}
192+ - Key : Service
193+ Value : JailData
194+
195+ # Dead letter queue for batch processing
196+ BatchProcessingDeadLetterQueue :
197+ Type : AWS::SQS::Queue
198+ Properties :
199+ QueueName : jaildata-batch-processing-dlq-${self:provider.stage}
200+ MessageRetentionPeriod : 1209600 # 14 days
201+ Tags :
202+ - Key : Name
203+ Value : JailData Batch Processing Dead Letter Queue
204+ - Key : Environment
205+ Value : ${self:provider.stage}
206+ - Key : Service
207+ Value : JailData
208+
172209 # DynamoDB table for error cache and deduplication
173210 ErrorCacheTable :
174211 Type : AWS::DynamoDB::Table
@@ -213,37 +250,151 @@ resources:
213250 Name : ${self:service}-${self:provider.stage}-CommunityUsagePlanId
214251
215252functions :
216- # Scheduled data collection function
217- dataCollection :
218- handler : handlers/data-collection.execute
253+ # Manual data collection trigger
254+ dataCollectionManual :
255+ handler : handlers/data-collection.collect
256+ memorySize : 1024
257+ timeout : 600 # 10 minutes
258+ events :
259+ - http :
260+ path : /collect/{facilityId}
261+ method : post
262+ private : true
263+
264+ # Scheduled data collection functions for different facilities
265+ # To add a new facility: copy a function, change the name, set the facility ID in the input, and pick a unique schedule
266+
267+ # Wake County - 10:00 AM UTC daily
268+ dataCollectionWake :
269+ handler : handlers/data-collection.collectScheduled
219270 memorySize : 1024
220271 timeout : 600 # 10 minutes
221272 events :
222- # Default collection at 10 AM UTC
223273 - schedule :
224274 rate : cron(0 10 * * ? *)
225- input : ' {"countyId": "wake", "source": "wake-county"}'
226- # Additional configurable collections can be added here
227- # Example: 10:30 AM UTC for Mecklenburg County
228- # - schedule:
229- # rate: cron(30 10 * * ? *)
230- # input: '{"countyId": "mecklenburg", "source": "mecklenburg-county"}'
231-
232- # Get detainee data
233- getDetainee :
234- handler : handlers/detainee.get
275+ enabled : true
276+ name : jaildata-collection-wake-${self:provider.stage}
277+ description : " Daily Wake County jail data collection"
278+ input : ' {"facilityId": "wake"}'
279+
280+ # Buncombe County - 10:15 AM UTC daily
281+ dataCollectionBuncombe :
282+ handler : handlers/data-collection.collectScheduled
283+ memorySize : 1024
284+ timeout : 600 # 10 minutes
285+ events :
286+ - schedule :
287+ rate : cron(15 10 * * ? *)
288+ enabled : true
289+ name : jaildata-collection-buncombe-${self:provider.stage}
290+ description : " Daily Buncombe County jail data collection"
291+ input : ' {"facilityId": "buncombe"}'
292+
293+ # DISABLED: Mecklenburg County - Need API ID (currently 0)
294+ dataCollectionMecklenburg :
295+ handler : handlers/data-collection.collectScheduled
296+ memorySize : 1024
297+ timeout : 600 # 10 minutes
298+ events :
299+ - schedule :
300+ rate : cron(30 10 * * ? *)
301+ enabled : false # DISABLED: Need API ID
302+ name : jaildata-collection-mecklenburg-${self:provider.stage}
303+ description : " Daily Mecklenburg County jail data collection"
304+ input : ' {"facilityId": "mecklenburg"}'
305+
306+ # DISABLED: Durham County - Need API ID (currently 0)
307+ dataCollectionDurham :
308+ handler : handlers/data-collection.collectScheduled
309+ memorySize : 1024
310+ timeout : 600 # 10 minutes
311+ events :
312+ - schedule :
313+ rate : cron(0 11 * * ? *)
314+ enabled : false # DISABLED: Need API ID
315+ name : jaildata-collection-durham-${self:provider.stage}
316+ description : " Daily Durham County jail data collection"
317+ input : ' {"facilityId": "durham"}'
318+
319+ # DISABLED: Orange County - Need API ID (currently 0)
320+ dataCollectionOrange :
321+ handler : handlers/data-collection.collectScheduled
322+ memorySize : 1024
323+ timeout : 600 # 10 minutes
324+ events :
325+ - schedule :
326+ rate : cron(30 11 * * ? *)
327+ enabled : false # DISABLED: Need API ID
328+ name : jaildata-collection-orange-${self:provider.stage}
329+ description : " Daily Orange County jail data collection"
330+ input : ' {"facilityId": "orange"}'
331+
332+ # DISABLED: Guilford County - Need API ID (currently 0)
333+ dataCollectionGuilford :
334+ handler : handlers/data-collection.collectScheduled
335+ memorySize : 1024
336+ timeout : 600 # 10 minutes
337+ events :
338+ - schedule :
339+ rate : cron(0 12 * * ? *)
340+ enabled : false # DISABLED: Need API ID
341+ name : jaildata-collection-guilford-${self:provider.stage}
342+ description : " Daily Guilford County jail data collection"
343+ input : ' {"facilityId": "guilford"}'
344+
345+ # Batch processing function (triggered by SQS)
346+ batchProcessing :
347+ handler : handlers/batch-processing.processBatch
348+ memorySize : 512
349+ timeout : 300 # 5 minutes
350+ events :
351+ - sqs :
352+ arn : !GetAtt BatchProcessingQueue.Arn
353+ batchSize : 10
354+ maximumBatchingWindowInSeconds : 30
355+
356+ # Get inmates by facility (with status filter)
357+ getInmatesByFacility :
358+ handler : handlers/detainee.getInmatesByFacility
359+ events :
360+ - http :
361+ path : inmates/{facilityId}
362+ method : get
363+ private : true
364+
365+ # Get all active inmates across facilities
366+ getAllActiveInmates :
367+ handler : handlers/detainee.getAllActiveInmates
368+ events :
369+ - http :
370+ path : inmates/active
371+ method : get
372+ private : true
373+
374+ # Search inmates by last name within a facility
375+ searchInmatesByName :
376+ handler : handlers/detainee.searchInmatesByName
377+ events :
378+ - http :
379+ path : inmates/{facilityId}/search
380+ method : get
381+ private : true
382+
383+ # Get specific inmate record
384+ getSpecificInmate :
385+ handler : handlers/detainee.getSpecificInmate
235386 events :
236387 - http :
237- path : detainee/{detaineeId }
388+ path : inmates/{facilityId}/{lastName}/{firstName}/{recordDate }
238389 method : get
239390 private : true
240391
241- # List active detainees
242- listActiveDetainees :
243- handler : handlers/detainee.listActive
392+ # Get specific inmate record with middle name
393+ getSpecificInmateWithMiddle :
394+ handler : handlers/detainee.getSpecificInmate
244395 events :
245396 - http :
246- path : detainees/active
397+ path : inmates/{facilityId}/{lastName}/{firstName}/{middleName}/{recordDate}
247398 method : get
248399 private : true
249400
0 commit comments