Adding deployment logs and a logs handler

This time I started thinking less about deployment status, and more about deployment output…

When I run docker pull nginx:latest, the command does not just return one final result. It prints many lines along the way (see image below), and I wanted those lines to be stored one by one instead of disappearing in the terminal. In my example, the command produced around 11 lines of output, so that felt like a good reminder that deployment progress is not just one state change.

docker pull nginx:latest output

That is why I added a deployment_logs table inside migrate(). The goal was to track deployment output per line, so later the frontend can read what actually happened during a deployment, not just whether the final status was success or failed.

I also added an index because I expect this logs table could grow very large over time… maybe even into millions of rows. If I already know retrieval will depend on deployment_id and time order, it makes sense to shape the table that way from the start.

In the same commit, I added two functions in api/db/deployments.go: AppendLog for inserting log lines and GetLogsAfter for reading logs after a certain timestamp. Then I started using AppendLog inside the job flow, so different execution paths can leave a visible trail in the database instead of failing silently.

After that, I created LogsHandler so the backend can expose those logs through an endpoint, and then registered that handler in main.go. The handler returns the current deployment status, the fetched log rows, and next_after so the frontend knows where to continue from.

One detail worth mentioning is that I used time.RFC3339Nano for parsing and formatting the after parameter. Since deployment logs can be inserted very quickly one after another, using regular second-level precision would not be enough to distinguish between them. RFC3339Nano gives nanosecond precision, which makes sure the frontend can always pick up exactly where it left off without missing or duplicating any log lines.

One thing I noticed here is that this still is not real streaming yet… to get more logs, the frontend has to hit the handler repeatedly with an interval. So for now the shape is closer to polling, but it already feels like an important step because I finally have a basic path for showing deployment logs in the UI.

© 2026 Wahyu Syahputra. All rights reserved.