From One Local Stack to Three Training Profiles

Mar 29, 2026

Testing#Testing#Docker#Workshops#AI

In March 2025, I introduced a Docker-based local testing stack built for learning, experimentation, and hands-on practice. The goal was simple: give testers something more realistic than a toy demo, but still practical enough to run locally without a painful setup.

Since then, the more important change was not extra infrastructure, but clearer runtime intent. What started as one environment gradually became three profiles with different purposes: lightweight for low-friction workshops, full for more realistic system-level exercises, and server for public, shared access.

What It Evolved Into

Lightweight Profile

The lightweight profile is the default for everyday training work. It keeps the application flow intact, but strips the environment back to the parts that matter most in workshops: frontend, backend, an LLM mock service, and a gateway that exposes everything through a single URL.

flowchart LR
    U[Browser]
    G[Gateway<br/>localhost:8081<br/>serves frontend + /images]
    F[Frontend]
    B[Backend]
    O[Ollama Mock<br/>localhost:11434]

    U --> G
    G --> F
    G --> B
    B --> O

This profile exists to remove the wrong kind of complexity. In AI workshops, Playwright workshops, and most hands-on exercises, fast startup and predictable behaviour matter more than simulating every infrastructure dependency. The LLM mock service is a good example of that choice: it preserves the application path without external dependencies, variable responses, extra cost, or avoidable classroom instability.

Use the lightweight profile when the environment should stay out of the way and let people focus on the application, the tests, and the ideas being taught.

Full Profile

The full profile exists for different reasons. This is the version to use when the stack needs to behave less like a tidy workshop app and more like a distributed system with real moving parts. It adds PostgreSQL, ActiveMQ, Mailhog, an email consumer service, Prometheus, Grafana, InfluxDB, and a real Ollama integration.

flowchart LR
    U[Browser]
    G[Gateway<br/>localhost:8081<br/>serves frontend + /images]
    F[Frontend]
    B[Backend]
    DB[(Postgres<br/>localhost:5432)]
    MQ[ActiveMQ<br/>localhost:8161 and 61616]
    C[Consumer<br/>localhost:4002]
    M[Mailhog<br/>localhost:8025]
    O[Ollama<br/>localhost:11434]
    P[Prometheus<br/>localhost:9090]
    GR[Grafana<br/>localhost:3000]
    I[InfluxDB<br/>localhost:8086]

    U --> G
    G --> F
    G --> B
    B --> DB
    B --> MQ
    MQ --> C
    C --> M
    B --> O
    P --> B
    P --> C
    GR --> P
    GR --> I

This profile is better suited to performance testing workshops, load testing, CI-oriented runs, asynchronous flow validation, and broader integration exercises. It is also where real LLM integration becomes useful, especially when the goal is to evaluate smaller open-source models in an application context rather than just call them in isolation.

Once messaging, persistence, observability, and a real model are involved, the system starts to expose the kinds of behaviour testers actually need to reason about: delayed effects, queue-backed workflows, state changes, resource bottlenecks, and telemetry that helps explain what happened. Use the full profile when realism is part of the lesson.

From there, the next step became possible: putting the stack online as a public shared environment. But that only made sense after the stack had already become clearer about local runtime intent. The public server is not a replacement for lightweight or full. It is the next profile in the same line of thinking.

Server Profile

Once the stack had split into lightweight and full, the next step was no longer about adding another local mode. It was about making the environment available in a way that supported more than a single machine or a single workshop session.

That is where awesome.byst.re comes in.

The public-facing release is not a hosted copy of the full local stack with every service left open. It is a separate server profile designed for shared use. The aim is to make the application available for demos, guided exercises, self-learning, and exploratory testing without exposing the whole supporting infrastructure to the public internet.

The gateway is the only public entrypoint. It serves the frontend, routes API traffic, exposes Swagger and OpenAPI for learning and inspection, and serves static assets. The supporting services remain behind that boundary. PostgreSQL, ActiveMQ, Mailhog, consumer processing, and the LLM backend are still there, but they are not directly exposed.

flowchart LR
    U[Browser]
    G[Gateway<br/>awesome.byst.re<br/>public entrypoint]
    F[Frontend]
    B[Backend]
    DB[(Postgres<br/>internal only)]
    MQ[ActiveMQ<br/>internal only]
    C[Consumer<br/>internal only]
    M[Mailhog<br/>private only]
    O[Ollama Mock<br/>internal only]

    U --> G
    G --> F
    G --> B
    B --> DB
    B --> MQ
    MQ --> C
    C --> M
    B --> O

