From cc6683cdcc0549bd2ec0f96ac71b462d0187cad7 Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Wed, 30 Apr 2025 23:14:55 +0900
Subject: [PATCH 1/2] Purge CDN cache on deploy

---
 Dockerfile    | 15 ++++++++++-----
 entrypoint.sh | 15 +++++++++++++++
 2 files changed, 25 insertions(+), 5 deletions(-)
 create mode 100644 entrypoint.sh

diff --git a/Dockerfile b/Dockerfile
index 8f8df9d..d8f6cd1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,19 +1,24 @@
 FROM fukamachi/qlot
 
+ARG TW_VERSION=4.1.3
+ARG TW_BIN=./bin/tailwindcss
+
 WORKDIR /app
 COPY . /app
 
 RUN apt-get update && apt-get install -y --no-install-recommends build-essential curl libev-dev
 
 RUN mkdir -p ./bin \
-  && curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 \
+  && curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/download/v${TW_VERSION}/tailwindcss-linux-x64 \
   && chmod +x tailwindcss-linux-x64 \
-  && mv tailwindcss-linux-x64 ./bin/tailwindcss
+  && mv tailwindcss-linux-x64 ${TW_BIN}
 
-RUN ./bin/tailwindcss -i ./static/style/global.css -o ./static/style/dist.css --minify
+RUN ${TW_BIN} -i ./static/style/global.css -o ./static/style/dist.css --minify
 
-RUN qlot install --quiet
+RUN qlot install --quiet --no-color
+
+RUN chmod +x entrypoint.sh
 
 EXPOSE 3000
 
-ENTRYPOINT [".qlot/bin/clackup", "--system", "hp", "--server", "woo", "--address", "0.0.0.0", "--port", "3000", "src/app.lisp"]
+ENTRYPOINT ["./entrypoint.sh"]
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 0000000..8361b19
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -e
+
+if [[ -n "$CLOUDFLARE_ZONE_ID" && -n "$CLOUDFLARE_API_KEY" ]]; then
+  echo "Purging Cloudflare cache..."
+  curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/purge_cache" \
+    -H "Content-Type: application/json" \
+    -H "Authorization: Bearer ${CLOUDFLARE_API_KEY}" \
+    -d '{ "hosts": ["skyizwhite.dev"] }'
+else
+  echo "Cloudflare credentials not provided. Skipping cache purge."
+fi
+
+echo "Starting server..."
+exec .qlot/bin/clackup --system hp --server woo --address 0.0.0.0 --port 3000 src/app.lisp

From f16f49dde75442f9a84ed65e01d7bc89202b903f Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Thu, 1 May 2025 00:37:46 +0900
Subject: [PATCH 2/2] Improve cache control

---
 src/renderer.lisp         | 27 +++++++++++++++++++--------
 src/routes/bio.lisp       |  4 +++-
 src/routes/blog.lisp      |  4 +++-
 src/routes/index.lisp     |  3 ++-
 src/routes/not-found.lisp |  4 +++-
 src/routes/work.lisp      |  4 +++-
 6 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/src/renderer.lisp b/src/renderer.lisp
index a6d826a..65e83d8 100644
--- a/src/renderer.lisp
+++ b/src/renderer.lisp
@@ -13,17 +13,28 @@
                 #:~layout))
 (in-package #:hp/renderer)
 
+(defun set-cache-control (strategy)
+  (set-response-header :cache-control
+                       (if (string= (hp-env) "dev")
+                           "private, no-store"
+                           (cond 
+                             ((eq strategy :static)
+                              "public, max-age=31536000, immutable")
+                             ((eq strategy :dynamic)
+                              "public, max-age=60 stale-while-revalidate=86400, stale-if-error=86400")
+                             (t
+                              "private, no-store")))))
+
 (defmethod jingle:process-response ((app jingle:app) result)
   (set-response-header :content-type "text/html; charset=utf-8")
-  (set-response-header :cache-control (if (string= (hp-env) "dev")
-                                          "private, no-store"
-                                          "public, max-age=60 s-maxage=300, stale-while-revalidate=86400, stale-if-error=86400"))
   (call-next-method app
                     (hsx:render-to-string
                      (match result
-                       ((guard (or (list page metadata)
-                                   page)
-                               (typep page 'element))
-                        (~layout :metadata metadata
-                          page))
+                       ((plist :body body
+                               :metadata metadata
+                               :cache cache)
+                        (progn
+                          (set-cache-control cache)
+                          (~layout :metadata metadata
+                            body)))
                        (_ (error "Invalid response form"))))))
diff --git a/src/routes/bio.lisp b/src/routes/bio.lisp
index 5002a65..e12e000 100644
--- a/src/routes/bio.lisp
+++ b/src/routes/bio.lisp
@@ -15,4 +15,6 @@
 
 (defun handle-get (params)
   (declare (ignore params))
-  (list (~page) *metadata*))
+  (list :body (~page)
+        :metadata *metadata*
+        :cache :dynamic))
diff --git a/src/routes/blog.lisp b/src/routes/blog.lisp
index 5760d3e..173a2ed 100644
--- a/src/routes/blog.lisp
+++ b/src/routes/blog.lisp
@@ -15,4 +15,6 @@
 
 (defun handle-get (params)
   (declare (ignore params))
-  (list (~page) *metadata*))
+  (list :body (~page)
+        :metadata *metadata*
+        :cache :dynamic))
diff --git a/src/routes/index.lisp b/src/routes/index.lisp
index 2c71a43..683ccc1 100644
--- a/src/routes/index.lisp
+++ b/src/routes/index.lisp
@@ -28,4 +28,5 @@
 
 (defun handle-get (params)
   (declare (ignore params))
-  (~page))
+  (list :body (~page)
+        :cache :static))
diff --git a/src/routes/not-found.lisp b/src/routes/not-found.lisp
index b05f179..34c3e21 100644
--- a/src/routes/not-found.lisp
+++ b/src/routes/not-found.lisp
@@ -18,4 +18,6 @@
        "Back to TOP"))))
 
 (defun handle-not-found ()
-  (list (~page) *metadata*))
+  (list :body (~page)
+        :metadata *metadata*
+        :cache :dynamic))
diff --git a/src/routes/work.lisp b/src/routes/work.lisp
index b538b06..9345a53 100644
--- a/src/routes/work.lisp
+++ b/src/routes/work.lisp
@@ -15,4 +15,6 @@
 
 (defun handle-get (params)
   (declare (ignore params))
-  (list (~page) *metadata*))
+  (list :body (~page)
+        :metadata *metadata*
+        :cache :dynamic))