{"id":48882243,"url":"https://github.com/rbwtech/lacak-nutri","last_synced_at":"2026-04-16T03:33:59.570Z","repository":{"id":325864422,"uuid":"1097152425","full_name":"rbwtech/lacak-nutri","owner":"rbwtech","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-23T21:38:15.000Z","size":1104,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-23T22:14:12.204Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rbwtech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-15T16:25:22.000Z","updated_at":"2025-11-23T21:38:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rbwtech/lacak-nutri","commit_stats":null,"previous_names":["rbwtech/lacak-nutri"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/rbwtech/lacak-nutri","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbwtech%2Flacak-nutri","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbwtech%2Flacak-nutri/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbwtech%2Flacak-nutri/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbwtech%2Flacak-nutri/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rbwtech","download_url":"https://codeload.github.com/rbwtech/lacak-nutri/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbwtech%2Flacak-nutri/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31870513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"online","status_checked_at":"2026-04-16T02:00:06.042Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-16T03:33:59.064Z","updated_at":"2026-04-16T03:33:59.553Z","avatar_url":"https://github.com/rbwtech.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n```\n            ██╗      █████╗  ██████╗ █████╗ ██╗  ██╗    ███╗   ██╗██╗   ██╗████████╗██████╗ ██╗\n            ██║     ██╔══██╗██╔════╝██╔══██╗██║ ██╔╝    ████╗  ██║██║   ██║╚══██╔══╝██╔══██╗██║\n            ██║     ███████║██║     ███████║█████╔╝     ██╔██╗ ██║██║   ██║   ██║   ██████╔╝██║\n            ██║     ██╔══██║██║     ██╔══██║██╔═██╗     ██║╚██╗██║██║   ██║   ██║   ██╔══██╗██║\n            ███████╗██║  ██║╚██████╗██║  ██║██║  ██╗    ██║ ╚████║╚██████╔╝   ██║   ██║  ██║██║\n            ╚══════╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝    ╚═╝  ╚═══╝ ╚═════╝    ╚═╝   ╚═╝  ╚═╝╚═╝\n```\n\n### Platform Analisis Nutrisi dan Validasi BPOM Berbasis Artificial Intelligence\n\n**Transparansi Instan, Keputusan Terinformasi**\n\n[![Live Demo](https://img.shields.io/badge/demo-lacaknutri.rbwtech.io-FF9966?style=for-the-badge\u0026logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6bTAgMThjLTQuNDEgMC04LTMuNTktOC04czMuNTktOCA4LTggOCAzLjU5IDggOC0zLjU5IDgtOCA4eiIgZmlsbD0iI0ZGRkZGRiIvPgo8L3N2Zz4=)](https://lacaknutri.rbwtech.io)\n[![GitHub](https://img.shields.io/badge/github-rbwtech%2Flacak--nutri-333333?style=for-the-badge\u0026logo=github)](https://github.com/rbwtech/lacak-nutri)\n[![License](https://img.shields.io/badge/license-MIT-6B8E23?style=for-the-badge)](LICENSE)\n\n## NAVIGATION / TABLE OF CONTENTS\n\n[Overview](#overview) •\n[Demo](#demo-access) •\n[Features](#core-features) •\n[Security](#security--protection-mechanisms) •\n[Tech Stack](#technology-stack) •\n[Installation](#quick-start-installation) •\n[Design System](#design-system) •\n[API Docs](https://github.com/rbwtech/lacak-nutri/blob/main/API_DOCUMENTATION.MD) •\n[License](#license) •\n[Team](#team) •\n[Acknowledgement](#acknowledgement) •\n[Support](#support)\n\n\u003c/div\u003e\n\n---\n\n## Overview\n\nLacakNutri adalah aplikasi web berbasis Full Stack dan AI yang dirancang untuk memberikan analisis nutrisi instan dan validasi keamanan pangan untuk produk makanan/minuman kemasan. Aplikasi ini menggunakan Vision Language Model (VLM) dari Google Gemini untuk memproses label nutrisi dan komposisi dari gambar, serta mekanisme web scraping untuk memverifikasi status registrasi produk ke database resmi BPOM.\n\n**Problem Statement:** Minimnya transparansi informasi nilai gizi dan kesulitan memverifikasi keamanan produk BPOM.\n\n**Solution:** Platform end-to-end yang mengubah label fisik menjadi data terstruktur dengan insight kesehatan personal dalam hitungan detik.\n\n### Core Value\n\n```\nCapture Image → AI Analysis (VLM) → Personalized Health Insights\nQR Code → BPOM Validation (Scraping) → BPOM Result\n```\n\n**Target Users:**\n\n- Konsumen sadar kesehatan\n- Keluarga dengan kondisi alergi/diet khusus\n- Individu dengan penyakit metabolik (diabetes, hipertensi)\n- Masyarakat umum yang peduli keamanan pangan\n\n---\n\n## DEMO ACCESS\n\n### Live Instance\n\n**URL:** https://lacaknutri.rbwtech.io\n\n### Admin Dashboard (Demo)\n\n```\nEmail: lacaknutri@rbwtech.io\nPassword: UINIC7.0\n```\n\n**Capabilities:**\n\n- Full CRUD operations\n- Real-time analytics dashboard\n- User management\n- Content moderation (GiziPedia)\n- Scan history monitoring\n\n### Test Credentials (Regular User)\n\n```\nEmail: demo@lacaknutri.com\nPassword: demo123\n```\n\n---\n\n## CORE FEATURES\n\n```\nDisclaimer:\nFungsi utama /api/scan/analyze menggunakan Gemini AI (VLM) untuk membaca dan menganalisis label dari gambar secara langsung. Ini lebih dari sekadar OCR; ini adalah analisis gambar terstruktur. Tesseract hanya digunakan untuk raw text extraction di endpoint terpisah (/api/scan/ocr-text).\n```\n\n### 1\\. Vision-Powered Nutrition Analysis (VLM \u0026 AI)\n\n**Engine:** Google Gemini 2.5 / 2.0 Flash\n\n**AI Analysis Pipeline (`/api/scan/analyze`)**:\n\n```mermaid\nflowchart TD\n    %% Input\n    U([User Uploads Image]):::input --\u003e FE[Frontend: Get Recaptcha v3 Token]:::frontend\n    FE --\u003e API[[API Request + Token]]:::api\n\n    %% Security Layer\n    subgraph SECURITY[\"Security Layer\"]\n      RL{Rate Limit?}:::decision\n      CV{Captcha Score?}:::decision\n    end\n    API --\u003e RL\n    RL -- \"Too Many (IP)\" --\u003e ERR429([429: Too Many Requests]):::error\n    RL -- \"OK\" --\u003e CV\n    CV -- \"Score \u003c 0.5\" --\u003e ERR403([403: Forbidden]):::error\n    CV -- \"Score \u003e= 0.5\" --\u003e GEM[\"analyze_nutrition_image (GeminiService)\"]:::service\n\n    %% Main Analysis\n    GEM -- \"Prompt + Image\" --\u003e GVLM[\"Gemini VLM Analysis\"]:::ai\n    GVLM -- \"Structured JSON\" --\u003e BE[Backend Service]:::backend\n    BE -- \"Extract Ingredients\" --\u003e ALRGY{User Allergies Found?}:::decision\n\n    ALRGY -- \"Allergens Detected\" --\u003e HIST[Create ScanHistoryOCR]:::storage\n    HIST --\u003e SHOW([Display Scan Result]):::result\n\n    ALRGY -- \"No Allergens\" --\u003e SHOW\n\n    %% Assignment of classes\n    class U input;\n    class FE frontend;\n    class API api;\n    class RL,CV,ALRGY decision;\n    class GEM service;\n    class GVLM ai;\n    class BE backend;\n    class SHOW result;\n    class ERR429,ERR403 error;\n    class HIST storage;\n    class SECURITY SECURITY;\n```\n\n**Hasil Structured JSON yang Dikelola oleh AI Service:**\n\n| Field              | Tipe Data       | Deskripsi                                                                                                            |\n| :----------------- | :-------------- | :------------------------------------------------------------------------------------------------------------------- |\n| **`nutrition`**    | JSON Object     | Data nutrisi terstruktur (kalori, protein, lemak, gula, sodium, dll.).                                               |\n| **`health_score`** | Integer (0-100) | Penilaian kesehatan objektif oleh AI.                                                                                |\n| **`grade`**        | String (A-E)    | Kategori nilai kesehatan berdasarkan `health_score`.                                                                 |\n| **`summary`**      | String          | Ringkasan analisis nutrisi (2-3 kalimat).                                                                            |\n| **`pros`, `cons`** | List of Strings | Keunggulan dan kelemahan nutrisi yang terdeteksi.                                                                    |\n| **`ingredients`**  | String          | Daftar bahan yang diekstraksi.                                                                                       |\n| **`warnings`**     | List of Strings | Daftar potensi peringatan (misalnya, Tinggi Gula, Aditif) **ditambah alergen yang terdeteksi dari profil pengguna**. |\n\n#### Rate Limiting (Keterbatasan Penggunaan)\n\nUntuk menjaga _resource_ AI, _endpoint_ `/api/scan/analyze` memiliki batasan penggunaan harian:\n\n- **Pengguna Tamu (Guest)** atau **Pengguna Terdaftar Biasa**: Maksimal **10x Analisis AI per hari**.\n- **Administrator**: Tidak memiliki batasan.\n\n### 2\\. BPOM Validation\n\nFitur ini memvalidasi produk menggunakan nomor registrasi BPOM yang diinput (MD/ML/SI/DBL) atau dipindai QR-nya.\n\n**Mekanisme:** **Web Scraping** (menggunakan `httpx` dan `BeautifulSoup4`) dari situs resmi BPOM (`https://cekbpom.pom.go.id`).\n\n**Alur Validasi BPOM (`/api/scan/bpom`)**:\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Frontend\n    participant API as Backend API\n    participant Google as Google Server\n    participant CRUD as Database/Cache\n    participant BPOMScraper\n\n    User-\u003e\u003eFrontend: Input BPOM / Click Scan\n    activate Frontend\n    Frontend-\u003e\u003eGoogle: Request reCAPTCHA v3 Token\n    Google--\u003e\u003eFrontend: Return Token\n\n    Frontend-\u003e\u003e+API: POST /scan/bpom (BPOM No + Token)\n\n    Note over API: 1. Check Rate Limit (IP Based)\u003cbr/\u003e2. Validate Captcha Token\n\n    API-\u003e\u003eGoogle: Verify Token (Server-to-Server)\n    Google--\u003e\u003eAPI: { success: true, score: 0.9 }\n\n    alt Score Low or Rate Limit Hit\n        API--\u003e\u003eFrontend: 403 Forbidden / 429 Too Many Requests\n        Frontend--\u003e\u003eUser: Show Error Message\n    else Security Passed\n        API-\u003e\u003e+CRUD: Check cache (ScanHistoryBPOM)\n\n        alt Data Cached\n            CRUD--\u003e\u003eAPI: Return cached data\n            API-\u003e\u003eCRUD: Create Scan History (No scraping)\n        else Cache Miss\n            API-\u003e\u003e+BPOMScraper: Search BPOM (Scraping)\n            BPOMScraper--\u003e\u003eAPI: Product details\n            API-\u003e\u003eCRUD: Create BPOM Cache\n            API-\u003e\u003eCRUD: Create Scan History\n        end\n\n        API--\u003e\u003e-Frontend: Validation Result JSON\n        Frontend--\u003e\u003eUser: Display Product Data\n    end\n    deactivate Frontend\n```\n\n**Benefit Caching:** Hasil _scraping_ disimpan dalam _database_ (`bpom_cache`) untuk menghemat _resource_ dan memberikan respons cepat.\n\n**Sample Response:**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"registration_number\": \"MD 272831023097\",\n    \"product_name\": \"Indomie Goreng\",\n    \"brand\": \"PT Indofood CBP Sukses Makmur Tbk\",\n    \"status\": \"TERDAFTAR\",\n    \"expiry_date\": \"2028-12-31\",\n    \"cached\": false\n  }\n}\n```\n\n### 3\\. Allergen Cross-Reference (Personalisasi)\n\n_Endpoint_ `/api/scan/analyze` secara otomatis memeriksa bahan-bahan yang diidentifikasi oleh AI terhadap daftar alergi yang tersimpan di profil pengguna.\n\n- Daftar alergi pengguna diambil dari _database_ (`current_user.allergies`).\n- Daftar bahan (`ingredients`) dari hasil AI diubah menjadi huruf kecil dan diperiksa keberadaan alergen yang telah diatur oleh pengguna.\n- Alergen yang terdeteksi ditambahkan ke dalam _field_ `warnings` sebelum disimpan ke `ScanHistoryOCR` dan ditampilkan kepada pengguna.\n\n### 4\\. Food Catalog (Database Makanan)\n\nAkses cepat ke database internal yang berisi **4.122 data produk** makanan dan minuman yang telah terkurasi.\n\n**Fitur Utama:**\n\n- **Pencarian Cepat (`/api/food/search`):** Mencari produk berdasarkan nama atau merek.\n- **Detail Nutrisi:** Menampilkan informasi nilai gizi (AKG), komposisi, dan takaran saji tanpa perlu melakukan scan ulang.\n- **Pagination:** Mendukung _infinite scroll_ atau _pagination_ untuk menjelajahi katalog.\n\n**Data Point:**\n\n- 4.122 entri produk unik.\n- Mencakup kategori: Makanan Ringan, Minuman, Produk Susu, Makanan Instan, dll.\n\n### 5\\. Favorites Management\n\nPengguna dapat menyimpan produk hasil scan atau pencarian ke dalam daftar favorit untuk akses cepat di kemudian hari.\n\n- **Endpoint:** `/api/favorites`\n- **Fungsi:** Simpan (`POST`), Hapus (`DELETE`), dan Lihat Daftar (`GET`) produk favorit.\n- **Integrasi:** Terhubung langsung dengan _Food Catalog_ dan _Scan History_.\n\n### 6\\. GiziPedia (Education Hub)\n\n**Content Structure:**\n\n- **Categories:** Zat Gizi Makro, Zat Gizi Mikro, Aditif Makanan, Label \u0026 Istilah\n- **Articles:** 100 artikel edukasi\n- **Format:** Markdown-based dengan images\n- **Search:** Full-text search dengan relevance ranking\n\n**Features:**\n\n- Rich text editor (admin)\n- Category filtering\n- Bookmark system\n- Reading time estimate\n- Related articles\n\n### 7\\. Allergen Management System\n\nManajemen data alergen yang dinamis.\n\n**Allergen Database:**\nAdmin dapat mengelola master data alergen (cth: Kacang, Susu, Gluten, Seafood) yang nantinya dipilih oleh user di profil mereka.\n\n**Detection Logic (Actual Implementation):**\n\n```python\n# app/routers/scan.py\nuser_allergies = [allergy.name.lower() for allergy in current_user.allergies]\ningredients_text = result.get('ingredients', '').lower()\n\ndetected_allergens = [\n    allergy.capitalize()\n    for allergy in user_allergies\n    if allergy in ingredients_text\n]\n# Result: [\"Kacang Tanah\", \"Gluten\"]\n```\n\n### 8\\. Scan History \u0026 Analytics\n\nSetiap aktivitas scan (OCR maupun BPOM) disimpan untuk referensi pengguna.\n\n- **Riwayat Terpisah:** Tab khusus untuk Riwayat OCR dan Riwayat BPOM.\n- **Detail View:** Pengguna dapat melihat kembali detail nutrisi dan hasil analisis AI dari produk yang pernah discan sebelumnya.\n- **Admin Analytics:** Admin dapat memantau jumlah scan harian untuk mengevaluasi penggunaan sistem.\n\n---\n\n## SECURITY \u0026 PROTECTION MECHANISMS\n\nAplikasi ini menerapkan standar keamanan tinggi untuk mencegah _abuse_ dan _brute-force attacks_.\n\n### 1. Google reCAPTCHA v3 (Invisible / Smart)\n\nSistem membedakan antara manusia dan bot tanpa mengganggu pengalaman pengguna (tanpa puzzle \"pilih lampu merah\").\n\n- **Frontend:** Menggunakan `react-google-recaptcha-v3` untuk menghasilkan token berdasarkan interaksi user.\n- **Backend:** Middleware memverifikasi token ke server Google sebelum memproses request sensitif.\n- **Penerapan:** Login, Register, Forgot Password, Scan BPOM, dan Scan AI.\n\n### 2. IP-Based Rate Limiting\n\nMenggunakan `slowapi` untuk membatasi jumlah request dari satu IP address dalam periode waktu tertentu.\n\n- **Login/Register/Reset Password:** Maksimal **5 request/menit** (Mencegah Brute Force).\n- **Forgot Password:** Maksimal **3 request/jam** (Mencegah Spam Email).\n- **AI Analysis:** Maksimal **10 request/hari** (Guest / User) untuk menghemat kuota API Gemini.\n\n### 3. Session \u0026 Quota Management\n\n- **Guest Mode:** User tanpa login bisa mencoba scan terbatas (dilacak via IP \u0026 Session Header).\n- **Registered User:** Riwayat tersimpan permanen.\n\n---\n\n## TECHNOLOGY STACK\n\n### Frontend Architecture\n\n```\nReact 18 (Vite 6)\n├── Routing: React Router v7\n├── State: TanStack Query v5 + Context API\n├── UI: Tailwind CSS 3 + Framer Motion (Animation) + Lucide React (Icons)\n├── Forms: React Hook Form + Zod validation\n├── HTTP: Axios\n├── Scanner: html5-qrcode\n├── Charts: Chart.js + react-chartjs-2\n└── Build: Vite 6 (ES modules)\n```\n\n**Key Dependencies (`package.json`):**\n\n```json\n{\n  \"react\": \"^18.3.1\",\n  \"vite\": \"^6.0.5\",\n  \"react-router-dom\": \"^7.1.1\",\n  \"@tanstack/react-query\": \"^5.64.1\",\n  \"tailwindcss\": \"^3.4.17\",\n  \"axios\": \"^1.7.9\",\n  \"html5-qrcode\": \"^2.3.8\",\n  \"chart.js\": \"^4.4.7\",\n  \"react-chartjs-2\": \"^5.3.0\",\n  \"react-hook-form\": \"^7.54.2\",\n  \"zod\": \"^3.24.1\",\n  \"framer-motion\": \"^11.16.0\",\n  \"lucide-react\": \"^0.471.0\"\n}\n```\n\n**Folder Structure:**\n\n```\nfrontend/\n├── public/\n└── vite.config.js\n\nfrontend/src/\n├── assets/\n├── components/\n│   ├── layouts/        # Header, Footer, MainLayout\n│   ├── scanner/        # Komponen Scanner Modular\n│   │   ├── CameraView.jsx\n│   │   └── ScanResult.jsx\n│   └── ui/             # Reusable UI Components (Button, Card, Modal, dll)\n├── config/             # Konfigurasi Axios/API\n├── context/            # Global State (AuthContext)\n├── hooks/              # Custom Hooks\n│   ├── useScannerCamera.js\n│   ├── useSmartCaptcha.js\n│   └── ...\n├── i18n/               # Multi-language (ID/EN)\n├── pages/              # Halaman Aplikasi\n│   ├── admin/          # Dashboard Admin\n│   ├── Scanner.jsx     # Halaman Utama Scanner\n│   ├── Login.jsx\n│   └── ...\n├── routes/             # Routing \u0026 Protection (ProtectedRoute)\n└── utils/              # Helper functions\n```\n\n### Backend Architecture\n\n```\nFastAPI + Python 3.11\n├── ORM: SQLAlchemy 2.0\n├── Database: PyMySQL (MariaDB connector)\n├── Validation: Pydantic v2\n├── Auth: JWT (python-jose) + Passlib (bcrypt)\n├── AI: google-genai (Google DeepMind SDK terbaru)\n├── OCR: Pytesseract (Tesseract OCR Wrapper)\n├── Scraping: HTTPX + BeautifulSoup4\n├── Image Processing: Pillow\n└── Server: Uvicorn (ASGI)\n```\n\n**Key Dependencies (`requirements.txt`):**\n\n```python\nfastapi\u003e=0.100.0\nuvicorn\u003e=0.20.0\npython-multipart\u003e=0.0.6\nsqlalchemy\u003e=2.0.0\npymysql\u003e=1.0.0\npydantic\u003e=2.0.0\npydantic-settings\u003e=2.0.0\npytesseract\npytz\nslowapi\nemail-validator\u003e=2.0.0\npython-jose[cryptography]\u003e=3.3.0\npasslib\u003e=1.7.4\nbcrypt==4.0.1\npython-dotenv\u003e=1.0.0\ngoogle-genai\u003e=0.1.0\nbeautifulsoup4\u003e=4.12.0\nhttpx\u003e=0.24.0\npillow\u003e=10.0.0\nrequests\u003e=2.31.0\n```\n\n**Project Structure:**\n\n```\nBackend (FastAPI)\nbackend/\n├── app/\n│   ├── core/           # Konfigurasi inti (DB, Security, Limiter)\n│   │   ├── config.py\n│   │   ├── database.py\n│   │   ├── limiter.py  \u003c-- Rate Limiter Instance\n│   │   └── security.py\n│   ├── crud/           # Database Operations (Create, Read, Update, Delete)\n│   ├── models/         # SQLAlchemy ORM Models (Tabel Database)\n│   ├── routers/        # API Endpoints (Controller)\n│   │   ├── auth.py     \u003c-- Login/Register logic\n│   │   ├── scan.py     \u003c-- Logic Scanner Utama\n│   │   └── ...\n│   ├── schemas/        # Pydantic Models (Data Validation)\n│   ├── services/       # External Services Logic\n│   │   ├── ai_service.py      \u003c-- Integrasi Google Gemini\n│   │   └── bpom_endpoint.py   \u003c-- Scraper BPOM\n│   └── dependencies.py # Dependency Injection (Auth, Captcha)\n├── main.py             # Entry Point Aplikasi\n└── requirements.txt\n```\n\n### Database Schema\n\n**Technology:** MariaDB 11.4.4 (via PyMySQL)\n\n**Schema Design:**\n\n```sql\n-- Users \u0026 Authentication\nusers (14 columns)\n├── id (PK)\n├── email (UNIQUE), password_hash, full_name\n├── role (enum: user, admin, owner)\n├── gender, age, height, weight\n├── activity_level (enum: sedentary, light, moderate, active, very_active)\n├── reset_token, reset_token_expires\n└── created_at, updated_at\n\n-- Reference Data\nallergens (\n  id, name, code, category, description,\n  severity_level, created_by, timestamps\n)\nadditives (\n  id, name, code, category, safety_level,\n  description, health_risks, timestamps\n)\n\n-- User Relations\nuser_allergies (id, user_id, allergen_id, notes)\nfavorites (\n  id, user_id,\n  food_id (FK -\u003e foods),\n  scan_ocr_id (FK -\u003e scan_history_ocr),\n  scan_bpom_id (FK -\u003e scan_history_bpom),\n  created_at\n)\n\n-- Core Data: Scan History\nscan_history_ocr (14 columns)\n├── id (PK), user_id (FK)\n├── image_data (LONGTEXT/Base64)\n├── product_name\n├── ocr_raw_data (JSON)      -- Stores calories, protein, etc.\n├── ai_analysis (TEXT)       -- AI Summary\n├── pros (JSON), cons (JSON)\n├── ingredients (TEXT)\n├── warnings (JSON)          -- Includes allergen warnings\n├── health_score (INT), grade (VARCHAR)\n└── is_favorited (BOOL), created_at\n\nscan_history_bpom (10 columns)\n├── id (PK), user_id (FK)\n├── bpom_number, product_name, brand, manufacturer\n├── status (TERDAFTAR, dll)\n├── raw_response (JSON)      -- Full scraped data\n└── is_favorited (BOOL), created_at\n\n-- Core Data: Food Catalog\nfoods (18 columns)\n├── id (PK)\n├── name, brand, barcode\n├── serving_size, calories, proteins, fats, carbs\n├── fiber, sugar, sodium\n├── ingredients, image_url\n├── external_id, data_source\n└── timestamps\n\n-- Caching \u0026 Content\nbpom_cache (id, bpom_number, data (JSON), timestamps)\narticles (id, title, slug, content, category_id, status, views, timestamps)\narticle_categories (id, name, slug, description)\n```\n\n**ERD Logic (Simplified):**\n\n```\n      [foods] \u003c───────┐\n                      │\n  [scan_history_ocr] ─┼──► [favorites] ◄── [users] ──► [user_allergies] ──► [allergens]\n                      │\n [scan_history_bpom] ─┘\n```\n\n### Infrastructure \u0026 Deployment\n\n**Frontend Hosting:**\n\n```yaml\nPlatform: VPS (Dedicated Server)\nWeb Server: Nginx 1.24\nSSL: Let's Encrypt\nDeployment: Manual Build (dist/) -\u003e Nginx Serve\n```\n\n**Backend Hosting:**\n\n```yaml\nSetup: Systemctl\nRuntime: Python 3.11\nServer: Uvicorn\nEnvironment: Production\n```\n\n**Database:**\n\n```yaml\nServer: VPS (aaPanel Managed)\nDBMS: MariaDB 11.4.4\nConnection: Remote (PyMySQL) via Host IP\n```\n\n---\n\n## QUICK START (INSTALLATION)\n\n### Prerequisites\n\n```bash\nNode.js 18+\nPython 3.11+\nMariaDB 11.4.4\nGit\n```\n\n### 1\\. Clone Repository\n\n```bash\ngit clone https://github.com/rbwtech/lacak-nutri.git\ncd lacak-nutri\n```\n\n### 2\\. Database Setup\n\n**Create Database:**\n\n```sql\nCREATE DATABASE lacak_nutri CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n```\n\n**Import Schema:**\n\nPastikan Anda berada di _root directory_ project (`lacak-nutri/`).\n\n```bash\nmysql -u root -p lacak_nutri \u003c database/schema.sql\nmysql -u root -p lacak_nutri \u003c database/seed.sql\n```\n\n### 3\\. Backend Configuration\n\n**Install Dependencies:**\n\n```bash\ncd backend\npython -m venv venv\nsource venv/bin/activate  # Windows: venv\\Scripts\\activate\npip install -r requirements.txt\n```\n\n**Environment Variables (.env):**\n\nBuat file `.env` di dalam folder `backend/` dan isi sesuai konfigurasi berikut:\n\n```env\nDB_HOST=localhost\nDB_PORT=3306\nDB_NAME=lacak_nutri\nDB_USER=root\nDB_PASSWORD=your_password\n\nSECRET_KEY=generate_your_secure_secret_key_here\nALGORITHM=HS256\nACCESS_TOKEN_EXPIRE_MINUTES=43200\n\nGEMINI_API_KEY=your_google_gemini_api_key\n\nUPLOAD_DIR=./uploads\nMAX_UPLOAD_SIZE=10485760\n\nCORS_ORIGINS=http://localhost:5173\n\nDEBUG=True\nHOST=0.0.0.0\nPORT=8000\n\nRECAPTCHA_SECRET_KEY=your_recaptcha_v3_server_secret\nEMAIL_SENDER_NAME=\"Lacak Nutri Admin\"\nEMAIL_SENDER_ADDRESS=admin@lacaknutri.com\n\nSMTP_SERVER=smtp.gmail.com\nSMTP_PORT=587\nSMTP_USERNAME=your_email@gmail.com\nSMTP_PASSWORD=your_app_password\n```\n\n**Run Server:**\n\nPastikan _virtual environment_ aktif dan Anda berada di folder `backend/`.\n\n```bash\nuvicorn main:app --reload --host 0.0.0.0 --port 8000\n```\n\nServer: `http://localhost:8000`\nAPI Docs: `http://localhost:8000/docs`\n\n### 4\\. Frontend Configuration\n\n**Install Dependencies:**\n\nBuka terminal baru dan masuk ke folder frontend.\n\n```bash\ncd frontend\nnpm install\n```\n\n**Environment Variables (.env):**\n\nBuat file `.env` di dalam folder `frontend/`.\n\n```env\nVITE_API_URL=http://localhost:8000/api\nVITE_RECAPTCHA_SITE_KEY=your_recaptcha_v3_client_site_key\n```\n\n**Run Development Server:**\n\n```bash\nnpm run dev\n```\n\nFrontend: `http://localhost:5173`\n\n### 5\\. Production Build\n\n**Frontend:**\n\n```bash\nnpm run build\n# Output akan berada di folder: dist/\n```\n\n**Backend:**\n\n```bash\n# Menggunakan Gunicorn (Linux/Mac)\ngunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000\n\n# Atau Uvicorn langsung (Windows/Simple Deploy)\nuvicorn main:app --host 0.0.0.0 --port 8000 --workers 4\n```\n\n---\n\n## DESIGN SYSTEM\n\nSistem desain LacakNutri menggunakan tema kustom Tailwind CSS dengan dukungan penuh untuk **Light Mode** dan **Dark Mode**.\n\n### Color Palette\n\nWarna dikelola menggunakan CSS Variables untuk mendukung pergantian tema yang mulus.\n\n| Color Token            | Light Mode (Hex) | Dark Mode (Hex) | Penggunaan Utama                                 |\n| :--------------------- | :--------------- | :-------------- | :----------------------------------------------- |\n| **Primary**            | `#FF9966`        | `#FF9966`       | Brand identity, CTA buttons, links               |\n| **Primary Hover**      | `#FF7A4D`        | `#FF7A4D`       | Hover states                                     |\n| **Secondary**          | `#6B8E23`        | `#8ABE53`       | Status sehat, verifikasi (adjusted for contrast) |\n| **Accent**             | `#A1D2D5`        | `#5D8A8D`       | Dekorasi, info cards, highlights                 |\n| **Background Base**    | `#FDFDF5`        | `#121212`       | Latar belakang utama aplikasi                    |\n| **Background Surface** | `#FFFFF7`        | `#1E1E1E`       | Kartu (Cards), Modal, Sidebar                    |\n| **Text Primary**       | `#333333`        | `#E0E0E0`       | Judul, konten utama                              |\n| **Text Secondary**     | `#8C8C8C`        | `#A0A0A0`       | Label, metadata, deskripsi singkat               |\n| **Border**             | `#EBE3D5`        | `#333333`       | Garis pemisah, border input                      |\n\n**Status Colors (Hardcoded):**\n\n- Success: `#4CAF50`\n- Warning: `#FFC107`\n- Error: `#EF5350`\n\n### Typography\n\n**Font Family:**\nMenggunakan **Manrope** dari Google Fonts sebagai font utama, dengan fallback ke Inter dan sans-serif.\n\n```css\nfont-family: \"Manrope\", \"Inter\", \"sans-serif\";\n```\n\n**Weights:** 400 (Regular), 500 (Medium), 600 (SemiBold), 700 (Bold), 800 (ExtraBold).\n\n### UI Components Styling\n\nKonfigurasi Tailwind (`tailwind.config.js`) mencakup kustomisasi berikut:\n\n**Border Radius:**\n\n- `rounded-xl`: 12px\n- `rounded-2xl`: 16px\n- `rounded-3xl`: 24px\n\n**Box Shadow:**\n\n- `shadow-soft`: `0 8px 24px rgba(0, 0, 0, 0.05)`\n\n**Animations:**\n\n- **Blob:** Animasi background fluid (`blob 7s infinite`).\n- **Fade In:** Transisi masuk elemen (`fadeIn 0.5s ease-out`).\n\n---\n\n## LICENSE\n\nThis project is licensed under the **MIT License**.\n\n```\nMIT License\n\nCopyright (c) 2025 Trio WakwaW Team\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n```\n\n---\n\n## TEAM\n\n**Trio WakwaW Team** - UINIC 7.0 Web Development Competition\n\n```\n┌─────────────────────────────────────────────────────┐\n│  Made with ❤️ by Trio WakwaW Team\n│\n│  • Radipta Basri Wijaya\n│  • Agung Nugraha\n│  • Bayu Wicaksono\n│\n└─────────────────────────────────────────────────────┘\n```\n\n---\n\n## ACKNOWLEDGEMENT\n\n**Technologies:**\n\n- [FastAPI](https://fastapi.tiangolo.com/) - Modern Python web framework\n- [React](https://react.dev/) - UI library\n- [Gemini AI](https://ai.google.dev/) - Generative AI analysis\n- [BPOM](https://cekbpom.pom.go.id/) - Public product registration database\n\n**Inspiration:**\n\n- MyFitnessPal - Nutrition tracking\n- Open Food Facts - Open food database\n- BPOM Mobile - Product verification\n\n**Competition:**\n\n- UINIC 7.0 Web Development - Universitas Islam Negeri Sunan Kalijaga Yogyakarta\n\n---\n\n## SUPPORT\n\n**Issues \u0026 Bugs:**  \nReport via [GitHub Issues](https://github.com/rbwtech/lacak-nutri/issues)\n\n**Feature Requests:**  \nSubmit via [GitHub Discussions](https://github.com/rbwtech/lacak-nutri/discussions)\n\n**General Inquiries:**  \nWhatsApp: wa.me/6285182381003\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**⭐ Star us on GitHub if you find this project useful!**\n\n**LacakNutri** © 2025 Trio WakwaW Team\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frbwtech%2Flacak-nutri","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frbwtech%2Flacak-nutri","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frbwtech%2Flacak-nutri/lists"}