A local workshop setup can be more open because free exploration is part of the exercise. A shared public environment needs clearer boundaries. In the server profile, Mailhog is blocked from public access, monitoring stays private, and admin credentials are not exposed. People can still use the application, inspect the API, and test real user-facing behaviour, but through the intended surface rather than every internal tool at once.

That opens up use cases a typical local stack cannot support as easily. It works well for public demos, self-learning, and workshops where local setup would otherwise eat too much time. More importantly, it introduces something worth teaching in its own right: shared-environment testing. In a shared system, state is not fully under your control. Other users create data, change assumptions, and make timing less predictable. Resets and drift are part of the experience.

So awesome.byst.re is more than a public demo. It extends the stack into a shared, public training context with firmer boundaries, and that makes it useful both for demonstration and for practising the kinds of conditions testers often face in real teams.

A useful way to summarise the three profiles is this:

flowchart TD
    A[Lightweight<br/>fast local workshops<br/>LLM mock service<br/>low friction]
    B[Full<br/>local realism<br/>real LLM<br/>observability and async flows]
    C[Server<br/>public shared access<br/>controlled exposure<br/>training and demos]

    A --> C
    B --> C

In practice, I maintain all three as serious, usable environments with real teaching value.

Shared Environments Are Part of the Job

One reason the public server profile matters is that it exposes a kind of testing work that local setups usually hide.

On your own machine, the environment is mostly under your control. You start it, seed it, reset it, and if something gets messy, you can usually return to a known state quite quickly. That is useful for learning core flows and tools, but it is not the whole reality of testing work.

In real teams, people often test against staging, demo, and shared QA environments. In those systems, state collides, data drifts, resets happen, and somebody else may change the environment while you are still in the middle of an exercise. A failing check does not always mean a product defect. Sometimes it means the environment is shared, active, and no longer in the state you assumed.

That is not just noise. It is part of the job.

It shapes how you prepare test data, how you investigate failures, and how you explain what you observed. It also teaches an important habit: before concluding that something is broken, first confirm what kind of environment you are standing in.

That is part of the value of awesome.byst.re. The public server is useful not only as a demo surface, but as a place to practise working in a shared environment with real constraints and clearer boundaries. That makes it a better teaching tool than a perfectly isolated setup alone.

A Good Exercise in Test Strategy

One reason this stack is interesting from a testing point of view is that it is not just one application running in one mode. It already has a small but meaningful operational shape: three runtime profiles, each supporting a different kind of work. That changes the first question you should ask. Not “which test cases should I run?”, but “what exactly am I testing, in which profile, and why?”

That quickly leads to the kinds of questions good testers have to ask in real projects. Which behaviours should stay consistent across all profiles? Which ones are profile-specific? What is already covered by automation, and what still needs human attention? Where are the likely weak points: configuration, async flows, model-backed features, deployment differences, or user-facing workflows? The stack is small enough to explore, but rich enough to make that analysis worthwhile.

Testing work in environments like this also rewards broad technical understanding. To test it well, you need more than UI-level confidence. You need to read code, inspect setup, understand container orchestration, reason about runtime differences, and look at API behaviour and observability. That is exactly why strong technical testers are valuable: meaningful testing usually depends on understanding how the system is built, not only how it looks from the outside.

So if you explore this project, do not stop at clicking through the public profile. Use awesome.byst.re for exploratory work, but also compare it with the two local profiles and ask what each one changes, what each one hides, and what each one makes easier to validate.

Conclusion

What began as one local stack gradually became three training profiles with different intent. That shift made the project more useful, not because it grew larger, but because each profile became clearer about the job it was there to do. For me, that is the real story here: not “one stack that does everything”, but a small set of environments designed around workshops, realism, and shared access.

Where to Explore It

If you want to look at the stack in practice, start here:

If this post gave you a useful idea or two, you can always buy me a coffee. The stack runs on Docker, but the author still runs on caffeine.

If this was useful, get the next one by email.

Continue reading

A few adjacent pieces worth reading next.

PostPlaywright CLI, Skills and Isolated Agentic TestingMar 02, 2026PostAI Testing Skills: The Evolution Beyond RAG and MCPDec 23, 2025PostAgentic Testing - The New Testing ApproachNov 27, 2025

Comments

Loading comments…