1import * as AWS from "alchemy/AWS";
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 * table) and always converge on the same single resource instance.
12 */
13
14/**
15 * A dedicated VPC with two public subnets (one per AZ — an internet-facing
16 * NLB requires two AZs). No NAT: Auto Mode nodes launch in the public
17 * subnets so they can pull images from ECR.
18 */
19export const GuestbookNetwork = AWS.EC2.Network("GuestbookNetwork", {
20 cidrBlock: "10.71.0.0/16",
21 availabilityZones: 2,
22});
23
24/**
25 * The EKS cluster every workload in this app runs on. `compute: "auto"` is
26 * EKS Auto Mode in one prop: the provider creates and owns the cluster +
27 * node IAM roles and enables managed compute, block storage, and elastic
28 * load balancing — no nodegroups, no addons, no controllers to install.
29 */
30export const GuestbookCluster = Effect.gen(function* () {
31 const network = yield* GuestbookNetwork;
32 return yield* AWS.EKS.Cluster("GuestbookCluster", {
33 compute: "auto",
34 resourcesVpcConfig: {
35 subnetIds: network.publicSubnetIds,
36 endpointPublicAccess: true,
37 endpointPrivateAccess: true,
38 },
39 });
40});
41
42/** The guestbook table. Items are keyed `pk = entry#<id>`. */
43export const EntriesTable = AWS.DynamoDB.Table("EntriesTable", {
44 partitionKey: "pk",
45 attributes: { pk: "S" },
46});
47
48/**
49 * The `guestbook` namespace, applied as a RAW MANIFEST via `Kubernetes.Manifest`
50 * (server-side apply) — a literal Kubernetes object. Workloads reference
51 * `ns.name` so they deploy after the namespace exists.
52 */
53export const GuestbookNamespace = Effect.gen(function* () {
54 const cluster = yield* GuestbookCluster;
55 return yield* Kubernetes.Manifest("GuestbookNamespace", {
56 cluster,
57 manifest: {
58 apiVersion: "v1",
59 kind: "Namespace",
60 metadata: {
61 name: "guestbook",
62 labels: { "app.kubernetes.io/part-of": "guestbook" },
63 },
64 },
65 });
66});