A working demo was only the beginning
The first version of LiveCap could capture microphone audio, send it to Amazon Transcribe, and show captions in a browser. That proved the core interaction. It did not prove that the product could be operated safely or explained honestly.
Production work began when the questions changed:
- What happens when the WebSocket disconnects?
- Where can traffic enter the system?
- What data is retained?
- How does the service behave while idle?
- What can the system recover automatically, and what will a user lose?
Those questions affected the interface as much as the infrastructure.
Privacy became an architecture constraint
LiveCap sends 16 kHz PCM audio from the browser to the backend while a session is active. Raw audio is not stored. Only finalized transcript text can be exported to a private S3 bucket through a time-limited download URL.
That boundary simplifies the data lifecycle and makes the privacy promise understandable: audio exists only for live processing, while users choose whether to export text.
It also changes debugging. I cannot rely on saved audio to reproduce every transcription problem, so session state, errors, reconnect behavior, and CloudWatch logs need to provide enough evidence without retaining the sensitive input.
One public entrypoint made the system easier to reason about
CloudFront is the browser-facing entrypoint. It serves the private S3 frontend and routes API, WebSocket, and wake requests to their correct origins. The ALB accepts application traffic from the CloudFront origin-facing path, and the Fargate task remains in private subnets without a public IP.
This structure is more complex than exposing an EC2 port, but every boundary has a purpose:
- CloudFront and WAF control public traffic.
- The ALB provides health-aware routing to the backend.
- ECS replaces failed tasks.
- IAM roles provide AWS access without credentials in the application image.
- Private S3 buckets hold the frontend and finalized transcript exports.
The architecture diagram matters because it shows the request path and trust boundaries. A list of AWS services does not.
Scale-to-zero is a product decision
The backend scales down after five idle minutes. This reduces idle Fargate cost, but the first session after that can wait 30-60 seconds for a task to start and pass its health check.
Hiding that delay would make the product feel broken. LiveCap instead exposes a Starting backend state and polls health for a bounded period. The interface teaches the user what the infrastructure is doing.
This is the trade-off I would carry into another system: cost controls need a user experience. An infrastructure optimization is incomplete if the interface cannot explain its effect.
Reliability needs precise boundaries
The client sends heartbeats and uses bounded reconnect attempts. ECS can replace a failed task. CI verifies backend, frontend, Terraform, and secret hygiene.
But the system does not claim active-active availability. It runs at a maximum of one task because active WebSocket sessions are process-local. If the task disappears, ECS restores the service, but the in-flight session is lost.
Writing that limitation down is part of engineering. It tells the next person where the architecture must change before horizontal scaling is safe.
What changed in my definition of “done”
A deployed URL is evidence, but it is not the finish line. For LiveCap, “done enough to show” now means:
- The product path works from browser capture to transcript download.
- Network and IAM boundaries match the architecture diagram.
- Tests and CI cover the backend, frontend, Terraform, and secret scanning.
- The interface explains cold starts and failure states.
- Documentation states the remaining cost and availability boundaries.
The most useful lesson was not a particular AWS service. It was learning to connect a product promise to infrastructure behavior and then prove where that promise holds.