Major changes: - Replace Payload CMS with Tina CMS (self-hosted) - Add Astro DB for consent logging (PDPA compliant) - Update Tailwind v3 to v4 (@tailwindcss/vite plugin) - Add astro-tina-starter template - Rewrite consent template for Astro (ConsentBanner.astro, Astro DB, Nano Stores) - Add install-tina-backend.sh for self-hosted Tina per customer - Rename convert-astro.sh to migrate-tina.sh - Add AGENTS.md template for generated websites - Delete all Payload/Next.js files Technical updates: - Astro DB using defineDb with eq operators for queries - Tailwind v4 with @theme block - Tina CMS local development mode - Proper Astro API routes for consent Research-verified with official documentation (April 2026)
PDPA Consent Logging Template
Template สำหรับเพิ่ม PDPA consent logging ใน Astro + Tina (Astro DB)
Files
consent/
├── ConsentBanner.astro # Consent banner component
├── api/
│ └── consent.ts # API endpoints (GET, POST, DELETE)
├── db/
│ └── config.ts # Astro DB schema (defineTable)
├── stores/
│ └── consent.ts # Nano Stores for client state
└── README.md # This file
วิธีใช้ (Astro)
1. เพิ่ม Astro DB Schema
Copy db/config.ts ไปที่ src/db/config.ts:
// src/db/config.ts
import { defineTable, column } from 'astro:db';
export const ConsentLog = defineTable({
columns: {
id: column.number({ primaryKey: true }),
action: column.text(),
purpose: column.text(),
analytics: column.boolean({ default: false }),
marketing: column.boolean({ default: false }),
functional: column.boolean({ default: false }),
userAgent: column.text({ optional: true }),
ip: column.text({ optional: true }),
timestamp: column.date(),
sessionId: column.text({ optional: true }),
},
});
2. สร้าง API Endpoint
Copy api/consent.ts ไปที่ src/pages/api/consent.ts
3. เพิ่ม ConsentBanner Component
Copy ConsentBanner.astro ไปที่ src/components/consent/ConsentBanner.astro
4. เพิ่มใน Layout
เพิ่ม <ConsentBanner /> ใน src/layouts/Layout.astro:
---
import ConsentBanner from '../components/consent/ConsentBanner.astro';
---
<html lang="th">
<body>
<slot />
<ConsentBanner />
</body>
</html>
API
POST /api/consent
บันทึก consent action
Request:
{
"action": "accept",
"purpose": "all",
"analytics": true,
"marketing": false,
"functional": true
}
Response:
{
"success": true,
"doc": {
"id": 1,
"action": "accept",
"purpose": "all",
"analytics": true,
"marketing": false,
"functional": true,
"userAgent": "Mozilla/5.0...",
"ip": "127.0.0.1",
"timestamp": "2026-04-10T00:00:00.000Z"
}
}
GET /api/consent
ดึง consent logs
curl "http://localhost:4321/api/consent"
DELETE /api/consent
Right to be forgotten (ลบข้อมูลตาม พ.ร.บ.)
curl -X DELETE "http://localhost:4321/api/consent?sessionId=xxx"
Nano Stores Usage
import { consentStore, hasAnalyticsConsent, hasMarketingConsent } from './stores/consent';
// Subscribe to changes
consentStore.subscribe((state) => {
console.log('Consent changed:', state);
});
// Check consent
if (hasAnalyticsConsent()) {
// Load analytics
}
UX
- ยอมรับทั้งหมด - เปิดทุกคุกกี้
- ปฏิเสธทั้งหมด - ปิดทุกคุกกี้ (ยกเว้น functional)
- ตั้งค่าคุกกี้ - แผงปรับแต่งเอง
⚠️ Pitfalls สำคัญ
- Astro DB ต้องรันบน server-side - ใช้
APIRouteimport - Nano Stores รันบน client-side - ใช้
<script>tag ใน Astro - import ถูกต้อง - ใช้
import { db } from 'astro:db'ไม่ใช่defineDb