From f9dbc124b307286fa00eddac2bf3af3271801154 Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Sat, 17 May 2025 11:22:03 +0900
Subject: [PATCH 1/6] Define *timeout*

---
 src/lib/cms.lisp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/lib/cms.lisp b/src/lib/cms.lisp
index e61aa08..7f24118 100644
--- a/src/lib/cms.lisp
+++ b/src/lib/cms.lisp
@@ -24,12 +24,14 @@
        (defcached (,name :timeout ,timeout) (&key query)
          (,origin :query query)))))
 
+(defparameter *timeout* 60)
+
 (define-object-client about)
-(memorize get-about 60)
+(memorize get-about *timeout*)
 
 (define-object-client work)
-(memorize get-work 60)
+(memorize get-work *timeout*)
 
 (define-list-client blog)
-(memorize get-blog-list 60)
-(memorize get-blog-detail 60)
+(memorize get-blog-list *timeout*)
+(memorize get-blog-detail *timeout*)

From d508d9ec70537e633f28db2cde320324a207f4b8 Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Sat, 17 May 2025 16:37:45 +0900
Subject: [PATCH 2/6] Add json api handler

---
 qlfile                    |  1 +
 qlfile.lock               |  4 ++++
 src/helper.lisp           | 12 ++++++++++++
 src/renderer.lisp         | 32 +++++++++++++++++++-------------
 src/routes/not-found.lisp | 17 ++++++++++-------
 5 files changed, 46 insertions(+), 20 deletions(-)
 create mode 100644 src/helper.lisp

diff --git a/qlfile b/qlfile
index 2f0ba9c..052a4e6 100644
--- a/qlfile
+++ b/qlfile
@@ -9,3 +9,4 @@ ql clack-errors
 git microcms https://github.com/skyizwhite/microcms-lisp-sdk
 ql local-time
 ql function-cache
+ql jonathan
diff --git a/qlfile.lock b/qlfile.lock
index f41858f..bcfc50c 100644
--- a/qlfile.lock
+++ b/qlfile.lock
@@ -46,3 +46,7 @@
  (:class qlot/source/ql:source-ql
   :initargs (:%version :latest)
   :version "ql-2023-10-21"))
