{
  "_meta": {
    "version": "2.0",
    "description": "MultiPortal SaaS — Reference database schema and seed data",
    "localStorage_prefix": "mp2_",
    "migration_note": "Replace localStorage API calls with fetch('/api/<resource>') REST endpoints. All IDs are strings for UUID compatibility."
  },

  "tables": {

    "users": {
      "_schema": {
        "id": "VARCHAR(36) PRIMARY KEY",
        "username": "VARCHAR(50) UNIQUE NOT NULL",
        "email": "VARCHAR(120) UNIQUE NOT NULL",
        "password": "VARCHAR(255) NOT NULL -- bcrypt hash",
        "full_name": "VARCHAR(120)",
        "avatar": "TEXT -- URL",
        "org_type": "VARCHAR(60)",
        "plan": "ENUM('free','starter','pro','enterprise') DEFAULT 'free'",
        "status": "ENUM('active','suspended','pending') DEFAULT 'active'",
        "email_verified": "BOOLEAN DEFAULT FALSE",
        "created_at": "DATETIME",
        "updated_at": "DATETIME",
        "last_login": "DATETIME"
      },
      "seed": [
        {
          "id": "u001",
          "username": "hezly",
          "email": "hezly@example.com",
          "password": "$2b$10$examplehash_hezly",
          "full_name": "Hezly Admin",
          "avatar": null,
          "org_type": "Government Agency",
          "plan": "pro",
          "status": "active",
          "email_verified": true,
          "created_at": "2025-01-10T08:00:00Z",
          "updated_at": "2025-01-10T08:00:00Z",
          "last_login": "2025-06-01T10:30:00Z"
        },
        {
          "id": "u002",
          "username": "demo",
          "email": "demo@example.com",
          "password": "$2b$10$examplehash_demo",
          "full_name": "Demo User",
          "avatar": null,
          "org_type": "Community Organisation",
          "plan": "free",
          "status": "active",
          "email_verified": false,
          "created_at": "2025-03-01T09:00:00Z",
          "updated_at": "2025-03-01T09:00:00Z",
          "last_login": null
        }
      ]
    },

    "portals": {
      "_schema": {
        "id": "VARCHAR(36) PRIMARY KEY",
        "user_id": "VARCHAR(36) REFERENCES users(id) ON DELETE CASCADE",
        "name": "VARCHAR(80) UNIQUE NOT NULL -- URL slug, lowercase, hyphens",
        "display_name": "VARCHAR(120) NOT NULL",
        "description": "TEXT",
        "category": "VARCHAR(60)",
        "template_id": "VARCHAR(20) REFERENCES templates(id)",
        "logo_url": "TEXT",
        "favicon_url": "TEXT",
        "status": "ENUM('active','inactive') DEFAULT 'active'",
        "settings": "JSON -- see settings_schema below",
        "created_at": "DATETIME",
        "updated_at": "DATETIME"
      },
      "_settings_schema": {
        "primary_color": "hex string",
        "secondary_color": "hex string",
        "font_family": "Google Font name",
        "contact_email": "string",
        "contact_phone": "string",
        "address": "string",
        "social_links": {
          "facebook": "URL or empty string",
          "instagram": "URL or empty string",
          "twitter": "URL or empty string",
          "youtube": "URL or empty string",
          "whatsapp": "URL or empty string",
          "telegram": "URL or empty string"
        },
        "footer_text": "string",
        "analytics_id": "Google Analytics ID or empty string"
      },
      "seed": [
        {
          "id": "p001",
          "user_id": "u001",
          "name": "kemas-linggiu",
          "display_name": "KEMAS Linggiu",
          "description": "Portal rasmi KEMAS Linggiu — maklumat program, aktiviti komuniti dan perkhidmatan.",
          "category": "government",
          "template_id": "t001",
          "logo_url": null,
          "favicon_url": null,
          "status": "active",
          "settings": {
            "primary_color": "#1a56db",
            "secondary_color": "#0ea5e9",
            "font_family": "Inter",
            "contact_email": "kemas.linggiu@gov.my",
            "contact_phone": "+607-123 4567",
            "address": "Pejabat KEMAS Linggiu, Johor, Malaysia",
            "social_links": {
              "facebook": "https://facebook.com/kemaslinggiu",
              "instagram": "",
              "twitter": "",
              "youtube": "",
              "whatsapp": "https://wa.me/6071234567",
              "telegram": ""
            },
            "footer_text": "Hak Cipta Terpelihara.",
            "analytics_id": ""
          },
          "created_at": "2025-02-01T08:00:00Z",
          "updated_at": "2025-02-01T08:00:00Z"
        },
        {
          "id": "p002",
          "user_id": "u001",
          "name": "masjid-alhidayah",
          "display_name": "Masjid Al-Hidayah",
          "description": "Portal rasmi Masjid Al-Hidayah — waktu solat, aktiviti, dan pengumuman.",
          "category": "religious",
          "template_id": "t002",
          "logo_url": null,
          "favicon_url": null,
          "status": "active",
          "settings": {
            "primary_color": "#16a34a",
            "secondary_color": "#f59e0b",
            "font_family": "Poppins",
            "contact_email": "masjid.alhidayah@gmail.com",
            "contact_phone": "+607-987 6543",
            "address": "Jalan Masjid, Taman Hidayah, Johor, Malaysia",
            "social_links": {
              "facebook": "https://facebook.com/masjidalhidayah",
              "instagram": "https://instagram.com/masjidalhidayah",
              "twitter": "",
              "youtube": "",
              "whatsapp": "https://wa.me/6079876543",
              "telegram": "https://t.me/masjidalhidayah"
            },
            "footer_text": "Semoga diberkati. Hak Cipta Terpelihara.",
            "analytics_id": ""
          },
          "created_at": "2025-02-15T10:00:00Z",
          "updated_at": "2025-02-15T10:00:00Z"
        },
        {
          "id": "p003",
          "user_id": "u001",
          "name": "smk-seri-perdana",
          "display_name": "SMK Seri Perdana",
          "description": "Portal Sekolah Menengah Kebangsaan Seri Perdana — info sekolah, jadual dan pengumuman.",
          "category": "education",
          "template_id": "t003",
          "logo_url": null,
          "favicon_url": null,
          "status": "inactive",
          "settings": {
            "primary_color": "#7c3aed",
            "secondary_color": "#ec4899",
            "font_family": "Nunito",
            "contact_email": "smkseriperdana@moe.edu.my",
            "contact_phone": "+607-456 7890",
            "address": "Jalan Perdana, Taman Seri Perdana, Johor, Malaysia",
            "social_links": {
              "facebook": "https://facebook.com/smkseriperdana",
              "instagram": "",
              "twitter": "",
              "youtube": "https://youtube.com/smkseriperdana",
              "whatsapp": "",
              "telegram": ""
            },
            "footer_text": "Portal Rasmi SMK Seri Perdana. Hak Cipta Terpelihara.",
            "analytics_id": ""
          },
          "created_at": "2025-03-01T11:00:00Z",
          "updated_at": "2025-03-01T11:00:00Z"
        }
      ]
    },

    "templates": {
      "_schema": {
        "id": "VARCHAR(20) PRIMARY KEY",
        "name": "VARCHAR(80) NOT NULL",
        "slug": "VARCHAR(80) UNIQUE NOT NULL",
        "description": "TEXT",
        "thumbnail_color": "VARCHAR(20) -- CSS hex",
        "thumbnail_icon": "VARCHAR(10) -- emoji or icon class",
        "path": "VARCHAR(200) -- file path or CDN URL",
        "category": "VARCHAR(60)",
        "tags": "JSON -- array of strings",
        "is_free": "BOOLEAN DEFAULT TRUE",
        "price": "DECIMAL(8,2) DEFAULT 0.00",
        "created_by": "VARCHAR(36) REFERENCES users(id)",
        "status": "ENUM('active','inactive') DEFAULT 'active'",
        "created_at": "DATETIME"
      },
      "seed": [
        { "id": "t001", "name": "Modern Business", "slug": "modern-business", "description": "Clean professional layout for businesses and agencies.", "thumbnail_color": "#4f6ef7", "thumbnail_icon": "🏢", "path": "templates/t001/", "category": "business", "tags": ["professional","corporate","clean"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2025-01-01T00:00:00Z" },
        { "id": "t002", "name": "Community Hub", "slug": "community-hub", "description": "Warm community-friendly template for mosques, associations and community groups.", "thumbnail_color": "#10b981", "thumbnail_icon": "🏘️", "path": "templates/t002/", "category": "community", "tags": ["community","religious","association"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2025-01-01T00:00:00Z" },
        { "id": "t003", "name": "Edu Portal", "slug": "edu-portal", "description": "Structured layout for schools, colleges and training centres.", "thumbnail_color": "#7c3aed", "thumbnail_icon": "🎓", "path": "templates/t003/", "category": "education", "tags": ["education","school","university"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2025-01-01T00:00:00Z" },
        { "id": "t004", "name": "Township Connect", "slug": "township-connect", "description": "Modern dark-hero layout for townships, neighbourhoods and resident associations.", "thumbnail_color": "#f59e0b", "thumbnail_icon": "🏙️", "path": "templates/t004/", "category": "community", "tags": ["township","residential","neighbourhood"], "is_free": false, "price": 29, "created_by": null, "status": "active", "created_at": "2025-01-01T00:00:00Z" },
        { "id": "t005", "name": "Waso Strategy", "slug": "waso-strategy", "description": "Professional business/consulting template with dark hero, services tabs, projects grid and contact form.", "thumbnail_color": "#f9c10b", "thumbnail_icon": "💼", "path": "templates/t005/", "category": "business", "tags": ["business","consulting","agency","corporate"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2026-01-01T00:00:00Z" },
        { "id": "t006", "name": "eLearning", "slug": "elearning", "description": "Feature-rich education template with hero slideshow, service highlights, course cards, team section and testimonials.", "thumbnail_color": "#0d6efd", "thumbnail_icon": "🎓", "path": "templates/t006/", "category": "education", "tags": ["education","school","courses","learning"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2026-01-01T00:00:00Z" },
        { "id": "t007", "name": "Villa Agency", "slug": "villa-agency", "description": "Elegant real estate template with full-screen hero, property grid, stats counter and contact map.", "thumbnail_color": "#c8a45a", "thumbnail_icon": "🏡", "path": "templates/t007/", "category": "realestate", "tags": ["real estate","property","agency","villa","rental"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2026-01-01T00:00:00Z" },
        { "id": "t008", "name": "Barista Cafe", "slug": "barista-cafe", "description": "Moody dark cafe template with hero slideshow, team cards, dotted menu, timeline reviews and opening hours footer.", "thumbnail_color": "#c8874a", "thumbnail_icon": "☕", "path": "templates/t008/", "category": "food", "tags": ["cafe","restaurant","food","coffee","hospitality"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2026-01-01T00:00:00Z" },
        { "id": "t009", "name": "Tiya Golf Club", "slug": "tiya-golf-club", "description": "Elegant golf club template with SVG wave decorations, membership pricing table, event listings, newsletter CTA and contact map.", "thumbnail_color": "#81B29A", "thumbnail_icon": "⛳", "path": "templates/t009/", "category": "sports", "tags": ["golf","club","sports","membership","events"], "is_free": true, "price": 0, "created_by": null, "status": "active", "created_at": "2026-01-01T00:00:00Z" }
      ]
    },

    "pages": {
      "_schema": {
        "id": "VARCHAR(36) PRIMARY KEY",
        "portal_id": "VARCHAR(36) REFERENCES portals(id) ON DELETE CASCADE",
        "title": "VARCHAR(120) NOT NULL",
        "slug": "VARCHAR(80) NOT NULL",
        "type": "ENUM('home','about','contact','custom') DEFAULT 'custom'",
        "content": "LONGTEXT -- full HTML content",
        "meta_title": "VARCHAR(160)",
        "meta_description": "VARCHAR(320)",
        "status": "ENUM('published','draft') DEFAULT 'draft'",
        "sort_order": "INT DEFAULT 0",
        "in_menu": "BOOLEAN DEFAULT TRUE",
        "created_at": "DATETIME",
        "updated_at": "DATETIME"
      },
      "seed": [
        {
          "id": "pg001", "portal_id": "p001", "title": "Laman Utama", "slug": "home", "type": "home", "status": "published", "in_menu": true, "sort_order": 0,
          "content": "<div class='container'><div class='row align-items-center'><div class='col-lg-7'><h1 class='display-5 fw-bold mb-3'>Selamat Datang ke Portal KEMAS Linggiu</h1><p class='lead'>Portal rasmi Jabatan Kemajuan Masyarakat (KEMAS) Linggiu. Kami menyediakan pelbagai program dan perkhidmatan untuk pembangunan komuniti tempatan.</p><button class='t1-btn mt-2' onclick=\"showPage('about')\">Ketahui Lebih Lanjut</button></div></div></div>",
          "meta_title": "KEMAS Linggiu — Laman Utama", "meta_description": "Portal rasmi KEMAS Linggiu", "created_at": "2025-02-01T08:00:00Z", "updated_at": "2025-02-01T08:00:00Z"
        },
        {
          "id": "pg002", "portal_id": "p001", "title": "Tentang Kami", "slug": "about", "type": "about", "status": "published", "in_menu": true, "sort_order": 1,
          "content": "<div class='container'><h2>Tentang KEMAS Linggiu</h2><p>Jabatan Kemajuan Masyarakat (KEMAS) Linggiu adalah cawangan KEMAS yang berkhidmat untuk komuniti di kawasan Linggiu dan persekitarannya.</p><div class='row mt-4'><div class='col-md-4 mb-3'><div class='t1-card'><h5>🎯 Misi</h5><p>Memperkasakan masyarakat luar bandar melalui pendidikan dan latihan kemahiran.</p></div></div><div class='col-md-4 mb-3'><div class='t1-card'><h5>👁️ Visi</h5><p>Masyarakat sejahtera, berilmu dan berdaya saing menjelang 2030.</p></div></div><div class='col-md-4 mb-3'><div class='t1-card'><h5>💡 Nilai</h5><p>Integriti, amanah, profesionalisme dan perkhidmatan cemerlang.</p></div></div></div></div>",
          "meta_title": "Tentang Kami — KEMAS Linggiu", "meta_description": "", "created_at": "2025-02-01T08:00:00Z", "updated_at": "2025-02-01T08:00:00Z"
        },
        {
          "id": "pg003", "portal_id": "p001", "title": "Hubungi Kami", "slug": "contact", "type": "contact", "status": "published", "in_menu": true, "sort_order": 2,
          "content": "<div class='container'><h2>Hubungi Kami</h2><div class='row'><div class='col-md-6'><p><strong>📍 Alamat:</strong> Pejabat KEMAS Linggiu, Johor, Malaysia</p><p><strong>📞 Telefon:</strong> +607-123 4567</p><p><strong>✉️ Emel:</strong> kemas.linggiu@gov.my</p><p><strong>🕐 Waktu Pejabat:</strong> Isnin–Jumaat, 8:00 pagi – 5:00 petang</p></div></div></div>",
          "meta_title": "Hubungi Kami — KEMAS Linggiu", "meta_description": "", "created_at": "2025-02-01T08:00:00Z", "updated_at": "2025-02-01T08:00:00Z"
        }
      ]
    },

    "menus": {
      "_schema": {
        "id": "VARCHAR(36) PRIMARY KEY",
        "portal_id": "VARCHAR(36) REFERENCES portals(id) ON DELETE CASCADE",
        "name": "VARCHAR(80) NOT NULL",
        "items": "JSON -- array of menu item objects",
        "created_at": "DATETIME",
        "updated_at": "DATETIME"
      },
      "_menu_item_schema": {
        "id": "string",
        "label": "string",
        "url": "string -- absolute URL or #",
        "page_slug": "string -- if linking to a portal page",
        "target": "_self | _blank",
        "sort_order": "integer"
      },
      "seed": []
    },

    "media": {
      "_schema": {
        "id": "VARCHAR(36) PRIMARY KEY",
        "portal_id": "VARCHAR(36) REFERENCES portals(id) ON DELETE CASCADE",
        "user_id": "VARCHAR(36) REFERENCES users(id)",
        "filename": "VARCHAR(255) NOT NULL -- stored filename on disk/S3",
        "original_name": "VARCHAR(255)",
        "mime_type": "VARCHAR(80)",
        "size": "BIGINT -- bytes",
        "url": "TEXT NOT NULL -- public URL",
        "alt_text": "VARCHAR(255)",
        "created_at": "DATETIME"
      },
      "seed": []
    }

  },

  "api_endpoints": {
    "_note": "Replace localStorage API functions in multiportal.html and admin.html with these REST endpoints.",
    "auth": {
      "POST /api/auth/login": { "body": { "username": "string", "password": "string" }, "returns": { "token": "JWT", "user": "UserObject" } },
      "POST /api/auth/register": { "body": { "username": "string", "email": "string", "password": "string", "full_name": "string", "org_type": "string" }, "returns": { "token": "JWT", "user": "UserObject" } },
      "POST /api/auth/logout": { "headers": { "Authorization": "Bearer <token>" }, "returns": { "success": true } },
      "GET /api/auth/me": { "headers": { "Authorization": "Bearer <token>" }, "returns": "UserObject" }
    },
    "portals": {
      "GET /api/portals": "List all portals for the authenticated user",
      "POST /api/portals": "Create a new portal",
      "GET /api/portals/:slug": "Get portal by slug (public, no auth needed for active portals)",
      "PUT /api/portals/:id": "Update portal settings",
      "DELETE /api/portals/:id": "Delete portal and all its pages/media"
    },
    "pages": {
      "GET /api/portals/:id/pages": "List all pages for a portal",
      "POST /api/portals/:id/pages": "Create a new page",
      "PUT /api/pages/:id": "Update a page",
      "DELETE /api/pages/:id": "Delete a page"
    },
    "templates": {
      "GET /api/templates": "List all available templates",
      "GET /api/templates/:id": "Get template details"
    },
    "media": {
      "GET /api/portals/:id/media": "List media for a portal",
      "POST /api/portals/:id/media": "Upload file (multipart/form-data)",
      "DELETE /api/media/:id": "Delete a media file"
    },
    "stats": {
      "GET /api/stats": "Returns { portals, pages, activePortals, totalViews } for the authenticated user"
    }
  }
}
