- Replace Astro DB with better-sqlite3 (bypasses remote SQLite limitation) - Add consent API with auto-create table pattern - Update admin dashboard to fetch from API instead of Astro DB - Add IP hashing and rate limiting for GDPR compliance - Add seo-utils-mcp-guide skill - Update legal templates with business placeholders
21 KiB
name, description
| name | description |
|---|---|
| thai-frontend-dev | Thai market website addon for frontend-dev. Adds PDPA compliance, bilingual i18n, cookie consent, Umami Analytics, Easypanel deployment, and Thai legal pages. Use when: building Thai websites, need PDPA compliance, Thai/English bilingual sites. Requires: frontend-dev as base skill. |
🇹🇭 Thai Frontend Dev - Website Addon
Addon Name: thai-frontend-dev
Base Skill: frontend-dev
Category: deep
Load Skills: [] (addon to frontend-dev)
🎯 Purpose
Create and deploy PDPA-compliant Astro websites on Easypanel automatically with:
- ✅ Bilingual support (Thai/English)
- ✅ Umami Analytics (privacy-first, no cookies)
- ✅ Cookie consent management (astro-consent)
- ✅ Consent logging database (better-sqlite3 - direct SQLite, bypasses Astro DB limitation)
- ✅ PDPA-compliant legal pages (Privacy Policy, Terms)
- ✅ Easypanel deployment (Docker, auto-deploy)
Use Cases:
- New Website - Build from ground up with all compliance features
- Redesign - Crawl existing website and rebuild with Astro + PDPA compliance
- Refactor - Update existing websites to new standard structure
🚀 Workflow
Phase 0: Pre-Flight (Critical Questions)
MUST ask before starting:
-
Website Type:
- Corporate (products, services, blog)
- Portfolio (showcase, gallery)
- Landing Page (single page, product launch)
- Blog/Magazine (content-focused)
- E-commerce (with Snipcart/Stripe)
- Custom (describe)
-
Website Name: (e.g., "Deal Plus Tech")
-
Brand/Company Name: (for title, meta)
-
Language Strategy:
- Thai only (th)
- English only (en)
- Bilingual Thai + English (th + en, with fallback)
- Default: Bilingual with English as default
-
For Redesign/Refactor:
- Original website URL or path?
- What to preserve? (content, design, URLs)
- What to improve?
-
Features Needed:
- Base (always included):
- Responsive design
- SEO optimization
- Bilingual i18n routing
- Cookie consent banner
- Consent logging DB
- Umami Analytics
- PDPA-compliant Privacy Policy
- PDPA-compliant Terms
- Contact forms
- Social media links
- Dark mode
- Blog with content collections
- Additional:
- Product catalog
- Portfolio/gallery
- Multi-language beyond TH/EN
- E-commerce (Snipcart/Stripe)
- Base (always included):
-
Color Scheme/Branding:
- Primary color (hex)
- Secondary color (hex)
- Logo file (or generate placeholder)
-
Analytics Configuration:
- Umami Analytics (required for PDPA compliance)
- Umami Website ID (provide now or fill later in .env)
- Umami Domain (self-hosted or cloud)
-
Admin Credentials:
- Admin password for consent logs viewer (CHANGE THIS!)
- Default:
changeme(MUST change in production)
Phase 1: Discovery & Planning
Automated steps:
- Analyze Requirements - Map features to components
- Plan Structure - Define folder structure based on languages
- Check Compliance - Verify all PDPA requirements covered
- Create Timeline - Estimate build time (typically 5-10 min)
Phase 2: Setup & Generation
For New Website:
-
Create Project Structure
website-name/ ├── src/ │ ├── pages/ │ │ ├── en/ # English pages │ │ ├── th/ # Thai pages │ │ └── admin/ # Admin dashboard │ ├── components/ │ ├── layouts/ │ └── content/ ├── db/ # Astro DB schema ├── Dockerfile └── package.json -
Configure i18n Routing
- English default:
/about,/contact - Thai prefixed:
/th/about,/th/contact - Fallback: Thai → English for missing translations
- English default:
-
Install Dependencies
npm install astro @astrojs/db @astrojs/sitemap npm install astro-consent drizzle-orm @libsql/client npm install tailwindcss @tailwindcss/vite -
Add Base Features
- Cookie consent banner (astro-consent)
- Consent logging API endpoints
- Umami Analytics (conditional loading)
- Language switcher component
- PDPA-compliant Privacy Policy (TH/EN)
- PDPA-compliant Terms & Conditions (TH/EN)
For Redesign:
-
Crawl Original Website:
- Visit original URL
- Extract all pages, products, blog posts
- Download all images
- Preserve original URLs
- Create content summary document
- Save image file list for reference
-
Rebuild with Astro:
- Create matching route structure
- Migrate content to Markdown/Content Collections
- Preserve SEO data (meta titles, descriptions)
- Reuse downloaded images
- Add PDPA compliance features
For Refactor:
-
Backup Existing Content
- Export blog posts
- Export products
- Save custom pages
-
Apply New Structure
- Reorganize folders
- Add i18n routing
- Integrate consent system
- Add Umami Analytics
- Update Dockerfile
-
Migrate Content
- Move blog posts to content collections
- Preserve URLs (redirects if needed)
- Update internal links
Phase 3: Legal Pages Generation
PDPA-Compliant Privacy Policy (Section 36 Requirements):
- ✅ Data Controller Information
- ✅ Types of Data Collected
- ✅ Purpose of Data Processing
- ✅ Legal Basis for Processing
- ✅ Data Retention Period
- ✅ Data Sharing & Disclosure
- ✅ Cross-border Transfers (if applicable)
- ✅ Automated Decision Making (if applicable)
- ✅ Cookies & Tracking Technologies
- ✅ Data Subject Rights (8 PDPA rights)
- ✅ Data Security Measures
- ✅ DPO Contact (if applicable)
- ✅ Right to Lodge Complaint (PDPC)
- ✅ Policy Version & Last Updated
PDPA-Compliant Terms & Conditions:
- ✅ Acceptance of Terms
- ✅ Services Description
- ✅ Intellectual Property Rights
- ✅ User Obligations
- ✅ Limitation of Liability
- ✅ Termination Conditions
- ✅ Governing Law (Thailand)
- ✅ Dispute Resolution
- ✅ Modifications to Terms
- ✅ Contact Information
Language: Generated in Thai, English, or both based on configuration.
Phase 4: Cookie Consent Implementation
Consent Flow:
-
Banner Display (First Visit)
- Essential cookies: Always ON (cannot reject)
- Analytics cookies: Opt-in required
- Marketing cookies: Opt-in required
- Equal prominence: Accept | Reject | Customize
-
Consent Storage
- localStorage: User preferences
- Database: Audit trail (PDPA compliance)
- Session ID: Unique identifier
- Timestamp: When consent given
- Policy Version: Track which version accepted
-
Script Loading (Conditional)
if (consent.analytics) { // Load Umami Analytics } if (consent.marketing) { // Load marketing scripts } -
Withdrawal Mechanism
- Footer link: "Cookie Preferences"
- Modal: Re-open consent banner
- One-click withdrawal
- Immediate script unloading
Database Schema (ConsentLog - better-sqlite3):
{
id: number (PK, autoincrement),
sessionId: string (UNIQUE),
timestamp: datetime (ISO string),
essential: boolean (0/1),
analytics: boolean (0/1),
marketing: boolean (0/1),
policyVersion: string,
ipHash: string (SHA256, first 16 chars),
userAgent: string
}
Why better-sqlite3 instead of Astro DB?
- Astro DB cannot create new tables with remote SQLite (
ASTRO_DB_REMOTE_URL=file:...) - better-sqlite3 bypasses this limitation completely
- Auto-creates table on API startup (
CREATE TABLE IF NOT EXISTS)
Phase 5: Umami Analytics Integration
Configuration:
-
Umami Setup:
- Self-host on Easypanel (recommended)
- Or use Umami Cloud
- Create website in Umami dashboard
- Get Website ID
-
Integration:
<!-- Conditional loading in BaseLayout.astro --> <script is:inline> const consent = JSON.parse( localStorage.getItem('consent-preferences') || '{}' ); if (consent.analytics) { // Load Umami script const script = document.createElement('script'); script.defer = true; script.src = 'https://analytics.domain.com/script.js'; script.setAttribute('data-website-id', 'xxx-xxx-xxx'); document.head.appendChild(script); } </script> -
Privacy Features:
- No cookies used
- No fingerprinting
- No personal data collected
- GDPR/PDPA compliant out-of-the-box
- Self-hosted = data stays on your servers
Note: Umami does NOT require consent for basic analytics (no personal data). However, we still respect user choice and load conditionally.
Phase 6: Admin Dashboard
Consent Logs Viewer:
- URL:
/admin/consent-logs - Authentication: Simple password (env:
ADMIN_PASSWORD) - Features:
- View all consent records (last 100)
- Filter by date, locale, consent type
- Export to CSV
- Delete individual records (right to be forgotten)
- Search by session ID
Security:
- Change default password immediately
- Consider adding rate limiting
- Add IP whitelist for production
- Use HTTPS only
Phase 7: Docker Setup
Dockerfile (better-sqlite3):
FROM node:20-alpine
WORKDIR /app
# Install build dependencies for better-sqlite3 native module
RUN apk add --no-cache python3 make g++
# Install dependencies
COPY package*.json ./
RUN npm install
# Copy source
COPY . .
# Build
RUN npm run build
# Serve
EXPOSE 80
CMD ["npm", "run", "preview"]
Key differences from Astro DB approach:
- Uses
node:20-alpinewith build tools for native module compilation better-sqlite3creates SQLite file atdata/consent.dbautomatically- No
ASTRO_DB_REMOTE_URLneeded - bypasses Astro DB limitation
Test Locally:
docker build -t website:latest .
docker run -p 80:80 \
-e UMAMI_WEBSITE_ID=xxx \
-e ADMIN_PASSWORD=secure-pass \
website:latest
# Verify in browser: http://localhost
Phase 8: Git & Easypanel Deployment
Two deployment options:
Option A: Manual Easypanel Deployment (Current)
-
Create Gitea Repository:
- Use Gitea API at
git.moreminimore.com - Create repo with website name
- Push initial code
- Use Gitea API at
-
Use easypanel-deploy Skill:
/use easypanel-deploy deploy → Project name: {website-name} → Service name: {website-name}-service → Git URL: https://git.moreminimore.com/user/{website-name}.git → Branch: main → Port: 80 -
Verify Deployment:
/use easypanel-deploy status → Project name: {website-name} → Service name: {website-name}-service
Option B: Automatic Deployment (Future Enhancement)
The skill can be extended to call easypanel-deploy automatically via subprocess or task delegation. This would:
- Push code to Gitea automatically
- Call easypanel-deploy skill
- Return deployment URL to user
Implementation would require:
# In create_astro_website.py
def deploy_to_easypanel(project_name, service_name, git_url):
"""Deploy to Easypanel using easypanel-deploy skill."""
# Option 1: Call easypanel-deploy via task()
# Option 2: Execute curl commands directly
pass
Phase 9: Documentation
Generated Files:
-
DEPLOYMENT.md
- How Easypanel is configured
- Auto-deploy workflow
- Environment variables
- Database setup
- Umami configuration
-
CONTENT-GUIDE.md
- How to add blog posts (Markdown format)
- How to add products
- Image guidelines
- Bilingual content management
- AI blog writing guide
-
CHECKLIST.md
- Update workflow
- Testing steps
- Rollback procedure
- PDPA compliance checklist
-
PDPA-COMPLIANCE.md
- Privacy policy requirements
- Cookie consent implementation
- Consent logging
- Data subject rights procedures
- Breach notification process
-
README.md
- Quick start guide
- Development commands
- Project structure
- Tech stack
📁 Output Structure
website-name/
├── public/
│ ├── favicon.ico
│ ├── favicon.svg
│ └── images/
│
├── src/
│ ├── components/
│ │ ├── common/
│ │ │ ├── Header.astro
│ │ │ ├── Footer.astro
│ │ │ └── LanguageSwitcher.astro
│ │ ├── consent/
│ │ │ ├── CookieBanner.astro
│ │ │ └── ConsentPreferences.astro
│ │ └── ui/
│ │ ├── Button.astro
│ │ └── Card.astro
│ │
│ ├── layouts/
│ │ └── BaseLayout.astro
│ │
│ ├── pages/
│ │ ├── index.astro
│ │ ├── th/
│ │ │ ├── index.astro
│ │ │ ├── about.astro
│ │ │ ├── contact.astro
│ │ │ ├── privacy-policy.astro
│ │ │ ├── terms-and-conditions.astro
│ │ │ └── blog/
│ │ │ ├── index.astro
│ │ │ └── [slug].astro
│ │ ├── en/
│ │ │ ├── index.astro
│ │ │ ├── about.astro
│ │ │ ├── contact.astro
│ │ │ ├── privacy-policy.astro
│ │ │ ├── terms-and-conditions.astro
│ │ │ └── blog/
│ │ │ ├── index.astro
│ │ │ └── [slug].astro
│ │ └── admin/
│ │ └── consent-logs.astro
│ │
│ ├── pages/api/
│ │ └── consent/
│ │ ├── index.ts # GET, POST
│ │ └── [sessionId].ts # DELETE
│ │
│ ├── styles/
│ │ └── global.css
│ │
│ ├── content/
│ │ ├── blog/
│ │ │ ├── (th)/
│ │ │ └── (en)/
│ │ └── config.ts
│ │
│ ├── lib/
│ │ ├── i18n.ts
│ │ ├── consent.ts
│ │ └── db.ts # better-sqlite3 setup
│ │
│ └── middleware.ts
│
├── data/ # SQLite database (auto-created)
│ └── consent.db
│
├── Dockerfile
├── docker-compose.yml
├── package.json
├── astro.config.mjs
├── tailwind.config.mjs
├── tsconfig.json
├── .env.example
├── .gitignore
├── README.md
├── DEPLOYMENT.md
├── CONTENT-GUIDE.md
├── CHECKLIST.md
└── PDPA-COMPLIANCE.md
🔧 Tools Used
- Astro 5.x - Static site generator with i18n, hybrid rendering
- Tailwind CSS 4.x - Utility-first CSS framework
- better-sqlite3 - Direct SQLite for consent logging (bypasses Astro DB limitation)
- astro-consent - Cookie consent management
- Umami Analytics - Privacy-first web analytics
- Docker - Containerization (alpine for native module support)
- Gitea - Git repository (git.moreminimore.com)
- Easypanel - Deployment platform
🔐 Environment Variables
Required (set in .env):
# Umami Analytics
UMAMI_WEBSITE_ID=your-website-id-here
UMAMI_DOMAIN=analytics.example.com
# Admin
ADMIN_PASSWORD=change-this-secure-password
# Site Configuration
SITE_URL=https://example.com
SITE_NAME="Example Website"
Note: Database (SQLite) is created automatically at data/consent.db. No external database needed.
Security:
- NEVER commit
.envfile - Use
.env.exampleas template - Change
ADMIN_PASSWORDbefore deployment - Use strong passwords in production
📐 Typography Guidelines
CRITICAL: All websites MUST follow these guidelines for readability on big screens.
Desktop First Approach
html {
font-size: 18px; /* Base size - NOT 16px */
}
@media (min-width: 1280px) {
html { font-size: 20px; }
}
@media (min-width: 1536px) {
html { font-size: 22px; }
}
@media (min-width: 1920px) {
html { font-size: 24px; }
}
Minimum Font Sizes
| Element | Minimum Size | Tailwind Class |
|---|---|---|
| Body text | 18px (base) | text-base |
| Small text | 16px | text-sm (minimum!) |
| Large text | 20px | text-lg |
| XL text | 24px | text-xl |
What NOT to Use
❌ NEVER use:
text-xs(12px) - Too small!text-smwithout responsive increasefont-size: 14pxor smaller
✅ ALWAYS use:
text-baseminimum for body texttext-lgor larger for important content- Responsive increases:
text-base md:text-lg lg:text-xl
⚠️ Important Notes
- Hybrid Rendering - Static pages + server endpoints for API
- Database - better-sqlite3 (direct SQLite, auto-creates tables)
- Main Branch Only - Direct to production
- Auto-Deploy - Easypanel watches Git
- Markdown Content - Blog/posts as Markdown files
- Preserve URLs - For redesign, keep original URL structure
- PDPA Compliance - All legal pages include required disclosures
- Consent Logging - Audit trail for 10+ years (PDPA requirement)
- Right to be Forgotten - API endpoint for consent deletion
- Bilingual Default - Thai + English with fallback
- Docker Alpine - Uses alpine for better-sqlite3 native module compilation
🎯 Success Criteria
- ✅ Website builds locally (
npm run dev) - ✅ Docker build succeeds
- ✅ Gitea repo created
- ✅ Easypanel service created
- ✅ Auto-deploy enabled
- ✅ Website accessible via browser
- ✅ i18n routing works (TH/EN switch)
- ✅ Cookie consent appears on first visit
- ✅ Consent logged to database
- ✅ Umami loads only with consent
- ✅ Admin page accessible with password
- ✅ Privacy Policy PDPA-compliant
- ✅ Terms & Conditions PDPA-compliant
- ✅ Data deletion works (right to be forgotten)
- ✅ Documentation complete
🔄 Ongoing Maintenance
When user asks to:
- Add content → Create Markdown in correct language folder, commit, auto-deploy
- Fix bugs → Fix code, commit, auto-deploy
- Update design → Update components, commit, auto-deploy
- Update legal pages → Edit privacy-policy.astro / terms.astro, commit, auto-deploy
- View consent logs → Navigate to
/admin/consent-logs, login with password - Delete consent data → Use admin dashboard or call DELETE
/api/consent/{sessionId}
All updates automatic via Easypanel auto-deploy!
📋 PDPA Compliance Checklist
Before deployment, verify:
Privacy Policy
- Contains all 14 Section 36 disclosures
- Available in Thai (or bilingual)
- Accessible before data collection
- Version number and last updated date
- DPO contact (if applicable)
- Complaint process (PDPC)
Cookie Consent
- Opt-in model (not pre-ticked)
- Granular choices (essential/analytics/marketing)
- Equal prominence for Accept/Reject
- Withdrawal as easy as acceptance
- Script blocking until consent
- Consent recorded with timestamp
Consent Logging
- Database stores all consent records
- Session ID unique per user
- Policy version tracked
- IP hashed (not raw)
- Retention period defined (10+ years)
- Deletion mechanism exists
Data Subject Rights
- Right to access (provide data copy)
- Right to rectification (correct data)
- Right to erasure (delete data)
- Right to restrict processing
- Right to data portability
- Right to object
- Right to withdraw consent
- Process documented in admin guide
Security
- Admin password changed from default
- HTTPS enabled
- Rate limiting on API endpoints
- SQL injection prevention (using ORM)
- XSS prevention (Astro escapes by default)
🚀 Commands
Development
# Install dependencies
npm install
# Start dev server
npm run dev
# Build for production
npm run build
# Preview build
npm run preview
Production
# Docker build
docker build -t website:latest .
# Docker run
docker run -p 80:80 \
-e UMAMI_WEBSITE_ID=xxx \
-e ADMIN_PASSWORD=secure-pass \
website:latest
📞 Support
For issues:
- Check
PDPA-COMPLIANCE.mdfor legal requirements - Check
DEPLOYMENT.mdfor Easypanel setup - Check
CONTENT-GUIDE.mdfor content management - Review Astro DB docs for database issues
- Check Umami docs for analytics issues
Admin Dashboard:
- URL:
https://your-domain.com/admin/consent-logs - Default password:
changeme(CHANGE THIS!)
📝 Examples
Generate New Website
python3 scripts/create_astro_website.py \
--name "Deal Plus Tech" \
--type "corporate" \
--languages "th,en" \
--primary-color "#2563eb" \
--secondary-color "#1e40af" \
--features "blog,products,contact" \
--umami-id "xxx-xxx-xxx" \
--output "./dealplustech-website"
Workflow:
- Creates website locally
- Shows preview instructions (npm run dev)
- Asks: "Sync to Gitea and deploy?"
- No: Stay local, you're done
- Yes: Proceed with Gitea sync + Easypanel deploy
Refactor Existing Website
python3 scripts/refactor_website.py \
--input "./dealplustech-astro" \
--output "./dealplustech-astro-refactored" \
--add-features "i18n,consent,umami" \
--languages "th,en"
All websites created with this skill are PDPA-compliant, bilingual-ready, and production-ready for Thai market.