+("jonathan" .
+ (:class qlot/source/ql:source-ql
+  :initargs (:%version :latest)
+  :version "ql-2020-09-25"))
diff --git a/src/helper.lisp b/src/helper.lisp
new file mode 100644
index 0000000..4732e38
--- /dev/null
+++ b/src/helper.lisp
@@ -0,0 +1,12 @@
+(defpackage #:website/helper
+  (:use #:cl
+        #:jingle)
+  (:export #:api-p))
+(in-package #:website/helper)
+
+(defun starts-with-p (prefix string)
+  (let ((pos (search prefix string :start1 0 :end1 (length prefix) :start2 0)))
+    (and pos (= pos 0))))
+
+(defun api-p ()
+  (starts-with-p "/api/" (request-uri *request*)))
diff --git a/src/renderer.lisp b/src/renderer.lisp
index 80fd48b..c3b2d28 100644
--- a/src/renderer.lisp
+++ b/src/renderer.lisp
@@ -1,7 +1,9 @@
 (defpackage #:website/renderer
   (:use #:cl
         #:hsx
-        #:jingle)
+        #:jingle
+        #:website/helper
+        #:jonathan)
   (:import-from #:hsx/element
                 #:element)
   (:import-from #:website/components/metadata
@@ -13,17 +15,21 @@
 (in-package #:website/renderer)
 
 (defmethod jingle:process-response :around ((app jingle:app) result)
-  (set-response-header :content-type "text/html; charset=utf-8")
   (when (eq (request-method *request*) :get)
     (set-response-header :cache-control "public, max-age=60"))
-  (call-next-method app
-                    (render-to-string
-                     (hsx (html :lang "ja"
-                            (head
-                              (~metadata :metadata (context :metadata))
-                              (~scripts))
-                            (body
-                              :hx-ext "head-support, response-targets, preload"
-                              :hx-boost "true" :hx-swap "transition:true"
-                              :hx-target-404 "body" :hx-target-5* "body"
-                              (~layout result)))))))
+  (cond ((api-p)
+         (set-response-header :content-type "application/json; charset=utf-8") 
+         (call-next-method app (to-json result)))
+        (t
+         (set-response-header :content-type "text/html; charset=utf-8")
+         (call-next-method app
+                           (render-to-string
+                            (hsx (html :lang "ja"
+                                   (head
+                                     (~metadata :metadata (context :metadata))
+                                     (~scripts))
+                                   (body
+                                     :hx-ext "head-support, response-targets, preload"
+                                     :hx-boost "true" :hx-swap "transition:true"
+                                     :hx-target-404 "body" :hx-target-5* "body"
+                                     (~layout result)))))))))
diff --git a/src/routes/not-found.lisp b/src/routes/not-found.lisp
index b2caaad..0715ff8 100644
--- a/src/routes/not-found.lisp
+++ b/src/routes/not-found.lisp
@@ -1,7 +1,8 @@
 (defpackage #:website/routes/not-found
   (:use #:cl
         #:hsx
-        #:jingle)
+        #:jingle
+        #:website/helper)
   (:export #:handle-not-found))
 (in-package #:website/routes/not-found)
 
@@ -12,9 +13,11 @@
 
 (defun handle-not-found ()
   (setf (context :metadata) *metadata*)
-  (hsx
-   (div :class "flex flex-col h-full items-center justify-center gap-y-6"
-     (h1 :class "font-bold text-2xl"
-       "404 Not Found")
-     (a :href "/" :class "text-lg text-pink-500 hover:underline"
-       "Back to TOP"))))
+  (if (api-p)
+      '(:|message| "404 Not Found")
+      (hsx
+       (div :class "flex flex-col h-full items-center justify-center gap-y-6"
+         (h1 :class "font-bold text-2xl"
+           "404 Not Found")
+         (a :href "/" :class "text-lg text-pink-500 hover:underline"
+           "Back to TOP")))))

From cb7062028e78a1575886fda0f3e0fc091696e58f Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Sat, 17 May 2025 16:42:51 +0900
Subject: [PATCH 3/6] re-export hsx, jingle, jonathan in helper

---
 src/components/header.lisp   | 3 +--
 src/components/metadata.lisp | 3 +--
 src/helper.lisp              | 8 +++++---
 src/renderer.lisp            | 5 +----
 src/routes/about.lisp        | 3 +--
 src/routes/blog.lisp         | 3 +--
 src/routes/index.lisp        | 2 +-
 src/routes/not-found.lisp    | 2 --
 src/routes/work.lisp         | 3 +--
 9 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/src/components/header.lisp b/src/components/header.lisp
index 9546095..d4a2f9c 100644
--- a/src/components/header.lisp
+++ b/src/components/header.lisp
@@ -1,7 +1,6 @@
 (defpackage #:website/components/header
   (:use #:cl
-        #:hsx
-        #:jingle)
+        #:website/helper)
   (:export #:~header))
 (in-package #:website/components/header)
 
diff --git a/src/components/metadata.lisp b/src/components/metadata.lisp
index f8fb04a..780e2c8 100644
--- a/src/components/metadata.lisp
+++ b/src/components/metadata.lisp
@@ -1,7 +1,6 @@
 (defpackage #:website/components/metadata
   (:use #:cl
-        #:hsx
-        #:jingle)
+        #:website/helper)
   (:import-from #:website/lib/env
                 #:website-url)
   (:export #:~metadata))
diff --git a/src/helper.lisp b/src/helper.lisp
index 4732e38..5ee1bda 100644
--- a/src/helper.lisp
+++ b/src/helper.lisp
@@ -1,6 +1,8 @@
-(defpackage #:website/helper
-  (:use #:cl
-        #:jingle)
+(uiop:define-package #:website/helper
+  (:use #:cl)
+  (:use-reexport #:hsx
+                 #:jingle
+                 #:jonathan)
   (:export #:api-p))
 (in-package #:website/helper)
 
diff --git a/src/renderer.lisp b/src/renderer.lisp
index c3b2d28..64c6724 100644
--- a/src/renderer.lisp
+++ b/src/renderer.lisp
@@ -1,9 +1,6 @@
 (defpackage #:website/renderer
   (:use #:cl
-        #:hsx
-        #:jingle
-        #:website/helper
-        #:jonathan)
+        #:website/helper)
   (:import-from #:hsx/element
                 #:element)
   (:import-from #:website/components/metadata
diff --git a/src/routes/about.lisp b/src/routes/about.lisp
index e8dcc44..e17f122 100644
--- a/src/routes/about.lisp
+++ b/src/routes/about.lisp
@@ -1,7 +1,6 @@
 (defpackage #:website/routes/about
   (:use #:cl
-        #:hsx
-        #:jingle)
+        #:website/helper)
   (:import-from #:website/lib/cms
                 #:get-about)
   (:import-from #:website/lib/time
diff --git a/src/routes/blog.lisp b/src/routes/blog.lisp
index 820b359..051e7df 100644
--- a/src/routes/blog.lisp
+++ b/src/routes/blog.lisp
@@ -1,7 +1,6 @@
 (defpackage #:website/routes/blog
   (:use #:cl
-        #:hsx
-        #:jingle)
+        #:website/helper)
   (:export #:handle-get))
 (in-package #:website/routes/blog)
 
diff --git a/src/routes/index.lisp b/src/routes/index.lisp
index 8797b29..efc327e 100644
--- a/src/routes/index.lisp
+++ b/src/routes/index.lisp
@@ -1,6 +1,6 @@
 (defpackage #:website/routes/index
   (:use #:cl
-        #:hsx)
+        #:website/helper)
   (:import-from #:website/lib/cms
                 #:get-about)
   (:export #:handle-get
diff --git a/src/routes/not-found.lisp b/src/routes/not-found.lisp
index 0715ff8..b5ca783 100644
--- a/src/routes/not-found.lisp
+++ b/src/routes/not-found.lisp
@@ -1,7 +1,5 @@
 (defpackage #:website/routes/not-found
   (:use #:cl
-        #:hsx
-        #:jingle
         #:website/helper)
   (:export #:handle-not-found))
 (in-package #:website/routes/not-found)
diff --git a/src/routes/work.lisp b/src/routes/work.lisp
index c1e6cf4..97114cc 100644
--- a/src/routes/work.lisp
+++ b/src/routes/work.lisp
@@ -1,7 +1,6 @@
 (defpackage #:website/routes/work
   (:use #:cl
-        #:hsx
-        #:jingle)
+        #:website/helper)
   (:import-from #:website/lib/cms
                 #:get-work)
   (:import-from #:website/lib/time

From fa0c60d4754d8cf7ec529a4701018029c730f35e Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Sat, 17 May 2025 17:14:58 +0900
Subject: [PATCH 4/6] Add access to helper

---
 qlfile                | 1 +
 qlfile.lock           | 4 ++++
 src/helper.lisp       | 3 ++-
 src/routes/about.lisp | 2 +-
 src/routes/index.lisp | 2 +-
 5 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/qlfile b/qlfile
index 052a4e6..1b680f7 100644
--- a/qlfile
+++ b/qlfile
@@ -10,3 +10,4 @@ git microcms https://github.com/skyizwhite/microcms-lisp-sdk
 ql local-time
 ql function-cache
 ql jonathan
+ql access
diff --git a/qlfile.lock b/qlfile.lock
index bcfc50c..f3d33ac 100644
--- a/qlfile.lock
+++ b/qlfile.lock
@@ -50,3 +50,7 @@
  (:class qlot/source/ql:source-ql
   :initargs (:%version :latest)
   :version "ql-2020-09-25"))
+("access" .
+ (:class qlot/source/ql:source-ql
+  :initargs (:%version :latest)
+  :version "ql-2024-10-12"))
diff --git a/src/helper.lisp b/src/helper.lisp
index 5ee1bda..a367676 100644
--- a/src/helper.lisp
+++ b/src/helper.lisp
@@ -2,7 +2,8 @@
   (:use #:cl)
   (:use-reexport #:hsx
                  #:jingle
-                 #:jonathan)
+                 #:jonathan
+                 #:access)
   (:export #:api-p))
 (in-package #:website/helper)
 
diff --git a/src/routes/about.lisp b/src/routes/about.lisp
index e17f122..fa84d69 100644
--- a/src/routes/about.lisp
+++ b/src/routes/about.lisp
@@ -24,7 +24,7 @@
            (div  :class "flex justify-center"
              (figure :class "flex flex-col items-center"
                (img
-                 :src (getf (getf about :avatar) :url)
+                 :src (accesses about :avatar :url)
                  :alt "avatar" :class "size-40 rounded-xl shadow-sm avatar")
                (figcaption (getf about :avatar-caption))))
            (raw! (getf about :content))
diff --git a/src/routes/index.lisp b/src/routes/index.lisp
index efc327e..fe78adb 100644
--- a/src/routes/index.lisp
+++ b/src/routes/index.lisp
@@ -30,7 +30,7 @@
     (hsx
      (div :class "flex flex-col items-center justify-center h-full"
        (img 
-         :src (getf (getf about :avatar) :url)
+         :src (accesses about :avatar :url)
          :alt "avatar" :class "size-40 rounded-xl shadow-sm avatar")
        (div :class "flex flex-col items-center gap-2 py-6"
          (h1 :class "font-bold text-2xl text-center"

From 4532ab3afe13070640cbaaded1067f8b6e9206ce Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Sat, 17 May 2025 23:48:30 +0900
Subject: [PATCH 5/6] Implement on-demand cache revalidation

---
 .env.example                   |  1 +
 qlfile                         |  2 ++
 qlfile.lock                    |  8 ++++++++
 src/helper.lisp                | 26 ++++++++++++++++++++++++++
 src/lib/cms.lisp               | 12 ++++++------
 src/lib/env.lisp               |  1 +
 src/renderer.lisp              | 34 ++++++++++++++++++++--------------
 src/routes/api/revalidate.lisp | 24 ++++++++++++++++++++++++
 src/routes/not-found.lisp      | 16 ++++++++++------
 9 files changed, 98 insertions(+), 26 deletions(-)
 create mode 100644 src/helper.lisp
 create mode 100644 src/routes/api/revalidate.lisp

diff --git a/.env.example b/.env.example
index 5166f7b..742b580 100644
--- a/.env.example
+++ b/.env.example
@@ -2,5 +2,6 @@ WEBSITE_ENV=
 WEBSITE_URL=
 MICROCMS_SERVICE_DOMAIN=
 MICROCMS_API_KEY=
+MICROCMS_WEBHOOK_KEY=
 CLOUDFLARE_ZONE_ID=
 CLOUDFLARE_API_KEY=
diff --git a/qlfile b/qlfile
index 2f0ba9c..9167909 100644
--- a/qlfile
+++ b/qlfile
@@ -9,3 +9,5 @@ ql clack-errors
 git microcms https://github.com/skyizwhite/microcms-lisp-sdk
 ql local-time
 ql function-cache
+ql jonathan
+ql flexi-streams
diff --git a/qlfile.lock b/qlfile.lock
index f41858f..0dfceae 100644
--- a/qlfile.lock
+++ b/qlfile.lock
@@ -46,3 +46,11 @@
  (:class qlot/source/ql:source-ql
   :initargs (:%version :latest)
   :version "ql-2023-10-21"))
+("jonathan" .
+ (:class qlot/source/ql:source-ql
+  :initargs (:%version :latest)
+  :version "ql-2020-09-25"))
+("flexi-streams" .
+ (:class qlot/source/ql:source-ql
+  :initargs (:%version :latest)
+  :version "ql-2024-10-12"))
diff --git a/src/helper.lisp b/src/helper.lisp
new file mode 100644
index 0000000..c208395
--- /dev/null
+++ b/src/helper.lisp
@@ -0,0 +1,26 @@
+(uiop:define-package #:website/helper
+  (:use #:cl
+        #:jingle)
+  (:import-from #:flexi-streams
+                #:make-flexi-stream)
+  (:import-from #:jonathan
+                #:parse)
+  (:export #:api-request-p
+           #:get-request-body-plist))
+(in-package #:website/helper)
+
+(defun starts-with-p (prefix string)
+  (let ((pos (search prefix string :start1 0 :end1 (length prefix) :start2 0)))
+    (and pos (= pos 0))))
+
+(defun api-request-p ()
+  (starts-with-p "/api/" (request-uri *request*)))
+
+(defun get-request-body-plist ()
+  (parse
+   (let ((text-stream (make-flexi-stream (request-raw-body *request*)
+                                         :external-format :utf-8)))
+     (with-output-to-string (out)
+       (loop :for char := (read-char text-stream nil)
+             :while char
+             :do (write-char char out))))))
diff --git a/src/lib/cms.lisp b/src/lib/cms.lisp
index e61aa08..7f75c80 100644
--- a/src/lib/cms.lisp
+++ b/src/lib/cms.lisp
@@ -17,19 +17,19 @@
 (setf microcms:*service-domain* (microcms-service-domain))
 (setf microcms:*api-key* (microcms-api-key))
 
-(defmacro memorize (name timeout)
+(defmacro memorize (name)
   (let ((origin (gensym)))
     `(progn
        (setf (fdefinition ',origin) (fdefinition ',name))
-       (defcached (,name :timeout ,timeout) (&key query)
+       (defcached ,name (&key query)
          (,origin :query query)))))
 
 (define-object-client about)
-(memorize get-about 60)
+(memorize get-about)
 
 (define-object-client work)
-(memorize get-work 60)
+(memorize get-work)
 
 (define-list-client blog)
-(memorize get-blog-list 60)
-(memorize get-blog-detail 60)
+(memorize get-blog-list)
+(memorize get-blog-detail)
diff --git a/src/lib/env.lisp b/src/lib/env.lisp
index a6e1ffb..f0a4bb1 100644
--- a/src/lib/env.lisp
+++ b/src/lib/env.lisp
@@ -18,3 +18,4 @@
 (env-var website-url "WEBSITE_URL")
 (env-var microcms-service-domain "MICROCMS_SERVICE_DOMAIN")
 (env-var microcms-api-key "MICROCMS_API_KEY")
+(env-var microcms-webhook-key "MICROCMS_WEBHOOK_KEY")
diff --git a/src/renderer.lisp b/src/renderer.lisp
index 80fd48b..7863e38 100644
--- a/src/renderer.lisp
+++ b/src/renderer.lisp
@@ -2,8 +2,10 @@
   (:use #:cl
         #:hsx
         #:jingle)
-  (:import-from #:hsx/element
-                #:element)
+  (:import-from #:jonathan
+                #:to-json)
+  (:import-from #:website/helper
+                #:api-request-p)
   (:import-from #:website/components/metadata
                 #:~metadata)
   (:import-from #:website/components/scripts
@@ -13,17 +15,21 @@
 (in-package #:website/renderer)
 
 (defmethod jingle:process-response :around ((app jingle:app) result)
-  (set-response-header :content-type "text/html; charset=utf-8")
   (when (eq (request-method *request*) :get)
     (set-response-header :cache-control "public, max-age=60"))
-  (call-next-method app
-                    (render-to-string
-                     (hsx (html :lang "ja"
-                            (head
-                              (~metadata :metadata (context :metadata))
-                              (~scripts))
-                            (body
-                              :hx-ext "head-support, response-targets, preload"
-                              :hx-boost "true" :hx-swap "transition:true"
-                              :hx-target-404 "body" :hx-target-5* "body"
-                              (~layout result)))))))
+  (cond ((api-request-p)
+         (set-response-header :content-type "application/json; charset=utf-8") 
+         (call-next-method app (to-json result)))
+        (t
+         (set-response-header :content-type "text/html; charset=utf-8")
+         (call-next-method app
+                           (render-to-string
+                            (hsx (html :lang "ja"
+                                   (head
+                                     (~metadata :metadata (context :metadata))
+                                     (~scripts))
+                                   (body
+                                     :hx-ext "head-support, response-targets, preload"
+                                     :hx-boost "true" :hx-swap "transition:true"
+                                     :hx-target-404 "body" :hx-target-5* "body"
+                                     (~layout result)))))))))
diff --git a/src/routes/api/revalidate.lisp b/src/routes/api/revalidate.lisp
new file mode 100644
index 0000000..7c0457e
--- /dev/null
+++ b/src/routes/api/revalidate.lisp
@@ -0,0 +1,24 @@
+(defpackage #:website/routes/api/revalidate
+  (:use #:cl
+        #:jingle)
+  (:import-from #:function-cache
+                #:clear-cache)
+  (:import-from #:website/lib/env
+                #:microcms-webhook-key)
+  (:import-from #:website/helper
+                #:get-request-body-plist)
+  (:import-from #:website/lib/cms
+                #:get-about)
+  (:export #:handle-post))
+(in-package #:website/routes/api/revalidate)
+
+(defun handle-post (params)
+  (declare (ignore params))
+  (unless (string= (car (get-request-header "X-MICROCMS-WEBHOOK-KEY"))
+                   (microcms-webhook-key))
+    (set-response-status :unauthorized)
+    (return-from handle-post '(:|message| "Invalid token")))
+  (let* ((body (get-request-body-plist))
+         (api (getf body :|api|)))
+    (cond ((string= api "about") (clear-cache 'get-about)))
+    '(:|message| "ok")))
diff --git a/src/routes/not-found.lisp b/src/routes/not-found.lisp
index b2caaad..163ff70 100644
--- a/src/routes/not-found.lisp
+++ b/src/routes/not-found.lisp
@@ -2,6 +2,8 @@
   (:use #:cl
         #:hsx
         #:jingle)
+  (:import-from #:website/helper
+                #:api-request-p)
   (:export #:handle-not-found))
 (in-package #:website/routes/not-found)
 
@@ -12,9 +14,11 @@
 
 (defun handle-not-found ()
   (setf (context :metadata) *metadata*)
-  (hsx
-   (div :class "flex flex-col h-full items-center justify-center gap-y-6"
-     (h1 :class "font-bold text-2xl"
-       "404 Not Found")
-     (a :href "/" :class "text-lg text-pink-500 hover:underline"
-       "Back to TOP"))))
+  (if (api-request-p)
+      '(:|message| "404 Not Found")
+      (hsx
+       (div :class "flex flex-col h-full items-center justify-center gap-y-6"
+         (h1 :class "font-bold text-2xl"
+           "404 Not Found")
+         (a :href "/" :class "text-lg text-pink-500 hover:underline"
+           "Back to TOP")))))

From 5a05f440a8e3907a261de7ae54b0d3540bc7d04d Mon Sep 17 00:00:00 2001
From: Akira Tempaku <paku@skyizwhite.dev>
Date: Sat, 17 May 2025 23:48:56 +0900
Subject: [PATCH 6/6] Add access

---
 qlfile                | 1 +
 qlfile.lock           | 4 ++++
 src/routes/about.lisp | 5 +++--
 src/routes/index.lisp | 5 +++--
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/qlfile b/qlfile
index 9167909..b4862b2 100644
--- a/qlfile
+++ b/qlfile
@@ -10,4 +10,5 @@ git microcms https://github.com/skyizwhite/microcms-lisp-sdk
 ql local-time
 ql function-cache
 ql jonathan
+ql access
 ql flexi-streams
diff --git a/qlfile.lock b/qlfile.lock
index 0dfceae..6421bac 100644
--- a/qlfile.lock
+++ b/qlfile.lock
@@ -50,6 +50,10 @@
  (:class qlot/source/ql:source-ql
   :initargs (:%version :latest)
   :version "ql-2020-09-25"))
+("access" .
+ (:class qlot/source/ql:source-ql
+  :initargs (:%version :latest)
+  :version "ql-2024-10-12"))
 ("flexi-streams" .
  (:class qlot/source/ql:source-ql
   :initargs (:%version :latest)
diff --git a/src/routes/about.lisp b/src/routes/about.lisp
index e8dcc44..1fd330c 100644
--- a/src/routes/about.lisp
+++ b/src/routes/about.lisp
@@ -1,7 +1,8 @@
 (defpackage #:website/routes/about
   (:use #:cl
         #:hsx
-        #:jingle)
+        #:jingle
+        #:access)
   (:import-from #:website/lib/cms
                 #:get-about)
   (:import-from #:website/lib/time
@@ -25,7 +26,7 @@
            (div  :class "flex justify-center"
              (figure :class "flex flex-col items-center"
                (img
-                 :src (getf (getf about :avatar) :url)
+                 :src (accesses about :avatar :url)
                  :alt "avatar" :class "size-40 rounded-xl shadow-sm avatar")
                (figcaption (getf about :avatar-caption))))
            (raw! (getf about :content))
diff --git a/src/routes/index.lisp b/src/routes/index.lisp
index 8797b29..398abbc 100644
--- a/src/routes/index.lisp
+++ b/src/routes/index.lisp
@@ -1,6 +1,7 @@
 (defpackage #:website/routes/index
   (:use #:cl
-        #:hsx)
+        #:hsx
+        #:access)
   (:import-from #:website/lib/cms
                 #:get-about)
   (:export #:handle-get
@@ -30,7 +31,7 @@
     (hsx
      (div :class "flex flex-col items-center justify-center h-full"
        (img 
-         :src (getf (getf about :avatar) :url)
+         :src (accesses about :avatar :url)
          :alt "avatar" :class "size-40 rounded-xl shadow-sm avatar")
        (div :class "flex flex-col items-center gap-2 py-6"
          (h1 :class "font-bold text-2xl text-center"