Build1 distinct publisher3 min readPublished
A dev.to author cut his project's twelve-service quickstart down to four running containers, and two of the three conclusions he had drawn from reading the code failed as soon as he started it.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The adapter builds its base URL as `base_url or settings.storage_url or self._default_local_base_url()`, and the fallback returns a `file://` URI under the repository root [11]. On that evidence, pointing `STORAGE_URL` at a directory should drop the object store, which is the inference the author made and then had to withdraw [10]. What actually runs is `_normalize_root_path`, one line: `root_path.replace("\\", "/").strip("/")` [14]. Python's `strip` works on both ends, so the absolute `/home/appuser/soit-storage` comes out as the relative `home/appuser/soit-storage`, and fsspec's LocalFileSystem resolves that against the process working directory [14]. The image sets `WORKDIR /app/` [15]. The write therefore goes to `/app/home/...`, and constructing the adapter inside the container raised `PermissionError: [Errno 13] Permission denied: '/app/home'` [13]. For a path normalizer, converting absolute paths into relative ones is an unusual service to offer.
`/app` is root-owned because `server/Dockerfile` copies the tree with `COPY ./ /app/` and no `--chown`, while the final instruction is `USER appuser` at uid 10001 [16]. A volume does not rescue it, since Docker creates the mount point root-owned as well [17]. That leaves running the API as root or pre-chowning a mount [18]. So the transfer condition for anyone else's object-store-free variant is narrow: the image's working directory has to be writable by the runtime user, or the normalizer has to stop eating the leading slash.
Four counts the containers still standing, out of seven that compose actually starts. Seven declared services minus the three that exit is four [4][21], and six of the twelve names in the original command are gone [22]. One image dominates the saving, Milvus at 2.6GB [5]. Read "a couple hundred megabytes" as 200 to 300MB and MinIO is roughly 9 to 13 times smaller [19][23], which is why keeping it costs an evaluator very little.
The method is what makes this write-up durable: a deployment guide records intent, a health check records behaviour [8]. That holds on the vector store, where a failed readiness check sets the field to `unavailable` and still returns 200, because the docstring says the platform degrades gracefully without it [6][7]. It breaks on storage, where the 503 branch reports "Object storage is unavailable" [6] for a fault that is really path handling plus directory ownership [12][13]. The author says two of his three code-derived conclusions failed on contact with a running stack, and that publishing the paper version would have left readers with a stack that starts and then refuses to show a UI [20]. The text supplied to me documents the first of those and cuts off mid-aside before the second [24]. One demonstrated failure of this kind is enough for me: a compose file plus a health router is not evidence about which services are optional, and the only way to find out is to boot the trimmed configuration.
Ranked by verification strength, evidence, and original report placement.
In server/app/api/v1/health/router.py a failed 'SELECT 1' raises HTTPException 503 'Database is unavailable', a failed storage.ensure_ready() raises 503 'Object storage is unavailable', and a failed vector.check_ready() only sets vector_status to 'unavailable' while the endpoint still returns 200.
The health check docstring states that the platform degrades gracefully when the vector store is down, so a vector outage should be surfaced rather than pull the instance out of rotation.
MinIO stays in the trimmed stack as one long-running container plus a minio-init that exits, on a couple hundred megabytes, which the author calls an order of magnitude smaller than the Milvus group.
The supplied text of the post documents the first wrong conclusion in full and breaks off mid-sentence in an aside about MinIO's two roles in the full topology, before the second wrong conclusion is described.
The project's README quickstart is a single docker compose command naming twelve services: postgres, redis, minio, etcd, milvus, vault, migrate, bootstrap, api, web, knowledge-ingest-worker and outbox-dispatcher.
Issue #25 on the project asked whether a user who just wants to look at it really needs all of the listed services.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 29, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Three services you can delete: queue, cache and search in one Postgres1 distinct publisher
build
The ICO fines what you cannot prove: Article 32 makes encryption and erasure an engineering liability1 distinct publisher
build
Edge KV puts the permission check an hour behind the Postgres row1 distinct publisher
build
The five-minute grep: what `synchronize: true` tells a reviewer before your tests do1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Quoted code, one witness
Unusually checkable for a single post: the resolution line from the storage adapter, the four-line _normalize_root_path, the Dockerfile's COPY without --chown and the USER appuser uid, the exact 503 body, the PermissionError path. Each step of the failure chain is shown rather than asserted, and the conclusion was tested against a real run instead of read off the source. What holds the number down is that every one of those quotes comes from the same person reading his own repository, with no one else reproducing it — and the text we have stops mid-sentence before the third finding is explained.
One run, one issue
The entire usage record is the maintainer's own execution of the trimmed stack plus a single issue asking whether all twelve services are needed. Nobody else is reported to have run the four-container configuration, no download, star or install figures appear, and the project itself is unnamed in the piece except through a storage path. The trim is a proposal with one witness.
Findings undersold
Slightly understated. The headline sells a container count and a confession, while the substance is a reproducible defect in a shipped image: a path helper that quietly relativises absolute paths, landing them in a directory the process was deliberately denied write access to. That sits here as an anecdote inside someone's cleanup story, with no bug report referenced and no claim that other projects share the pattern — even though the strip-then-drop-privileges combination is generic. The one place the rhetoric outruns the evidence is the opening line about losing most users at the first command, which carries no data at all.
Maintainer writing about his own repo
This is the project talking about itself: "Here is ours", a developer-platform post whose practical effect is to make a twelve-service stack look approachable, published where such posts recruit contributors. The obvious pull is toward a tidy result. It largely does not happen — the piece keeps a wrong conclusion in place, concedes that the local filesystem backend cannot work in the shipped image, and admits the object store was never separable from the component being removed. Self-interest is present and visible; it does not appear to have shaped the findings.
Solid on mechanics, thin on reach
High confidence in the failure mechanism — the path conversion, the ownership, the mount that does not help — because it is shown at the level of quoted code and a traceback from a run. Much lower confidence in anything beyond this repository: whether the defect persists, whether the four-container stack works for anyone else, whether readme friction really costs most users. And the piece's own arithmetic of three conclusions is only two-thirds visible in the text available.