:3000 {
    root * /usr/share/caddy

    # Compress text responses only. woff2/png and other binaries are already
    # compressed, so they're excluded — re-compressing them burns CPU for ~0%.
    encode {
        zstd
        gzip
        match {
            header Content-Type text/*
            header Content-Type application/javascript*
            header Content-Type application/json*
            header Content-Type image/svg+xml*
        }
    }

    # Vite emits all build output under /assets/ with content-hashed filenames,
    # so those bytes never change for a given URL — cache them indefinitely.
    @assets path /assets/*
    header @assets Cache-Control "public, max-age=31536000, immutable"

    # The HTML shell is the un-hashed entry point; it must revalidate so a new
    # deploy is served immediately rather than from a stale cache.
    header /index.html Cache-Control "no-cache"

    try_files {path} /index.html
    file_server
}
