1import * as GCP from "alchemy/GCP";
2import * as Kubernetes from "alchemy/Kubernetes";
3import * as Effect from "effect/Effect";
4
5/**
6 * Shared infrastructure for the guestbook app.
7 *
8 * Each export is an Effect that declares a resource. Resources are memoized
9 * by logical id, so these can be yielded from the stack program AND from a
10 * workload's props/init effect (e.g. `Api` targets the cluster and binds the
11 * database) and always converge on the same single resource instance.
12 */
13
14/**
15 * The GKE cluster every workload in this app runs on. `autopilot: true` is
16 * GKE Autopilot: Google provisions and scales the nodes from the pods'
17 * resource requests — no node pools to manage. Autopilot clusters are
18 * regional and always have Workload Identity Federation enabled, which is
19 * how the workloads' bindings authenticate.
20 */
21export const GuestbookCluster = GCP.Container.Cluster("GuestbookCluster", {
22 // Autopilot needs a region; the Cluster default is the zone `us-central1-a`.
23 location: "us-central1",
24 autopilot: true,
25 releaseChannel: "REGULAR",
26});
27
28/**
29 * The guestbook database: a named Firestore database in Native mode.
30 * Entries are documents at `entries/<id>`.
31 */
32export const EntriesDatabase = GCP.Firestore.Database("EntriesDatabase", {
33 type: "FIRESTORE_NATIVE",
34});
35
36/**
37 * The `guestbook` namespace, applied as a RAW MANIFEST via `Kubernetes.Manifest`
38 * (server-side apply) — a literal Kubernetes object. Workloads reference
39 * `ns.name` so they deploy after the namespace exists.
40 */
41export const GuestbookNamespace = Effect.gen(function* () {
42 const cluster = yield* GuestbookCluster;
43 return yield* Kubernetes.Manifest("GuestbookNamespace", {
44 cluster,
45 manifest: {
46 apiVersion: "v1",
47 kind: "Namespace",
48 metadata: {
49 name: "guestbook",
50 labels: { "app.kubernetes.io/part-of": "guestbook" },
51 },
52 },
53 });
54});
55
56/** The document path of one guestbook entry. */
57export const entryPath = (id: string) => `entries/${id}`;