From 5053ccdba2927b19e1b202590e80467e6b400c52 Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Wed, 1 Apr 2026 18:36:51 +0700 Subject: [PATCH] feat(thai-frontend-dev): update consent system to better-sqlite3 - 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 --- skills/seo-utils-mcp-guide/SKILL.md | 67 ++++ skills/thai-frontend-dev/SKILL.md | 99 +++-- .../scripts/create_astro_website.py | 261 ++++++++++++- .../templates/admin-consent-logs.astro | 105 +++++- .../templates/thai-privacy-policy-template.md | 344 +++--------------- .../thai-terms-of-service-template.md | 162 +++------ 6 files changed, 539 insertions(+), 499 deletions(-) create mode 100644 skills/seo-utils-mcp-guide/SKILL.md diff --git a/skills/seo-utils-mcp-guide/SKILL.md b/skills/seo-utils-mcp-guide/SKILL.md new file mode 100644 index 0000000..62671ee --- /dev/null +++ b/skills/seo-utils-mcp-guide/SKILL.md @@ -0,0 +1,67 @@ +--- +name: seo-utils-mcp-guide +description: | + Background knowledge for using SEO Utils MCP tools correctly. Helps choose the right tool + (local database vs API) for SEO data queries. Use when: user asks about SEO data, rank tracker, + keyword research, GSC data, backlink analysis, or any SEO-related queries. +--- + +# SEO Utils MCP Tool Selection Guide + +When the user asks about SEO data, use this guide to pick the correct tool. + +## Rule 1: Local Data vs API Data + +The user has TWO types of SEO data: + +**Local database** (synced/tracked over time) — use `query_database` or `query_gsc`: +- Organic Rank Tracker reports → `organic_rank_tracker_*` tables +- Google Business Rank Tracker → `google_business_rank_tracker_*` tables +- Google Search Console data → `search_console_*` tables (use `query_gsc`) +- LLM Rank Tracker → `llm_rank_tracker_*` tables +- Content Struct outlines → `content_struct*` tables +- NLP Analysis → `nlp_analysis_*` tables +- NAP Finder → `nap_finder_*` tables +- Saved Keywords → `saved_keywords_*` tables +- Automations → `automations`, `automation_*` tables +- Indexing status → `site_urls`, `index_now_urls` tables +- Log Analysis → `log_analysis_*` tables +- SEO Tests → `tests`, `test_*` tables + +**DataForSEO API** (on-demand, third-party estimates) — use action tools: +- `get_keyword_suggestions` / `get_bing_related_keywords` — keyword research +- `get_organic_keywords` — what keywords a domain ranks for (estimated) +- `get_traffic_summary` / `get_historical_rank` — traffic estimates +- `get_traffic_competitors` / `get_top_pages` — competitor/page analysis +- `fetch_backlinks` / `get_backlink_summary` / etc. — backlink data +- `bulk_traffic_analysis` / `bulk_backlink_analysis` — multi-domain comparison +- `check_keyword_metrics` — search volume, KD, CPC +- `fetch_serp_data` — live SERP results + +## Rule 2: Common Mistakes to Avoid + +| User says | WRONG tool | CORRECT approach | +|-----------|-----------|-----------------| +| "rank tracker report" or "my rankings" | `get_organic_keywords` | `query_database` on `organic_rank_tracker_*` tables | +| "keyword cannibalization" | `get_organic_keywords` | `query_database` on `search_console_query_pages` | +| "trending queries" or "GSC data" | `get_organic_keywords` | `query_gsc` on `search_console_queries` | +| "my backlink history" | `fetch_backlinks` | Could be either — ask if they mean tracked data or fresh API data | +| "optimization opportunities" | `get_organic_keywords` | `query_database` on `search_console_query_pages` + `search_console_query_page_mentions` | +| "weak pages" or "low CTR pages" | `get_organic_keywords` | `query_gsc` on `search_console_pages` or `search_console_queries` | +| "my automations" | N/A | `query_database` on `automations` table | +| "content brief" or "content outline" | N/A | `query_database` on `content_struct_layout_headings` + `content_struct_layout_metadata` | + +## Rule 3: When to Use API Tools + +Use DataForSEO API action tools ONLY when: +- User asks about a **domain they don't track** (competitor research) +- User explicitly asks for **fresh/live data** from DataForSEO +- User wants **keyword suggestions** or **keyword metrics** for new keywords +- User wants **backlink data** for any domain +- User wants to **compare multiple domains** (bulk analysis) + +## Rule 4: Export and Send + +- `send_email` — send any email with SMTP. Check `smtp_credentials` table first +- Automations — use `create_automation` for recurring workflows (triggered by events) +- For one-time exports, generate the content and use `send_email` to deliver it diff --git a/skills/thai-frontend-dev/SKILL.md b/skills/thai-frontend-dev/SKILL.md index c043ad8..59ac62a 100644 --- a/skills/thai-frontend-dev/SKILL.md +++ b/skills/thai-frontend-dev/SKILL.md @@ -22,7 +22,7 @@ Create and deploy **PDPA-compliant** Astro websites on Easypanel automatically w - ✅ **Bilingual support** (Thai/English) - ✅ **Umami Analytics** (privacy-first, no cookies) - ✅ **Cookie consent management** (astro-consent) -- ✅ **Consent logging database** (Astro DB + Turso) +- ✅ **Consent logging database** (better-sqlite3 - direct SQLite, bypasses Astro DB limitation) - ✅ **PDPA-compliant legal pages** (Privacy Policy, Terms) - ✅ **Easypanel deployment** (Docker, auto-deploy) @@ -256,22 +256,26 @@ Create and deploy **PDPA-compliant** Astro websites on Easypanel automatically w - One-click withdrawal - Immediate script unloading -**Database Schema (ConsentLog):** +**Database Schema (ConsentLog - better-sqlite3):** ```typescript { - id: number (PK), - sessionId: string (unique), - timestamp: datetime, - locale: 'en' | 'th', - essential: boolean, - analytics: boolean, - marketing: boolean, + 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 @@ -336,34 +340,36 @@ Create and deploy **PDPA-compliant** Astro websites on Easypanel automatically w ### Phase 7: Docker Setup -**Dockerfile:** +**Dockerfile (better-sqlite3):** ```dockerfile -FROM node:20-alpine AS builder +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 ci +RUN npm install + +# Copy source COPY . . + +# Build RUN npm run build -FROM node:20-alpine -WORKDIR /app -COPY package*.json ./ -RUN npm ci --production -COPY --from=builder /app/dist ./dist -COPY --from=builder /app/db ./db - -# SQLite runtime -RUN apk add --no-cache sqlite-libs - +# Serve EXPOSE 80 - -ENV NODE_ENV=production -ENV ASTRO_DB_REMOTE_URL=file:/app/data/consent.db - -CMD ["sh", "-c", "mkdir -p /app/data && npx astro preview --host 0.0.0.0 --port 80"] +CMD ["npm", "run", "preview"] ``` +**Key differences from Astro DB approach:** +- Uses `node:20-alpine` with build tools for native module compilation +- `better-sqlite3` creates SQLite file at `data/consent.db` automatically +- No `ASTRO_DB_REMOTE_URL` needed - bypasses Astro DB limitation + **Test Locally:** ```bash @@ -513,9 +519,8 @@ website-name/ │ │ │ ├── pages/api/ │ │ └── consent/ -│ │ ├── POST.ts -│ │ ├── GET.ts -│ │ └── [sessionId]/DELETE.ts +│ │ ├── index.ts # GET, POST +│ │ └── [sessionId].ts # DELETE │ │ │ ├── styles/ │ │ └── global.css @@ -529,13 +534,12 @@ website-name/ │ ├── lib/ │ │ ├── i18n.ts │ │ ├── consent.ts -│ │ └── utils.ts +│ │ └── db.ts # better-sqlite3 setup │ │ │ └── middleware.ts │ -├── db/ -│ ├── config.ts -│ └── seed.ts +├── data/ # SQLite database (auto-created) +│ └── consent.db │ ├── Dockerfile ├── docker-compose.yml @@ -558,11 +562,10 @@ website-name/ - **Astro 5.x** - Static site generator with i18n, hybrid rendering - **Tailwind CSS 4.x** - Utility-first CSS framework -- **Astro DB** - SQLite database for consent logging -- **Turso** - Managed libSQL for production (optional) +- **better-sqlite3** - Direct SQLite for consent logging (bypasses Astro DB limitation) - **astro-consent** - Cookie consent management - **Umami Analytics** - Privacy-first web analytics -- **Docker** - Containerization +- **Docker** - Containerization (alpine for native module support) - **Gitea** - Git repository (git.moreminimore.com) - **Easypanel** - Deployment platform @@ -580,15 +583,13 @@ UMAMI_DOMAIN=analytics.example.com # Admin ADMIN_PASSWORD=change-this-secure-password -# Database (optional - defaults to SQLite file) -ASTRO_DB_REMOTE_URL=libsql://your-db.turso.io -ASTRO_DB_APP_TOKEN=your-turso-token - # 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 `.env` file - Use `.env.example` as template @@ -647,7 +648,7 @@ html { ## ⚠️ Important Notes 1. **Hybrid Rendering** - Static pages + server endpoints for API -2. **Database** - SQLite file (dev) → Turso (production, optional) +2. **Database** - better-sqlite3 (direct SQLite, auto-creates tables) 3. **Main Branch Only** - Direct to production 4. **Auto-Deploy** - Easypanel watches Git 5. **Markdown Content** - Blog/posts as Markdown files @@ -656,6 +657,7 @@ html { 8. **Consent Logging** - Audit trail for 10+ years (PDPA requirement) 9. **Right to be Forgotten** - API endpoint for consent deletion 10. **Bilingual Default** - Thai + English with fallback +11. **Docker Alpine** - Uses alpine for better-sqlite3 native module compilation --- @@ -757,23 +759,11 @@ npm run build # Preview build npm run preview - -# Push DB schema (development) -npm run db:push - -# Seed development data -npm run db:seed ``` ### Production ```bash -# Build with remote database -npm run build --remote - -# Push DB schema to Turso -npm run db:push --remote - # Docker build docker build -t website:latest . @@ -781,7 +771,6 @@ docker build -t website:latest . docker run -p 80:80 \ -e UMAMI_WEBSITE_ID=xxx \ -e ADMIN_PASSWORD=secure-pass \ - -e ASTRO_DB_REMOTE_URL=file:/app/data/consent.db \ website:latest ``` diff --git a/skills/thai-frontend-dev/scripts/create_astro_website.py b/skills/thai-frontend-dev/scripts/create_astro_website.py index 0d54eab..36811b7 100644 --- a/skills/thai-frontend-dev/scripts/create_astro_website.py +++ b/skills/thai-frontend-dev/scripts/create_astro_website.py @@ -193,7 +193,6 @@ def ask_analytics_setup(): ASTRO_CONFIG_TEMPLATE = """import {{ defineConfig }} from 'astro/config'; import tailwindcss from '@tailwindcss/vite'; -import db from '@astrojs/db'; import sitemap from '@astrojs/sitemap'; export default defineConfig({{ @@ -212,13 +211,22 @@ export default defineConfig({{ }}, integrations: [ tailwindcss(), - db(), sitemap({{ i18n: {{ defaultLocale: '{default_locale}', }}, }}), ], + vite: {{ + optimizeDeps: {{ + exclude: ['better-sqlite3'] + }}, + build: {{ + rollupOptions: {{ + external: ['better-sqlite3'] + }} + }} + }} }}); """ @@ -228,25 +236,217 @@ PACKAGE_JSON_TEMPLATE = """{{ "version": "1.0.0", "scripts": {{ "dev": "astro dev", - "build": "astro build --remote", + "build": "astro build", "preview": "astro preview", - "astro": "astro", - "db:push": "astro db push --remote", - "db:seed": "astro db seed" + "astro": "astro" }}, "dependencies": {{ "astro": "^5.17.1", - "@astrojs/db": "^0.14.0", "@astrojs/sitemap": "^3.2.0", "@tailwindcss/vite": "^4.2.1", "tailwindcss": "^4.2.1", - "astro-consent": "^1.0.0", - "drizzle-orm": "^0.38.0", - "@libsql/client": "^0.14.0" + "better-sqlite3": "^11.0.0" + }}, + "devDependencies": {{ + "@types/better-sqlite3": "^7.6.8" }} }} """ +# ============================================================================== +# CONSENT API TEMPLATES (using better-sqlite3 directly) +# ============================================================================== + +CONSENT_DB_TEMPLATE = """import Database from 'better-sqlite3'; +import {{ join }} from 'path'; +import {{ mkdirSync, existsSync }} from 'fs'; + +const DATA_DIR = join(process.cwd(), 'data'); +const DB_PATH = join(DATA_DIR, 'consent.db'); + +export function getDb() {{ + // 1. Create directory if not exists + if (!existsSync(DATA_DIR)) {{ + mkdirSync(DATA_DIR, {{ recursive: true }}); + }} + + // 2. Open database + const db = new Database(DB_PATH); + + // 3. Auto-create table (works with remote SQLite!) + db.exec(` + CREATE TABLE IF NOT EXISTS ConsentLog ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + sessionId TEXT UNIQUE NOT NULL, + timestamp TEXT NOT NULL, + essential INTEGER NOT NULL DEFAULT 0, + analytics INTEGER NOT NULL DEFAULT 0, + marketing INTEGER NOT NULL DEFAULT 0, + policyVersion TEXT NOT NULL, + ipHash TEXT, + userAgent TEXT + ) + `); + + return db; +}} + +// Rate limiting map +const rateLimitMap = new Map(); +const RATE_LIMIT = 10; +const RATE_WINDOW = 60000; // 1 minute + +export function checkRateLimit(ip: string): boolean {{ + const now = Date.now(); + const record = rateLimitMap.get(ip); + + if (!record || now > record.resetTime) {{ + rateLimitMap.set(ip, {{ count: 1, resetTime: now + RATE_WINDOW }}); + return true; + }} + + if (record.count >= RATE_LIMIT) {{ + return false; + }} + + record.count++; + return true; +}} + +// IP Hashing for privacy (GDPR compliance) +export async function hashIP(ip: string): Promise {{ + try {{ + if (crypto.subtle) {{ + const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(ip)); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); + return hashHex.substring(0, 16); + }} + }} catch {{}} + return `fallback-${Date.now()}`; +}} +""" + +CONSENT_API_INDEX_TEMPLATE = """import type {{ APIRoute }} from 'astro'; +import {{ getDb, checkRateLimit, hashIP }} from '../../../../lib/db'; + +export const GET: APIRoute = async ({{ clientAddress }}) => {{ + // Rate limit check + const ip = clientAddress || 'unknown'; + if (!checkRateLimit(ip)) {{ + return new Response( + JSON.stringify({{ error: 'Rate limit exceeded' }}), + {{ status: 429, headers: {{ 'Content-Type': 'application/json' }} }} + ); + }} + + try {{ + const db = getDb(); + const logs = db.prepare(` + SELECT * FROM ConsentLog + ORDER BY timestamp DESC + LIMIT 100 + `).all(); + db.close(); + + return new Response( + JSON.stringify({{ logs }}), + {{ status: 200, headers: {{ 'Content-Type': 'application/json' }} }} + ); + }} catch (error) {{ + return new Response( + JSON.stringify({{ error: 'Failed to fetch logs' }}), + {{ status: 500 }} + ); + }} +}}; + +export const POST: APIRoute = async ({{ request, clientAddress }}) => {{ + try {{ + const body = await request.json(); + const {{ sessionId, essential, analytics, marketing, policyVersion, userAgent }} = body; + + // Validate required fields + if (!sessionId || essential === undefined || !policyVersion) {{ + return new Response( + JSON.stringify({{ error: 'Missing required fields' }}), + {{ status: 400, headers: {{ 'Content-Type': 'application/json' }} }} + ); + }} + + const db = getDb(); + const ipHash = await hashIP(clientAddress || 'unknown'); + const timestamp = new Date().toISOString(); + + // Insert with prepared statement (prevents SQL injection) + const stmt = db.prepare(` + INSERT INTO ConsentLog (sessionId, timestamp, essential, analytics, marketing, policyVersion, ipHash, userAgent) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `); + stmt.run( + sessionId, + timestamp, + essential ? 1 : 0, + analytics ? 1 : 0, + marketing ? 1 : 0, + policyVersion, + ipHash, + userAgent || 'unknown' + ); + db.close(); + + return new Response( + JSON.stringify({{ success: true, sessionId }}), + {{ status: 201, headers: {{ 'Content-Type': 'application/json' }} }} + ); + }} catch (error) {{ + return new Response( + JSON.stringify({{ error: 'Failed to log consent' }}), + {{ status: 500 }} + ); + }} +}}; +""" + +CONSENT_API_DELETE_TEMPLATE = """import type {{ APIRoute }} from 'astro'; +import {{ getDb }} from '../../../../lib/db'; + +export const DELETE: APIRoute = async ({{ params }}) => {{ + const {{ sessionId }} = params; + + if (!sessionId) {{ + return new Response( + JSON.stringify({{ error: 'Session ID required' }}), + {{ status: 400, headers: {{ 'Content-Type': 'application/json' }} }} + ); + }} + + try {{ + const db = getDb(); + const stmt = db.prepare('DELETE FROM ConsentLog WHERE sessionId = ?'); + const result = stmt.run(sessionId); + db.close(); + + if (result.changes === 0) {{ + return new Response( + JSON.stringify({{ error: 'Record not found' }}), + {{ status: 404 }} + ); + }} + + return new Response( + JSON.stringify({{ success: true }}), + {{ status: 200, headers: {{ 'Content-Type': 'application/json' }} }} + ); + }} catch (error) {{ + return new Response( + JSON.stringify({{ error: 'Failed to delete' }}), + {{ status: 500 }} + ); + }} +}}; +""" + # ... (rest of templates remain the same) @@ -506,10 +706,12 @@ def create_project(args, languages, default_locale, features): output_path / "src" / "layouts", output_path / "src" / "pages", output_path / "src" / "pages" / default_locale, + output_path / "src" / "pages" / "admin", + output_path / "src" / "pages" / "api" / "consent", output_path / "src" / "styles", output_path / "src" / "content" / "blog", output_path / "src" / "lib", - output_path / "db", + output_path / "data", ] for d in dirs: @@ -636,11 +838,42 @@ import Footer from '../components/common/Footer.astro'; print(" ✓ Basic pages created") - # Create Dockerfile - dockerfile = f"""FROM node:20-slim + # Create consent API with better-sqlite3 (bypasses Astro DB limitation) + lib_db_content = CONSENT_DB_TEMPLATE + (output_path / "src" / "lib" / "db.ts").write_text(lib_db_content, encoding="utf-8") + print(" ✓ Consent database library created (better-sqlite3)") + + # Create consent API endpoints + consent_index = CONSENT_API_INDEX_TEMPLATE + (output_path / "src" / "pages" / "api" / "consent" / "index.ts").write_text( + consent_index, encoding="utf-8" + ) + + consent_delete = CONSENT_API_DELETE_TEMPLATE + consent_delete = consent_delete.replace("{{", "{").replace("}}", "}") + consent_delete = consent_delete.replace("[sessionId]", "[sessionId]") + (output_path / "src" / "pages" / "api" / "consent" / "[sessionId].ts").write_text( + consent_delete, encoding="utf-8" + ) + print(" ✓ Consent API endpoints created") + + # Create admin consent logs page + admin_consent_src = template_dir / "admin-consent-logs.astro" + if admin_consent_src.exists(): + shutil.copy( + admin_consent_src, + output_path / "src" / "pages" / "admin" / "consent-logs.astro", + ) + print(" ✓ Admin consent logs page copied") + + # Create Dockerfile (using alpine for better-sqlite3 native module support) + dockerfile = f"""FROM node:20-alpine WORKDIR /app +# Install build dependencies for better-sqlite3 +RUN apk add --no-cache python3 make g++ + # Install dependencies COPY package*.json ./ RUN npm install @@ -656,7 +889,7 @@ EXPOSE 80 CMD ["npm", "run", "preview"] """ (output_path / "Dockerfile").write_text(dockerfile, encoding="utf-8") - print(" ✓ Dockerfile created") + print(" ✓ Dockerfile created (alpine for better-sqlite3)") # Create .gitignore gitignore = """# Dependencies diff --git a/skills/thai-frontend-dev/scripts/templates/admin-consent-logs.astro b/skills/thai-frontend-dev/scripts/templates/admin-consent-logs.astro index 6818b75..1ec43b1 100644 --- a/skills/thai-frontend-dev/scripts/templates/admin-consent-logs.astro +++ b/skills/thai-frontend-dev/scripts/templates/admin-consent-logs.astro @@ -1,8 +1,7 @@ --- // Password-protected admin page for viewing consent logs -import { db, ConsentLog, desc } from 'astro:db'; +// Uses API instead of Astro DB (better-sqlite3) to bypass remote SQLite limitation -// Simple password protection (in production, use proper auth) const ADMIN_PASSWORD = Astro.env.ADMIN_PASSWORD || 'changeme'; let logs = []; @@ -16,9 +15,11 @@ if (Astro.request.method === 'POST') { if (password === ADMIN_PASSWORD) { isAuthenticated = true; try { - logs = await db.select().from(ConsentLog).orderBy(desc(ConsentLog.timestamp)).limit(100); + const response = await fetch('/api/consent'); + const data = await response.json(); + logs = data.logs || []; } catch (err) { - error = 'Failed to load consent logs. Make sure database is initialized.'; + error = 'Failed to load consent logs. Make sure the API is running.'; console.error(err); } } else { @@ -27,7 +28,7 @@ if (Astro.request.method === 'POST') { } --- - + @@ -134,6 +135,8 @@ if (Astro.request.method === 'POST') { } .actions { margin-bottom: 1rem; + display: flex; + gap: 1rem; } .btn { display: inline-block; @@ -150,6 +153,15 @@ if (Astro.request.method === 'POST') { .btn-primary:hover { background: #1d4ed8; } + .btn-success { + background: #16a34a; + color: white; + border: none; + cursor: pointer; + } + .btn-success:hover { + background: #15803d; + } .btn-danger { background: #dc2626; color: white; @@ -174,6 +186,24 @@ if (Astro.request.method === 'POST') { background: #fee2e2; color: #dc2626; } + .info-box { + margin-top: 1rem; + padding: 1rem; + background: #fef3c7; + border-radius: 0.375rem; + } + .info-box h3 { + font-size: 0.875rem; + font-weight: 600; + margin-bottom: 0.5rem; + color: #92400e; + } + .info-box ul { + font-size: 0.75rem; + color: #92400e; + list-style: disc; + padding-left: 1.5rem; + } @@ -182,7 +212,7 @@ if (Astro.request.method === 'POST') { {!isAuthenticated ? ( ) : (
-
+
Refresh + ← Back to Site
@@ -215,7 +246,6 @@ if (Astro.request.method === 'POST') { Date/Time - Locale Session ID Essential Analytics @@ -228,15 +258,14 @@ if (Astro.request.method === 'POST') { {logs.length === 0 ? ( - + No consent logs found. Make sure the website has received consent. ) : ( logs.map((log) => ( - {new Date(log.timestamp).toLocaleString('en-GB')} - {log.locale.toUpperCase()} + {new Date(log.timestamp).toLocaleString('th-TH')} {log.sessionId} {log.essential ? 'Yes' : 'No'} @@ -273,13 +302,13 @@ if (Astro.request.method === 'POST') {
-
-

⚠️ Important Notes:

-
    -
  • Consent records must be retained for 10 years (PDPA requirement)
  • +
    +

    ⚠️ Important Notes (PDPA Compliance):

    +
      +
    • Consent records must be retained for 10 years
    • Only delete records when user exercises "right to be forgotten"
    • -
    • Document all deletions for compliance audit
    • -
    • IP addresses are hashed for privacy protection
    • +
    • IP addresses are hashed (SHA-256, first 16 chars) for privacy
    • +
    • Rate limiting: 10 requests/minute per IP
@@ -308,6 +337,46 @@ if (Astro.request.method === 'POST') { alert('Error deleting consent record'); } } + + async function exportCSV() { + try { + const response = await fetch('/api/consent'); + const data = await response.json(); + const logs = data.logs || []; + + const headers = ['วันที่/เวลา', 'Session ID', 'Essential', 'Analytics', 'Marketing', 'Policy Version', 'IP Hash', 'User Agent']; + const csvRows = [headers.join(',')]; + + for (const log of logs) { + const row = [ + new Date(log.timestamp).toLocaleString('th-TH'), + log.sessionId, + log.essential ? 'Yes' : 'No', + log.analytics ? 'Yes' : 'No', + log.marketing ? 'Yes' : 'No', + log.policyVersion, + log.ipHash || '', + (log.userAgent || '').replace(/,/g, ';') + ]; + csvRows.push(row.join(',')); + } + + // UTF-8 BOM for Excel compatibility + const csvContent = '\ufeff' + csvRows.join('\n'); + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); + const url = URL.createObjectURL(blob); + + const link = document.createElement('a'); + link.href = url; + link.download = `consent-logs-${new Date().toISOString().split('T')[0]}.csv`; + link.click(); + + URL.revokeObjectURL(url); + } catch (error) { + console.error('Export error:', error); + alert('Failed to export CSV'); + } + } diff --git a/skills/thai-frontend-dev/scripts/templates/thai-privacy-policy-template.md b/skills/thai-frontend-dev/scripts/templates/thai-privacy-policy-template.md index 420534e..edc1f8d 100644 --- a/skills/thai-frontend-dev/scripts/templates/thai-privacy-policy-template.md +++ b/skills/thai-frontend-dev/scripts/templates/thai-privacy-policy-template.md @@ -1,12 +1,12 @@ # นโยบายความเป็นส่วนตัว (Privacy Policy) -**ชื่อเว็บไซต์:** [WEBSITE_NAME] -**มีผลบังคับใช้วันที่:** [DATE] -**แก้ไขล่าสุด:** [DATE] +**ชื่อเว็บไซต์:** {SITE_NAME} +**มีผลบังคับใช้วันที่:** {EFFECTIVE_DATE} +**แก้ไขล่าสุด:** {LAST_UPDATED} ## 1. บทนำ -บริษัท [COMPANY_NAME] ("เรา", "ของเรา" หรือ "บริษัท") ให้คำมั่นสัญญาที่จะปกป้องข้อมูลส่วนบุคคลของผู้ใช้บริการ ("ผู้ใช้", "ของคุณ" หรือ "ท่าน") ที่ใช้งานเว็บไซต์ [WEBSITE_URL] ("เว็บไซต์") นโยบายความเป็นส่วนตัวฉบับนี้อธิบายถึงวิธีการเก็บรวบรวม ใช้ เปิดเผย และคุ้มครองข้อมูลส่วนบุคคลของท่าน +บริษัท {COMPANY_NAME} ("เรา", "ของเรา" หรือ "บริษัท") ให้คำมั่นสัญญาที่จะปกป้องข้อมูลส่วนบุคคลของผู้ใช้บริการ ("ผู้ใช้", "ของคุณ" หรือ "ท่าน") ที่ใช้งานเว็บไซต์ {SITE_URL} ("เว็บไซต์") นโยบายความเป็นส่วนตัวฉบับนี้อธิบายถึงวิธีการเก็บรวบรวม ใช้ เปิดเผย และคุ้มครองข้อมูลส่วนบุคคลของท่าน นโยบายนี้จัดทำขึ้นตามกฎหมายคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 (PDPA) และกฎหมายที่เกี่ยวข้องของประเทศไทย @@ -32,11 +32,6 @@ - ข้อมูลบัญชีธนาคาร - ประวัติการทำธุรกรรม -**ข้อมูลอื่นๆ:** -- ความคิดเห็น ข้อเสนอแนะ -- แบบสำรวจความพึงพอใจ -- เนื้อหาที่ท่านส่งมา - ### 2.2 ข้อมูลที่เก็บรวบรวมโดยอัตโนมัติ เมื่อท่านใช้งานเว็บไซต์ เราอาจเก็บรวบรวมข้อมูลต่อไปนี้โดยอัตโนมัติ: @@ -54,329 +49,106 @@ - ลิงก์ที่ท่านคลิก - ข้อมูล Cookie -**ข้อมูลตำแหน่ง:** -- ข้อมูลตำแหน่งทางภูมิศาสตร์ (หากท่านอนุญาต) - ## 3. วัตถุประสงค์ในการใช้ข้อมูล เราใช้ข้อมูลส่วนบุคคลของท่านเพื่อวัตถุประสงค์ดังต่อไปนี้: -### 3.1 การให้บริการ - - ให้บริการและบำรุงรักษาเว็บไซต์ - ประมวลผลคำขอและธุรกรรมของท่าน - ส่งมอบสินค้าหรือบริการที่ท่านสั่งซื้อ - จัดการบัญชีผู้ใช้ของท่าน - -### 3.2 การสื่อสาร - - ตอบกลับคำถามและข้อร้องเรียน - ส่งข้อมูลเกี่ยวกับบริการของเรา - แจ้งเตือนเกี่ยวกับการอัปเดตหรือการเปลี่ยนแปลง - ส่งข่าวสารโปรโมชั่น (หากท่านยินยอม) - -### 3.3 การปรับปรุงบริการ - -- วิเคราะห์การใช้งานเว็บไซต์ -- พัฒนาและปรับปรุงบริการ -- ทดสอบฟีเจอร์ใหม่ -- วิจัยตลาด - -### 3.4 ความปลอดภัย - +- วิเคราะห์การใช้งานเว็บไซต์และปรับปรุงบริการ - ระบุและป้องกันภัยคุกคามด้านความปลอดภัย -- ตรวจสอบกิจกรรมที่อาจเป็นการฉ้อโกง -- บังคับใช้นโยบายและข้อกำหนดของเรา - ปฏิบัติตามข้อกำหนดทางกฎหมาย -### 3.5 ตามกฎหมาย - -- ปฏิบัติตามภาระผูกพันทางกฎหมาย -- ตอบสนองต่อคำขอจากหน่วยงานราชการ -- ป้องกันสิทธิและทรัพย์สินของเรา -- ป้องกันอันตรายต่อสาธารณะ - ## 4. ฐานทางกฎหมายในการประมวลผลข้อมูล เราประมวลผลข้อมูลส่วนบุคคลของท่านบนฐานทางกฎหมายดังต่อไปนี้: -### 4.1 ความยินยอม (Consent) - -ท่านได้ให้ความยินยอมให้เราประมวลผลข้อมูลส่วนบุคคลของท่านเพื่อวัตถุประสงค์เฉพาะ เช่น: -- การส่งข่าวสารทางอีเมล -- การใช้ Cookie สำหรับการตลาด -- การเก็บข้อมูลสุขภาพหรือข้อมูลอ่อนไหวอื่นๆ - -### 4.2 การปฏิบัติตามสัญญา (Contract) - -การประมวลผลจำเป็นสำหรับการปฏิบัติตามสัญญาที่ท่านทำกับเรา เช่น: -- การประมวลผลการสั่งซื้อ -- การให้บริการที่ท่านร้องขอ -- การจัดการบัญชีผู้ใช้ - -### 4.3 หน้าที่ทางกฎหมาย (Legal Obligation) - -การประมวลผลจำเป็นเพื่อปฏิบัติตามภาระผูกพันทางกฎหมาย เช่น: -- การเก็บรักษาบันทึกทางการเงิน -- การรายงานต่อหน่วยงานราชการ -- การปฏิบัติตามคำสั่งศาล - -### 4.4 ผลประโยชน์โดยชอบด้วยกฎหมาย (Legitimate Interest) - -การประมวลผลจำเป็นเพื่อประโยชน์โดยชอบด้วยกฎหมายของเรา เช่น: -- การป้องกันและการตรวจสอบการฉ้อโกง -- ความปลอดภัยของเครือข่ายและข้อมูล -- การปรับปรุงบริการ +- **ความยินยอม (Consent):** การส่งข่าวสารทางอีเมล, การใช้ Cookie สำหรับการตลาด +- **การปฏิบัติตามสัญญา (Contract):** การประมวลผลการสั่งซื้อ, การให้บริการที่ท่านร้องขอ +- **หน้าที่ทางกฎหมาย (Legal Obligation):** การเก็บรักษาบันทึกทางการเงิน, การรายงานต่อหน่วยงานราชการ +- **ผลประโยชน์โดยชอบด้วยกฎหมาย (Legitimate Interest):** การป้องกันและตรวจสอบการฉ้อโกง, ความปลอดภัยของเครือข่าย ## 5. การเปิดเผยข้อมูลให้กับบุคคลที่สาม เราไม่ขายหรือให้เช่าข้อมูลส่วนบุคคลของท่านให้กับบุคคลที่สาม อย่างไรก็ตาม เราอาจเปิดเผยข้อมูลของท่านในกรณีต่อไปนี้: -### 5.1 ผู้ให้บริการ (Service Providers) - -เราอาจแบ่งปันข้อมูลกับผู้ให้บริการที่ช่วยเราดำเนินธุรกิจ: -- **ผู้ให้บริการชำระเงิน:** เช่น ธนาคาร, ผู้ให้บริการบัตรเครดิต -- **ผู้ให้บริการจัดส่ง:** เช่น ไปรษณีย์ไทย, Kerry, Flash Express -- **ผู้ให้บริการคลาวด์:** เช่น AWS, Google Cloud, Azure -- **ผู้ให้บริการอีเมล:** เช่น SendGrid, Mailchimp -- **ผู้ให้บริการวิเคราะห์ข้อมูล:** เช่น Google Analytics - -### 5.2 หน่วยงานราชการ - -เราอาจเปิดเผยข้อมูลเมื่อได้รับคำสั่งตามกฎหมาย: -- ศาลหรือกระบวนการยุติธรรม -- หน่วยงานบังคับใช้กฎหมาย -- หน่วยงานกำกับดูแล -- หน่วยงานภาษี - -### 5.3 การโอนกิจการ - -ในกรณีที่มีการควบรวมกิจการ ขายทรัพย์สิน หรือการโอนกิจการ ข้อมูลของท่านอาจถูกโอนไปยังผู้ซื้อหรือผู้รับโอน - -### 5.4 เพื่อปกป้องสิทธิ - -เราอาจเปิดเผยข้อมูลเพื่อ: -- ปกป้องสิทธิ ทรัพย์สิน หรือความปลอดภัยของเรา -- ป้องกันการฉ้อโกง -- ปฏิบัติตามข้อกำหนดการใช้งาน +- **ผู้ให้บริการ:** ผู้ให้บริการชำระเงิน, ผู้ให้บริการจัดส่ง, ผู้ให้บริการคลาวด์, ผู้ให้บริการอีเมล, ผู้ให้บริการวิเคราะห์ข้อมูล +- **หน่วยงานราชการ:** ศาล, หน่วยงานบังคับใช้กฎหมาย, หน่วยงานกำกับดูแล, หน่วยงานภาษี +- **การโอนกิจการ:** กรณีควบรวมกิจการหรือขายทรัพย์สิน ## 6. การเก็บรักษาข้อมูล -เราเก็บรักษาข้อมูลส่วนบุคคลของท่านไว้เฉพาะเท่าที่จำเป็นเพื่อวัตถุประสงค์ที่ระบุไว้ในนโยบายนี้: +เราเก็บรักษาข้อมูลส่วนบุคคลของท่านไว้เฉพาะเท่าที่จำเป็น: -### 6.1 ระยะเวลาการเก็บรักษา - -- **ข้อมูลบัญชีผู้ใช้:** เก็บรักษาตราบเท่าที่ท่านเป็นผู้ใช้บริการ และ 3 ปีหลังจากนั้น -- **ข้อมูลธุรกรรม:** 5 ปี ตามข้อกำหนดของกฎหมายภาษี -- **ข้อมูลการติดต่อ:** 2 ปีหลังจากการติดต่อล่าสุด +- **ข้อมูลบัญชีผู้ใช้:** เก็บรักษาตลาบเท่าที่ท่านเป็นผู้ใช้บริการ และ {DATA_RETENTION_CUSTOMER_YEARS} ปีหลังจากนั้น +- **ข้อมูลธุรกรรม:** {DATA_RETENTION_PAYMENT_YEARS} ปี ตามข้อกำหนดของกฎหมายภาษี +- **ข้อมูลการติดต่อ:** {DATA_RETENTION_CONTACT_YEARS} ปีหลังจากการติดต่อล่าสุด - **ข้อมูล Cookie:** ตามการตั้งค่า Cookie ของท่าน -### 6.2 การทำลายข้อมูล - -เมื่อไม่จำเป็นต้องเก็บรักษาข้อมูลต่อไป เราจะ: -- ลบข้อมูลจากระบบอิเล็กทรอนิกส์ -- ทำลายเอกสารที่เป็นกระดาษ -- ทำให้ข้อมูลไม่สามารถระบุตัวตนได้ - ## 7. สิทธิของท่าน ภายใต้ PDPA ท่านมีสิทธิดังต่อไปนี้เกี่ยวกับข้อมูลส่วนบุคคลของท่าน: -### 7.1 สิทธิในการเข้าถึง (Right to Access) - -ท่านมีสิทธิขอเข้าถึงข้อมูลส่วนบุคคลที่ท่านเป็นเจ้าของ: -- ขอสำเนาข้อมูลส่วนบุคคล -- ทราบวัตถุประสงค์ของการประมวลผล -- ทราบแหล่งที่มาของข้อมูล - -### 7.2 สิทธิในการแก้ไข (Right to Rectification) - -ท่านมีสิทธิขอให้แก้ไขข้อมูลส่วนบุคคลที่ไม่ถูกต้อง: -- แก้ไขข้อมูลการติดต่อ -- อัปเดตข้อมูลบัญชี -- แก้ไขข้อมูลอื่นๆ - -### 7.3 สิทธิในการลบ (Right to Erasure) - -ท่านมีสิทธิขอให้ลบข้อมูลส่วนบุคคลในกรณีต่อไปนี้: -- ข้อมูลไม่จำเป็นต้องใช้แล้ว -- ท่านถอนความยินยอม -- ข้อมูลถูกประมวลผลโดยมิชอบด้วยกฎหมาย - -### 7.4 สิทธิในการจำกัดการประมวลผล (Right to Restriction) - -ท่านมีสิทธิขอให้จำกัดการประมวลผลข้อมูล: -- ขณะตรวจสอบความถูกต้องของข้อมูล -- เมื่อการประมวลผลเป็นการมิชอบด้วยกฎหมาย -- เมื่อเราไม่จำเป็นต้องใช้ข้อมูลแล้ว แต่ท่านต้องการให้เก็บไว้เพื่อการใช้สิทธิทางกฎหมาย - -### 7.5 สิทธิในการคัดค้าน (Right to Object) - -ท่านมีสิทธิคัดค้านการประมวลผลข้อมูล: -- การประมวลผลเพื่อประโยชน์โดยชอบด้วยกฎหมาย -- การประมวลผลเพื่อการตลาดโดยตรง -- การประมวลผลเพื่อวัตถุประสงค์ทางสถิติ - -### 7.6 สิทธิในการโอนย้ายข้อมูล (Right to Data Portability) - -ท่านมีสิทธิขอให้โอนข้อมูลส่วนบุคคลไปยังผู้ควบคุมข้อมูลอื่น: -- ข้อมูลที่ท่านให้ไว้ -- ข้อมูลที่ประมวลผลโดยอัตโนมัติ -- เมื่อการประมวลผลอาศัยความยินยอมหรือสัญญา - -### 7.7 สิทธิในการถอนความยินยอม (Right to Withdraw Consent) - -หากการประมวลผลอาศัยความยินยอม ท่านมีสิทธิถอนความยินยอมเมื่อใดก็ได้: -- การถอนความยินยอมไม่กระทบต่อการประมวลผลก่อนหน้า -- ท่านอาจไม่สามารถใช้บริการบางอย่างได้หลังถอนความยินยอม - -### 7.8 สิทธิในการร้องเรียน (Right to Complaint) - -หากท่านเชื่อว่าข้อมูลของท่านถูกประมวลผลโดยมิชอบด้วยกฎหมาย ท่านมีสิทธิร้องเรียนต่อ: -- สำนักงานคณะกรรมการคุ้มครองข้อมูลส่วนบุคคล (สคส.) -- เว็บไซต์: www.pdpc.or.th -- โทรศัพท์: 0-2141-6900 +1. **สิทธิในการเข้าถึง:** ขอสำเนาข้อมูลส่วนบุคคล +2. **สิทธิในการแก้ไข:** ขอให้แก้ไขข้อมูลที่ไม่ถูกต้อง +3. **สิทธิในการลบ:** ขอให้ลบข้อมูลในกรณีที่ไม่จำเป็นต้องใช้แล้ว หรือถอนความยินยอม +4. **สิทธิในการจำกัดการประมวลผล:** ขอให้ระงับการใช้ข้อมูลชั่วคราว +5. **สิทธิในการโอนย้ายข้อมูล:** ขอให้โอนข้อมูลไปยังผู้ควบคุมข้อมูลอื่น +6. **สิทธิในการคัดค้าน:** คัดค้านการประมวลผลเพื่อประโยชน์โดยชอบด้วยกฎหมาย +7. **สิทธิในการถอนความยินยอม:** ถอนความยินยอมเมื่อใดก็ได้ +8. **สิทธิในการร้องเรียน:** ร้องเรียนต่อสำนักงานคณะกรรมการคุ้มครองข้อมูลส่วนบุคคล (สคส.) ## 8. Cookie และเทคโนโลยีการติดตาม -### 8.1 Cookie คืออะไร +### ประเภทของ Cookie ที่เราใช้: -Cookie เป็นไฟล์ข้อความขนาดเล็กที่เว็บไซต์บันทึกลงในอุปกรณ์ของท่านเมื่อท่านเข้าชมเว็บไซต์ - -### 8.2 ประเภทของ Cookie ที่เราใช้ - -**Cookie ที่จำเป็น (Necessary Cookies):** -- จำเป็นสำหรับการทำงานของเว็บไซต์ -- ไม่สามารถปิดใช้งานได้ -- ไม่เก็บข้อมูลส่วนบุคคล - -**Cookie เพื่อประสิทธิภาพ (Performance Cookies):** -- รวบรวมข้อมูลเกี่ยวกับวิธีการใช้เว็บไซต์ -- ช่วยให้เราปรับปรุงเว็บไซต์ -- ข้อมูลเป็นแบบรวมกลุ่มและไม่ระบุตัวตน - -**Cookie เพื่อการทำงาน (Functional Cookies):** -- จดจำการตั้งค่าของท่าน -- ให้องค์ประกอบที่เป็นส่วนตัวมากขึ้น - -**Cookie เพื่อการตลาด (Marketing Cookies):** -- ติดตามกิจกรรมการท่องเว็บ -- ใช้เพื่อแสดงโฆษณาที่เกี่ยวข้อง -- แบ่งปันข้อมูลกับบุคคลที่สาม - -### 8.3 การจัดการ Cookie - -ท่านสามารถจัดการ Cookie ได้โดย: -- **การตั้งค่าเบราว์เซอร์:** ปิดการใช้งาน Cookie ทั้งหมดหรือบางประเภท -- **การตั้งค่า Cookie ของเรา:** เลือกประเภท Cookie ที่ท่านยินยอม -- **เครื่องมือของบุคคลที่สาม:** เช่น Google Analytics Opt-out - -### 8.4 ผลกระทบจากการปิด Cookie - -หากท่านปิดการใช้งาน Cookie: -- ฟีเจอร์บางอย่างของเว็บไซต์อาจไม่ทำงาน -- ท่านอาจไม่สามารถเข้าสู่ระบบได้ -- การตั้งค่าของท่านอาจไม่ถูกจดจำ +- **Cookie ที่จำเป็น (Necessary):** จำเป็นสำหรับการทำงานของเว็บไซต์ ไม่สามารถปิดใช้งานได้ +- **Cookie เพื่อประสิทธิภาพ (Performance):** รวบรวมข้อมูลการใช้เว็บไซต์เพื่อปรับปรุง +- **Cookie เพื่อการทำงาน (Functional):** จดจำการตั้งค่าของท่าน +- **Cookie เพื่อการตลาด (Marketing):** ติดตามกิจกรรมการท่องเว็บเพื่อแสดงโฆษณาที่เกี่ยวข้อง (ต้องได้รับความยินยอม) ## 9. ความปลอดภัยของข้อมูล -เราใช้มาตรการรักษาความปลอดภัยที่เหมาะสมเพื่อคุ้มครองข้อมูลส่วนบุคคลของท่าน: - -### 9.1 มาตรการทางเทคนิค +เราใช้มาตรการรักษาความปลอดภัยที่เหมาะสม: - **การเข้ารหัส:** ข้อมูลถูกเข้ารหัสระหว่างการส่ง (SSL/TLS) - **การควบคุมการเข้าถึง:** จำกัดการเข้าถึงข้อมูลเฉพาะผู้ที่จำเป็น - **Firewall:** ป้องกันการเข้าถึงโดยไม่ได้รับอนุญาต -- **การตรวจจับการบุกรุก:** ตรวจสอบกิจกรรมที่ผิดปกติ +- **การสำรองข้อมูล:** สำรองข้อมูลเป็นประจำ +- **การตรวจสอบ:** ทบทวนและปรับปรุงมาตรการความปลอดภัยอย่างสม่ำเสมอ -### 9.2 มาตรการทางองค์กร - -- **นโยบายความปลอดภัย:** นโยบายและขั้นตอนที่ชัดเจน -- **การฝึกอบรม:** พนักงานได้รับการฝึกอบรมเรื่องความปลอดภัยของข้อมูล -- **การตรวจสอบ:** ทบทวนและปรับปรุงมาตรการอย่างสม่ำเสมอ -- **การจัดการผู้ให้บริการ:** ประเมินความปลอดภัยของผู้ให้บริการ - -### 9.3 มาตรการทางกายภาพ - -- **การควบคุมการเข้าถึง:** จำกัดการเข้าถึงศูนย์ข้อมูล -- **การป้องกันสิ่งแวดล้อม:** ระบบป้องกันอัคคีภัยและน้ำท่วม -- **การทำลายสื่อ:** ทำลายสื่อเก็บข้อมูลอย่างปลอดภัย - -### 9.4 การแจ้งเหตุละเมิดข้อมูล +## 10. การแจ้งเหตุละเมิดข้อมูล ในกรณีที่มีการละเมิดข้อมูลส่วนบุคคล เราจะ: - แจ้งสำนักงานคณะกรรมการคุ้มครองข้อมูลส่วนบุคคลภายใน 72 ชั่วโมง - แจ้งให้ท่านทราบหากมีความเสี่ยงสูงต่อสิทธิและเสรีภาพของท่าน -- ดำเนินการเพื่อลดผลกระทบ - -## 10. การโอนข้อมูลข้ามพรมแดน - -เราอาจโอนข้อมูลส่วนบุคคลของท่านไปยังประเทศนอกประเทศไทย: - -### 10.1 ประเทศปลายทาง - -ข้อมูลอาจถูกโอนไปยัง: -- ประเทศที่มีมาตรฐานการคุ้มครองข้อมูลที่เพียงพอ -- ประเทศที่มีมาตรการคุ้มครองที่เหมาะสม -- ประเทศที่กฎหมายกำหนด - -### 10.2 มาตรการคุ้มครอง - -การโอนข้อมูลข้ามพรมแดนอยู่ภายใต้: -- มาตรฐานข้อบทเชิงสัญญา (Standard Contractual Clauses) -- กฎบัตรบริษัท (Binding Corporate Rules) -- การรับรองมาตรฐาน (Certification) ## 11. เด็กและเยาวชน -### 11.1 อายุขั้นต่ำ +เว็บไซต์ของเราไม่ได้ออกแบบมาสำหรับเด็กอายุต่ำกว่า 20 ปี หากท่านอายุต่ำกว่า 20 ปี กรุณาให้ผู้ปกครองอ่านและยินยอมแทน -เว็บไซต์ของเราไม่ได้ออกแบบมาสำหรับเด็กอายุต่ำกว่า 20 ปี: -- เราไม่เก็บรวบรวมข้อมูลจากเด็กโดยรู้เท่าไม่ถึงการณ์ -- หากท่านอายุต่ำกว่า 20 ปี กรุณาอย่าให้ข้อมูลส่วนบุคคล +## 12. การติดต่อ -### 11.2 ความยินยอมจากผู้ปกครอง +### เจ้าหน้าที่คุ้มครองข้อมูลส่วนบุคคล (DPO) -หากเราทราบ bahwaเราเก็บรวบรวมข้อมูลจากเด็กอายุต่ำกว่า 20 ปี: -- เราจะขอความยินยอมจากผู้ปกครอง -- หากไม่ได้รับความยินยอม เราจะลบข้อมูลดังกล่าว +**ชื่อ:** {DPO_NAME} +**อีเมล:** {DPO_EMAIL} +**โทรศัพท์:** {DPO_PHONE} +**ที่อยู่:** {COMPANY_ADDRESS} -## 12. การเปลี่ยนแปลงนโยบายความเป็นส่วนตัว +### ช่องทางการติดต่อ -เราอาจอัปเดตนโยบายความเป็นส่วนตัวนี้เป็นครั้งคราว: +**อีเมล:** {CONTACT_EMAIL} +**โทรศัพท์:** {CONTACT_PHONE} +**ที่อยู่:** {COMPANY_ADDRESS} -### 12.1 การแจ้งการเปลี่ยนแปลง - -เราจะแจ้งท่านเกี่ยวกับการเปลี่ยนแปลงโดย: -- โพสต์นโยบายที่อัปเดตบนเว็บไซต์ -- ส่งอีเมลแจ้งให้ทราบ -- แสดงประกาศบนเว็บไซต์ - -### 12.2 การยอมรับการเปลี่ยนแปลง - -การใช้งานเว็บไซต์ของท่านหลังจากการเปลี่ยนแปลงแสดงว่าท่านยอมรับนโยบายที่อัปเดต: -- หากท่านไม่เห็นด้วย กรุณาหยุดใช้งานเว็บไซต์ -- ท่านมีสิทธิถอนความยินยอมหรือลบบัญชี - -## 13. การติดต่อ - -หากท่านมีคำถามหรือข้อกังวลเกี่ยวกับนโยบายความเป็นส่วนตัว: - -### 13.1 เจ้าหน้าที่คุ้มครองข้อมูลส่วนบุคคล (DPO) - -**ชื่อ:** [DPO_NAME] -**อีเมล:** [DPO_EMAIL] -**โทรศัพท์:** [DPO_PHONE] -**ที่อยู่:** [COMPANY_ADDRESS] - -### 13.2 ช่องทางการติดต่ออื่นๆ - -**แบบฟอร์มติดต่อ:** [CONTACT_FORM_URL] -**อีเมล:** [CONTACT_EMAIL] -**โทรศัพท์:** [CONTACT_PHONE] -**ที่อยู่:** [COMPANY_ADDRESS] - -### 13.3 หน่วยงานกำกับดูแล +### หน่วยงานกำกับดูแล หากท่านไม่พอใจกับการตอบสนองของเรา ท่านสามารถติดต่อ: @@ -386,37 +158,21 @@ Cookie เป็นไฟล์ข้อความขนาดเล็กท อีเมล: ocppd@pdpc.or.th เว็บไซต์: www.pdpc.or.th -## 14. คำจำกัดความ - -**"ข้อมูลส่วนบุคคล"** หมายถึง ข้อมูลเกี่ยวกับบุคคลซึ่งทำให้สามารถระบุตัวตนของบุคคลนั้นได้ ไม่ว่าทางตรงหรือทางอ้อม - -**"การประมวลผล"** หมายถึง การเก็บรวบรวม ใช้ เปิดเผย ส่งต่อ ปรับเปลี่ยน เปรียบเทียบ ทำลาย หรือการดำเนินการใดๆ กับข้อมูลส่วนบุคคล - -**"ผู้ควบคุมข้อมูล"** หมายถึง บุคคลหรือนิติบุคคลซึ่งมีอำนาจหน้าที่ตัดสินใจเกี่ยวกับการเก็บรวบรวม ใช้ หรือเปิดเผยข้อมูลส่วนบุคคล - -**"ผู้ประมวลผลข้อมูล"** หมายถึง บุคคลหรือนิติบุคคลซึ่งดำเนินการเกี่ยวกับการเก็บรวบรวม ใช้ หรือเปิดเผยข้อมูลส่วนบุคคลตามคำสั่งหรือในนามของผู้ควบคุมข้อมูล - -## 15. กฎหมายที่ใช้บังคับ +## 13. กฎหมายที่ใช้บังคับ นโยบายความเป็นส่วนตัวนี้ตีความและบังคับใช้ตามกฎหมายแห่งราชอาณาจักรไทย: - พระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 - พระราชบัญญัติว่าด้วยการกระทำความผิดเกี่ยวกับคอมพิวเตอร์ - กฎหมายคุ้มครองผู้บริโภค -## 16. การแยกความมีผลบังคับใช้ - -หากข้อกำหนดใดในนโยบายนี้ถูกพิจารณาว่าเป็นโมฆะหรือบังคับไม่ได้: -- ข้อกำหนดดังกล่าวจะถูกตัดออก -- ข้อกำหนดที่เหลือจะยังคงมีผลบังคับใช้เต็มที่ - --- **ลงชื่อ:** _________________________ -**ชื่อ:** [AUTHORIZED_NAME] -**ตำแหน่ง:** [AUTHORIZED_TITLE] -**วันที่:** [DATE] +**ชื่อ:** {AUTHORIZED_NAME} +**ตำแหน่ง:** {AUTHORIZED_TITLE} +**วันที่:** {SIGN_DATE} -**บริษัท [COMPANY_NAME]** +**บริษัท {COMPANY_NAME}** --- diff --git a/skills/thai-frontend-dev/scripts/templates/thai-terms-of-service-template.md b/skills/thai-frontend-dev/scripts/templates/thai-terms-of-service-template.md index a16d48e..aafc688 100644 --- a/skills/thai-frontend-dev/scripts/templates/thai-terms-of-service-template.md +++ b/skills/thai-frontend-dev/scripts/templates/thai-terms-of-service-template.md @@ -1,15 +1,15 @@ # เงื่อนไขการให้บริการ (Terms of Service) -**ชื่อเว็บไซต์:** [WEBSITE_NAME] -**เว็บไซต์:** [WEBSITE_URL] -**มีผลบังคับใช้วันที่:** [DATE] -**แก้ไขล่าสุด:** [DATE] +**ชื่อเว็บไซต์:** {SITE_NAME} +**เว็บไซต์:** {SITE_URL} +**มีผลบังคับใช้วันที่:** {EFFECTIVE_DATE} +**แก้ไขล่าสุด:** {LAST_UPDATED} ## 1. การยอมรับเงื่อนไข ### 1.1 ข้อตกลง -ด้วยการเข้าถึงและใช้งานเว็บไซต์ [WEBSITE_URL] ("เว็บไซต์") ของบริษัท [COMPANY_NAME] ("เรา", "ของเรา" หรือ "บริษัท") ท่าน ("ผู้ใช้", "ท่าน" หรือ "ของคุณ") ยอมรับและตกลงที่จะถูกผูกมัดด้วยเงื่อนไขการให้บริการฉบับนี้ ("เงื่อนไข") +ด้วยการเข้าถึงและใช้งานเว็บไซต์ {SITE_URL} ("เว็บไซต์") ของบริษัท {COMPANY_NAME} ("เรา", "ของเรา" หรือ "บริษัท") ท่าน ("ผู้ใช้", "ท่าน" หรือ "ของคุณ") ยอมรับและตกลงที่จะถูกผูกมัดด้วยเงื่อนไขการให้บริการฉบับนี้ ("เงื่อนไข") ### 1.2 การแก้ไขเงื่อนไข @@ -28,10 +28,11 @@ ### 2.1 คำอธิบายบริการ -เว็บไซต์ของเราให้บริการ: -- [SERVICE_DESCRIPTION] -- ข้อมูลและเนื้อหาเกี่ยวกับ [TOPIC] -- เครื่องมือและฟีเจอร์ต่างๆ +{BUSINESS_NAME} ให้บริการ: + +1. **{SERVICE_1}** - {SERVICE_1_DESC} +2. **{SERVICE_2}** - {SERVICE_2_DESC} +3. **{SERVICE_3}** - {SERVICE_3_DESC} ### 2.2 การเปลี่ยนแปลงบริการ @@ -66,14 +67,14 @@ เราขอสงวนสิทธิในการระงับหรือลบบัญชีของท่านหาก: - ท่านละเมิดเงื่อนไขนี้ -- มีการ_activity_ที่น่าสงสัยหรือเป็นอันตราย +- มีกิจกรรมที่น่าสงสัยหรือเป็นอันตราย - มีการร้องเรียนจากผู้ใช้รายอื่น - ตามข้อกำหนดของกฎหมาย ### 3.4 การลบบัญชี ท่านสามารถลบบัญชีของท่านเมื่อใดก็ได้: -- ติดต่อเราที่ [CONTACT_EMAIL] +- ติดต่อเราที่ {CONTACT_EMAIL} - ข้อมูลบางอย่างอาจถูกเก็บไว้ตามข้อกำหนดของกฎหมาย - การลบบัญชีไม่สามารถย้อนกลับได้ @@ -94,7 +95,7 @@ ### 4.3 สิทธิของท่าน -ท่าน retainsสิทธิในเนื้อหาที่ท่านส่งมา: +ท่านยังคงเป็นเจ้าของเนื้อหาที่ท่านส่งมา: - ท่านยังคงเป็นเจ้าของเนื้อหาของท่าน - ท่านให้ใบอนุญาตแก่เราในการใช้เนื้อหานั้น - ท่านรับประกันว่ามีสิทธิในการให้ใบอนุญาต @@ -130,12 +131,6 @@ - ส่งสแปมหรือข้อความเชิงพาณิชย์ที่ไม่พึงประสงค์ - ปลอมแปลงตัวตนหรือแหล่งที่มาของเนื้อหา -**กิจกรรมที่ผิดจริยธรรม:** -- ส่งเนื้อหาที่หยาบคาย อนาจาร หรือผิดศีลธรรม -- ส่งเสริมการเลือกปฏิบัติหรือความเกลียดชัง -- ส่งเสริมความรุนแรงหรือการทำร้ายตนเอง -- ส่งเสริมการพนันหรือยาเสพติดที่ผิดกฎหมาย - ### 5.2 ผลของการละเมิด หากท่านละเมิดข้อห้าม: @@ -174,34 +169,26 @@ - ลบเนื้อหาที่ละเมิดเงื่อนไข - รายงานกิจกรรมที่ผิดกฎหมายต่อเจ้าหน้าที่ -### 6.5 การตอบสนองต่อการละเมิด - -หากท่านเชื่อว่ามีการละเมิดลิขสิทธิ์: -- แจ้งเราที่ [CONTACT_EMAIL] -- ให้ข้อมูลการละเมิดโดยละเอียด -- เราจะดำเนินการตาม DMCA และกฎหมายที่เกี่ยวข้อง - ## 7. การชำระเงิน ### 7.1 ราคาและค่าธรรมเนียม - ราคาทั้งหมดแสดงเป็นเงินบาทไทย (THB) -- ราคานี้รวม/ไม่รวมภาษีมูลค่าเพิ่ม +- ราคานี้ {PRICE_INCLUDES_VAT} - เราขอสงวนสิทธิในการเปลี่ยนราคาเมื่อใดก็ได้ ### 7.2 การชำระเงิน การชำระเงินต้องชำระล่วงหน้า: -- เรายอมรับการชำระเงินผ่าน [PAYMENT_METHODS] +- เรายอมรับการชำระเงินผ่าน {PAYMENT_METHODS} - การชำระเงินจะประมวลผลโดยบุคคลที่สาม - ท่านต้องให้ข้อมูลการชำระเงินที่ถูกต้อง ### 7.3 การคืนเงิน นโยบายการคืนเงิน: -- [REFUND_POLICY_DETAILS] -- คำขอคืนเงินต้องส่งภายใน [X] วัน -- การคืนเงินจะประมวลผลภายใน [X] วันทำการ +- ผู้ใช้สามารถขอคืนเงินได้ภายใน {REFUND_DAYS} วันนับจากวันที่ชำระเงิน +- การคืนเงินจะดำเนินการภายใน {REFUND_PROCESSING_DAYS} วันทำการ ### 7.4 การต่ออายุอัตโนมัติ @@ -231,11 +218,11 @@ ความรับผิดรวมของเราจะไม่เกิน: - จำนวนที่ท่านจ่ายให้เราในช่วง 12 เดือนที่ผ่านมา -- หรือ 1,000 บาท แล้วแต่จำนวนใดมากกว่า +- หรือ {LIABILITY_MAX_AMOUNT} บาท แล้วแต่จำนวนใดมากกว่า ### 8.4 ข้อยกเว้น -ข้อจำกัดบางอย่างไม่ใช้บังคับกับ: +ข้อจำกัดบางอย่างไม่ใช่บังคับกับ: - การเสียชีวิตหรือการบาดเจ็บส่วนบุคคล - การฉ้อโกงหรือการแสดงโดยประมาทเลินเล่ออย่างร้ายแรง - หน้าที่ที่ไม่สามารถถูกจำกัดตามกฎหมาย @@ -262,7 +249,7 @@ ### 10.1 นโยบายความเป็นส่วนตัว การใช้ข้อมูลส่วนบุคคลอยู่ภายใต้นโยบายความเป็นส่วนตัว: -- อ่านนโยบายความเป็นส่วนตัวของเรา +- อ่านนโยบายความเป็นส่วนตัวของเราที่ {PRIVACY_POLICY_URL} - นโยบายความเป็นส่วนตัวเป็นส่วนหนึ่งของเงื่อนไขนี้ - ในกรณีที่มีความขัดแย้ง เงื่อนไขนี้จะมีผลบังคับใช้ @@ -273,48 +260,32 @@ - ท่านสามารถจัดการการตั้งค่า Cookie ได้ - การปิดการใช้งาน Cookie อาจจำกัดการทำงานของเว็บไซต์ -## 11. ลิงก์ไปยังเว็บไซต์ภายนอก +## 11. การยุติบริการ -### 11.1 ลิงก์ของบุคคลที่สาม - -เว็บไซต์อาจมีลิงก์ไปยังเว็บไซต์ของบุคคลที่สาม: -- เราไม่ควบคุมเว็บไซต์เหล่านั้น -- เราไม่รับผิดชอบเนื้อหาหรือการปฏิบัติของเว็บไซต์เหล่านั้น -- การเข้าถึงเว็บไซต์เหล่านั้นเป็นความเสี่ยงของท่าน - -### 11.2 การโฆษณา - -เว็บไซต์อาจมีโฆษณาของบุคคลที่สาม: -- เราไม่รับผิดชอบผลิตภัณฑ์หรือบริการที่โฆษณา -- ธุรกรรมกับเจ้าของโฆษณาอยู่ระหว่างท่านและเจ้าของโฆษณา -- เราไม่ตรวจสอบหรือรับรองการโฆษณา - -## 12. การยุติบริการ - -### 12.1 การยุติโดยท่าน +### 11.1 การยุติโดยท่าน ท่านสามารถยุติการใช้งานเว็บไซต์เมื่อใดก็ได้: - หยุดใช้งานเว็บไซต์ - ลบบัญชีของท่าน -- ส่งคำขอเป็นลายลักษณ์อักษร +- ส่งคำขอเป็นลายลักษณ์อักษรที่ {CONTACT_EMAIL} -### 12.2 การยุติโดยเรา +### 11.2 การยุติโดยเรา เราขอสงวนสิทธิในการยุติการเข้าถึงของท่าน: - โดยไม่แจ้งล่วงหน้า - ด้วยเหตุผลใดๆ หรือไม่มีเหตุผล - ทันทีที่มีผล -### 12.3 ผลของการยุติ +### 11.3 ผลของการยุติ เมื่อการเข้าถึงถูกยุติ: - สิทธิ์ในการใช้งานเว็บไซต์สิ้นสุดลง - ท่านต้องหยุดใช้งานเว็บไซต์ทันที -- ข้อกำหนดบางประการยังคงมีผล (ดูข้อ 15) +- ข้อกำหนดบางประการยังคงมีผล -## 13. กฎหมายที่ใช้บังคับ +## 12. กฎหมายที่ใช้บังคับ -### 13.1 กฎหมายไทย +### 12.1 กฎหมายไทย เงื่อนไขนี้ถูกควบคุมและตีความตามกฎหมายแห่งราชอาณาจักรไทย: - พระราชบัญญัติคุ้มครองผู้บริโภค @@ -322,94 +293,49 @@ - พระราชบัญญัติลิขสิทธิ์ - กฎหมายที่เกี่ยวข้องอื่นๆ -### 13.2 เขตอำนาจศาล +### 12.2 เขตอำนาจศาล ข้อพิพาทใดๆ อยู่ภายใต้เขตอำนาจศาลของ: -- ศาลไทย -- กรุงเทพมหานคร -- หรือศาลที่มีเขตอำนาจ +- ศาลแพ่ง/ศาลล้มละลายกลาง {COURT_LOCATION} +- หรือศาลที่มีเขตอำนาจในประเทศไทย -### 13.3 การระงับข้อพิพาท +### 12.3 การระงับข้อพิพาท ก่อนดำเนินการทางกฎหมาย: - พยายามเจรจาเพื่อระงับข้อพิพาท -- ใช้เวลา 30 วันในการเจรจา +- ใช้เวลา {NEGOTIATION_DAYS} วันในการเจรจา - หากไม่สำเร็จ จึงดำเนินการทางกฎหมาย -## 14. ข้อกำหนดทั่วไป - -### 14.1 การสละสิทธิ - -การไม่บังคับใช้สิทธิใดๆ ไม่ถือเป็นการสละสิทธิ: -- การสละสิทธิต้องเป็นลายลักษณ์อักษร -- การสละสิทธิครั้งหนึ่งไม่ถือเป็นการสละสิทธิในอนาคต - -### 14.2 การโอนสิทธิ - -ท่านไม่สามารถโอนสิทธิหรือหน้าที่ภายใต้เงื่อนไขนี้: -- การโอนที่พยายามทำจะถือเป็นโมฆะ -- เราสามารถโอนสิทธิของเราได้โดยไม่ต้องแจ้งให้ท่านทราบ - -### 14.3 ความสัมพันธ์ระหว่างคู่สัญญา - -เงื่อนไขนี้ไม่สร้างความสัมพันธ์: -- ไม่มีความสัมพันธ์การจ้างงาน -- ไม่มีความสัมพันธ์หุ้นส่วน -- ไม่มีความสัมพันธ์ร่วมทุน - -### 14.4 การแยกความมีผลบังคับใช้ - -หากข้อกำหนดใดถูกพิจารณาว่าเป็นโมฆะ: -- ข้อกำหนดนั้นจะถูกตัดออก -- ข้อกำหนดที่เหลือจะยังคงมีผลบังคับใช้เต็มที่ - -### 14.5 ข้อกำหนดทั้งหมด - -เงื่อนไขนี้เป็นข้อตกลงทั้งหมดระหว่างท่านและเรา: -- แทนที่ข้อตกลงหรือความเข้าใจก่อนหน้าทั้งหมด -- ไม่ว่าจะด้วยลายลักษณ์อักษรหรือด้วยวาจา -- ไม่มีการแก้ไขด้วยวาจามีผลบังคับใช้ - -## 15. ข้อกำหนดที่ยังคงมีผล - -ข้อกำหนดดังต่อไปนี้จะยังคงมีผลหลังการยุติ: -- ความเป็นเจ้าของทรัพย์สินทางปัญญา -- การปฏิเสธความรับผิดชอบ -- ข้อจำกัดความรับผิด -- การชดเชย -- กฎหมายที่ใช้บังคับ - -## 16. การติดต่อ +## 13. การติดต่อ หากท่านมีคำถามเกี่ยวกับเงื่อนไขนี้: -**อีเมล:** [CONTACT_EMAIL] -**โทรศัพท์:** [CONTACT_PHONE] -**ที่อยู่:** [COMPANY_ADDRESS] -**แบบฟอร์มติดต่อ:** [CONTACT_FORM_URL] +**อีเมล:** {CONTACT_EMAIL} +**โทรศัพท์:** {CONTACT_PHONE} +**ที่อยู่:** {COMPANY_ADDRESS} --- -## ภาคผนวก ก: คำจำกัดความ +## ภาคผนวก: คำจำกัดความ **"บัญชี"** หมายถึง บัญชีผู้ใช้ที่ท่านสร้างบนเว็บไซต์ **"เนื้อหา"** หมายถึง ข้อมูล ข้อความ กราฟิก ภาพ วิดีโอ ซอฟต์แวร์ หรือวัสดุอื่นๆ -**"เว็บไซต์"** หมายถึง เว็บไซต์ [WEBSITE_URL] และบริการที่เกี่ยวข้องทั้งหมด +**"เว็บไซต์"** หมายถึง เว็บไซต์ {SITE_URL} และบริการที่เกี่ยวข้องทั้งหมด -**"เรา" "ของเรา"** หมายถึง บริษัท [COMPANY_NAME] +**"เรา" "ของเรา"** หมายถึง บริษัท {COMPANY_NAME} **"ท่าน" "ผู้ใช้"** หมายถึง บุคคลหรือนิติบุคคลที่เข้าถึงหรือใช้งานเว็บไซต์ --- **ลงชื่อ:** _________________________ -**ชื่อ:** [AUTHORIZED_NAME] -**ตำแหน่ง:** [AUTHORIZED_TITLE] -**วันที่:** [DATE] +**ชื่อ:** {AUTHORIZED_NAME} +**ตำแหน่ง:** {AUTHORIZED_TITLE} +**วันที่:** {SIGN_DATE} -**บริษัท [COMPANY_NAME]** +**บริษัท {COMPANY_NAME}** ---