You're a new engineer on the Hummingbird team. It's your first week. The senior engineer is on
vacation. Support tickets are coming in. You have Claude Code, a terminal, and curl.
| What | How to access |
|---|---|
| Source code | Which you cloned in your current directory |
| CloudWatch logs | aws logs tail /ecs/hummingbird/production/api --follow |
| Claude Code | export ANTHROPIC_MODEL='us.anthropic.claude-opus-4-6-v1' then claude |
Start here — confirm the API is up:
curl http://<alb-dns>/healthYou should see
{"status":"ok","service":"hummingbird"}.
Before touching any bug, open Claude Code and ask:
Give me a high-level walkthrough of this codebase.
What is the full lifecycle of an uploaded image — from POST /upload to GET /download?
Which file and function handles each step?
"A teammate forgot
APP_PORTin their.envfile. The server started — no crash, no error — but it wasn't on port 9000. The log saidlistening on port undefined."
Investigate with Claude Code:
In server.js, how is the port determined?
What happens in Node.js when you call app.listen(undefined)?
Is there any fallback or guard?
Fix accepted when: server.js uses process.env.APP_PORT || 9000.
"I upload with
?width=800. I callGET /v1/media/:idstraight after. The response hassize,name,status— but nowidthanywhere."
Reproduce it:
curl -X POST "http://<alb-dns>/v1/media/upload?width=800" -F "file=@sample.jpg"
curl http://<alb-dns>/v1/media/<mediaId>Investigate with Claude Code:
In clients/dynamodb.js, what fields does createMedia save to DynamoDB?
Now look at what getMedia returns. Are all the same fields present?
Fix accepted when: getMedia return object includes width: Number(Item.width.N).
"I try to download while the image is still processing. I get a
202— fine. But theLocationheader says:Location: hummingbird-alb-xxx.elb.amazonaws.com/v1/media/abc/statusNo
http://. My client can't follow it."
Reproduce it:
curl -X POST "http://<alb-dns>/v1/media/upload?width=500" -F "file=@sample.jpg"
curl -i http://<alb-dns>/v1/media/<mediaId>/downloadLook at the Location header in the output.
Investigate with Claude Code:
In the downloadController in controllers/media.js, show me how the Location header is built.
What does req.hostname return vs req.get('host') in Express?
What does a valid Location header look like for a 3xx response?
Fix accepted when: Location value starts with http:// and includes the host and port.
"
GET /statussaysCOMPLETE.GET /downloadstill returns202. Every time. Forever."
Reproduce it:
curl -X POST "http://<alb-dns>/v1/media/upload?width=500" -F "file=@sample.jpg"
curl -X PUT "http://<alb-dns>/v1/media/<mediaId>/resize?width=500"
curl http://<alb-dns>/v1/media/<mediaId>/status
curl -i http://<alb-dns>/v1/media/<mediaId>/downloadCheck CloudWatch — the downloadController logs the currentStatus on every 202:
aws logs tail /ecs/hummingbird/production/api --followInvestigate with Claude Code:
In the downloadController in controllers/media.js, what condition decides
whether to return a 202 vs a 302?
Is that comparison correct given that COMPLETE status should trigger the redirect?
Fix accepted when: The condition checks media.status !== MEDIA_STATUS.COMPLETE.
"
PUT /resizeresponds{ status: 'COMPLETE' }.GET /statussaysPENDING. Resize again — stillPENDING. Zero errors in the logs. The resize appears to work every time."
Tail logs while triggering a resize:
aws logs tail /ecs/hummingbird/production/api --follow &
curl -X PUT "http://<alb-dns>/v1/media/<mediaId>/resize?width=500"Look at all three DynamoDB log lines carefully. Pay attention to every field.
Investigate with Claude Code:
Compare the DynamoDB key used in createMedia, getMedia, and setMediaStatus
in clients/dynamodb.js. Are all three targeting the exact same item?
Then ask:
What does DynamoDB do when UpdateItem is called on a key that doesn't exist
and there is no ConditionExpression?
Fix accepted when: setMediaStatus uses SK: { S: 'METADATA' } — matching the casing in
createMedia and getMedia.