Phase 0: Walking Skeleton¶
A walking skeleton is the smallest real version of a system that works from one end to the other. It may not do everything yet, but every important layer is connected.
For PackyTrace, this meant scanning a seeded product through the gateway, reading it from the real database, saving the scan, publishing an event, and displaying the result in the web app.
Task 0.1: Product Database and Migration Runner¶
Like you're 5¶
We built the product room's first filing cabinet. We also hired a worker who reads a numbered instruction list every time the room opens, ensuring the cabinet has the correct drawers.
Normal explanation¶
The passport service was connected to PostgreSQL. A startup migration runner creates
the product_catalog table, and Docker Compose gives the service its database address.
The passport service connects using its own restricted database role, so it cannot
read another service's private tables.
Technologies used: PostgreSQL stores the data; goose runs versioned SQL migrations from Go; Docker Compose supplies and connects the local database.
Task 0.2: Seed the Product Catalog¶
Like you're 5¶
An empty filing cabinet is not useful, so we filled it with 13 example product cards. Each card says which company owns the product and includes details such as allergens and environmental information.
Normal explanation¶
A database seed migration inserts a curated demo catalog. It includes the products previously shown by the mock web app, shared Brand IDs, allergen codes, eco data, and an intentionally unverified product for later verdict testing.
Technologies used: a seed migration is a migration that inserts initial data; UUIDs are unique identifiers used for the demo Brands.
Task 0.3: Type-Safe Product Queries¶
Like you're 5¶
Instead of letting workers write random notes when looking inside the cabinet, we gave them approved question cards. A machine checks those cards and prepares the correct instructions for finding products.
Normal explanation¶
The passport service now keeps its SQL queries in committed files. sqlc reads those queries and database migrations, then generates type-safe Go code for executing them. A catalog repository translates database rows into passport-domain product objects. CI checks that generated code has not drifted from the SQL source.
Technologies used: SQL queries PostgreSQL; sqlc generates Go database code; pgx is the PostgreSQL driver used by Go.
Task 0.4: Scan Business Rules¶
Like you're 5¶
We taught the product room what “scan this product” means. It knows how to reject a bad number, say when a product is missing, build an honest product passport, and make sure one visitor cannot read another visitor's scan.
Normal explanation¶
Pure Go domain models and application use cases now represent catalog entries, scanned
items, scan records, and resolved passports. ResolveScan coordinates the scan without
depending directly on HTTP, PostgreSQL, or Kafka. Tests cover validation, unknown
products, missing journey data, eco-score calculation, and scan ownership.
This follows PackyTrace's hexagonal architecture: business rules depend on interfaces called ports, while infrastructure is connected later through adapters.
Technologies used: Go domain code, hexagonal architecture, ports and adapters, and table-driven automated tests.
Task 0.5: Real Scan API¶
Like you're 5¶
We opened two service windows. At the first window, a visitor can ask to scan a product. At the second, they can return with their receipt and see the saved result. Someone else's receipt deliberately looks like it does not exist.
Normal Explanation¶
The passport service now implements:
POST /api/v1/scansto resolve and save a product scan;GET /api/v1/scans/{scanId}to retrieve the saved result.
Scans are stored in the scan_records table. Access is scoped by the pseudonymous
Visitor ID. A non-owner receives 404 Not Found, which avoids revealing whether the
private scan exists.
Technologies used: HTTP endpoints, JSON requests and responses, PostgreSQL, repository adapters, and a pseudonymous Visitor ID.
Task 0.6: Announce Product Scans¶
Like you're 5¶
Whenever a product is scanned, the product room puts a note on a shared noticeboard: “A product was scanned.” Other rooms can read the note later, but the scan still works if the noticeboard is temporarily unavailable.
Normal Explanation¶
After saving a scan, the passport service publishes a ProductScanned event to the
passport.facts.v1 Kafka topic. The event uses PackyTrace's generated contract types
and standard event envelope. Publishing is currently fire-and-forget, so Kafka downtime
does not make the user's scan fail.
Docker Compose also runs a one-time kafka-init service that creates the required
topics.
Technologies used: Apache Kafka is the event noticeboard; franz-go is the Go Kafka client; JSON Schema-generated contracts define the event shape.
Task 0.7: End-to-End Smoke Test¶
Like you're 5¶
Before opening the shop, a worker walks through the front door, scans a product, and checks that the expected result comes back.
Normal Explanation¶
The container smoke test now sends a real scan request through the running API gateway and verifies the scan round-trip. This catches failures that isolated unit tests may miss, such as broken container networking or incorrect service configuration.
Technologies used: a shell-based smoke test, Docker Compose, HTTP, and the real running services.
Task 0.8: Connect the Web App to the Real API¶
Like you're 5¶
The website used to play with pretend product cards. We gave it a telephone so it can ask the real product room for answers. We kept the pretend cards available in case the real rooms are offline.
Normal Explanation¶
The SvelteKit web app gained an API client, response mappers, and a locally cached Visitor ID. In real mode it sends scan requests through the gateway and translates the backend response into the shape expected by the existing interface. The old mock scan implementation remains available as an isolated fallback.
Technologies used: SvelteKit and TypeScript build the web app; fetch makes HTTP
requests; browser localStorage remembers the Visitor ID.
Checkpoint 0¶
Like you're 5¶
We checked that the entire little path worked and kept a known-good copy of the pretend demo, just in case.
Normal Explanation¶
The project passed make check and make smoke, and both real and mock scan modes were
verified. A Git tag preserves the known-good mock demo fallback.