# 🏗️ Architecture Diagram

## System Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                        CLIENT (Browser)                         │
│  - Vietnamese/English language switching (/i18n/)               │
│  - Bootstrap responsive UI                                      │
│  - CKEditor rich text editor                                    │
└────────────────────────┬────────────────────────────────────────┘
                         │ HTTP/HTTPS
                         ↓
┌─────────────────────────────────────────────────────────────────┐
│                    WEB SERVER (Nginx/Gunicorn)                   │
│  - Reverse proxy                                                │
│  - Static files serving                                         │
│  - Media files serving (/media/, /static/)                      │
└────────────────────────┬────────────────────────────────────────┘
                         │
                         ↓
┌─────────────────────────────────────────────────────────────────┐
│                    DJANGO APPLICATION                            │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              Django URLs (i18n_patterns)                │   │
│  │  /                 → BmcBase.urls                       │   │
│  │  /admin/           → Django Admin                       │   │
│  │  /ckeditor/        → CKEditor Upload Handler            │   │
│  └─────────────────────────────────────────────────────────┘   │
│                         │                                       │
│         ┌───────────────┼───────────────┬──────────────┐       │
│         ↓               ↓               ↓              ↓       │
│  ┌─────────────┐ ┌────────────┐ ┌─────────────┐ ┌──────────┐  │
│  │   Views     │ │    Forms   │ │  Templates  │ │  Static  │  │
│  │             │ │            │ │             │ │  Files   │  │
│  │ - index()   │ │ BinhLuan   │ │ - base.html │ │ - CSS    │  │
│  │ - blog()    │ │ Form       │ │ - index.html│ │ - JS     │  │
│  │ - products()│ │            │ │ - blog.html │ │ - Images │  │
│  │ - careers() │ │            │ │ - products. │ │ - Fonts  │  │
│  │ - contact() │ │            │ │   html      │ │          │  │
│  │ - search()  │ │            │ │ - careers.  │ │ CKEditor │  │
│  │ - comments()│ │            │ │   html      │ │          │  │
│  │ ...         │ │            │ │ ...         │ │          │  │
│  └──────┬──────┘ └────────────┘ └─────────────┘ └──────────┘  │
│         │                                                      │
│         └──────────────────────┬──────────────────────────────┘ │
│                                │                               │
│                                ↓                               │
│                      ┌──────────────────┐                      │
│                      │   ORM Models     │                      │
│                      │                  │                      │
│                      │ - KienThuc       │                      │
│                      │ - BinhLuan       │                      │
│                      │ - SanPham        │                      │
│                      │ - Careers        │                      │
│                      │ - ThongBao       │                      │
│                      │ - TinTuc         │                      │
│                      │ - FormLienHe     │                      │
│                      │ - ...            │                      │
│                      └────────┬─────────┘                      │
└───────────────────────────────┼──────────────────────────────┘
                                │
                                ↓
┌─────────────────────────────────────────────────────────────────┐
│                    DATABASE (PostgreSQL)                         │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐  │
│  │  Tables: kienthuc, binhluan, sanpham, careers,          │  │
│  │  thongbao, tintuc, theloaibaiviet, formlienhe, etc.     │  │
│  │                                                          │  │
│  │  Relationships:                                          │  │
│  │  - KienThuc ←M2M→ TheLoaiBaiViet                        │  │
│  │  - KienThuc ←1:M→ BinhLuan                              │  │
│  └─────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                  FILE SYSTEM STORAGE                            │
│                                                                 │
│  /media/                                                       │
│  ├── products/         (Product images)                        │
│  ├── banners/          (Article/Announcement images)           │
│  ├── uploads/          (CKEditor uploads)                      │
│  └── contacts/         (Contact form attachments)              │
│                                                                 │
│  /staticfiles/                                                 │
│  ├── css/              (Bootstrap, custom styles)              │
│  ├── js/               (Bootstrap, jQuery, etc.)               │
│  ├── img/              (Site images)                           │
│  ├── lib/              (Owl carousel, Lightbox, etc.)          │
│  └── ckeditor/         (CKEditor plugin)                       │
└─────────────────────────────────────────────────────────────────┘
```

---

## URL Routing Flow

```
HTTP Request
    │
    ├─ Protocol: /en/... or /vi/...
    │  (i18n_patterns prefix)
    │
    ↓
BMC/urls.py (Main URLconf)
    │
    ├─ path("", include("BmcBase.urls"))
    ├─ path('admin/', admin.site.urls)
    └─ path('ckeditor/', include('ckeditor_uploader.urls'))
    │
    ↓
BmcBase/urls.py (App URLconf)
    │
    ├─ "" → index()
    ├─ "about/" → about()
    ├─ "blog/" → blog()
    ├─ "blog/tim-kiem/" → blog_search()
    ├─ "blog/bai-viet/<id>/" → blog_post()
    ├─ "products/" → products()
    ├─ "products/<id>/" → product_detail()
    ├─ "careers/" → careers()
    ├─ "career/<id>/" → career()
    ├─ "contact/" → contact()
    ├─ "form/" → form_submit()
    ├─ "noti/" → noti()
    ├─ "noti/<id>/" → noti_post()
    └─ ... (20+ routes)
    │
    ↓
View Function
    │
    ├─ Get data from DB
    ├─ Process forms
    ├─ Build context
    └─ Render template
    │
    ↓
Template
    │
    ├─ Extend base.html
    ├─ Load static files
    ├─ Load i18n
    ├─ Display data
    └─ Include forms
    │
    ↓
HTML Response to Client
```

---

## Data Flow: Blog Post Creation & Display

```
CREATION FLOW:
──────────────
Admin visits /admin/BmcBase/kienthuc/
    │
    ├─ Fill form:
    │  - ten (Vietnamese title)
    │  - ten_tieng_anh (English title)
    │  - ngay_dang (Date)
    │  - the_loai (Category) → M2M
    │  - mo_ta (Summary)
    │  - noi_dung (Content with CKEditor)
    │  - banner (Image upload)
    │
    ↓
Click Save
    │
    ↓
KienThuc.objects.create() or .save()
    │
    ├─ Save to database
    ├─ Save image to /media/banners/
    └─ Create M2M relationship with TheLoaiBaiViet
    │
    ↓
Post created (visible immediately)


DISPLAY FLOW:
─────────────
User visits /blog/
    │
    ↓
blog() view executes
    │
    ├─ KienThuc.objects.all().order_by('-ngay_dang')
    ├─ Filter by category if specified
    ├─ Paginate 10/page
    └─ Get all categories
    │
    ↓
Render blog.html with context:
    {
        'notifications': [KienThuc objects],
        'categories': [TheLoaiBaiViet objects],
        'tag_css': [CSS classes]
    }
    │
    ↓
Template loops:
    {% for post in notifications %}
        <article>
            <h2>{{ post.ten }}</h2>
            <p>{{ post.mo_ta }}</p>
            <img src="{{ post.banner.url }}" />
            <a href="{% url 'blog_post' post.id %}">Read More</a>
        </article>
    {% endfor %}
    │
    ↓
HTML sent to browser


DETAIL VIEW & COMMENTS:
──────────────────────
User clicks "Read More"
    │
    ↓
blog_post(request, id_bai_viet) view
    │
    ├─ Get KienThuc by ID
    ├─ Get comments:
    │  BinhLuan.objects.filter(
    │      bai_viet=post,
    │      trang_thai_da_duyet=True
    │  ).order_by('-ngay_dang')[:10]
    ├─ Get categories
    ├─ Find related posts
    │
    ├─ IF POST (comment submission):
    │  │
    │  ├─ Validate BinhLuanForm
    │  ├─ Create comment with:
    │  │  - ten_nguoi_dang (name)
    │  │  - thong_tin_lien_he (contact)
    │  │  - tieu_de (title)
    │  │  - noi_dung (content)
    │  │  - bai_viet = post
    │  │  - trang_thai_da_duyet = False (pending approval)
    │  │
    │  ├─ Save to database
    │  └─ Return success
    │
    ├─ ELSE (GET):
    │  └─ Create empty form
    │
    ↓
Render blog_post.html with:
    {
        'bai_viet': KienThuc,
        'danh_sach_binh_luan': [approved comments],
        'binh_luan_form': BinhLuanForm(),
        'danh_sach_bai_viet_cung_chu_de': [related posts]
    }
    │
    ↓
HTML displays:
    - Post title & content
    - Approved comments
    - Comment form
    - Related posts


ADMIN COMMENT APPROVAL:
──────────────────────
Admin visits /admin/BmcBase/binhluan/
    │
    ├─ Sees list of comments with:
    │  - ten_nguoi_dang
    │  - ngay_dang
    │  - tieu_de
    │  - trang_thai_da_duyet (checkbox)
    │  - bai_viet
    │
    ↓
Admin checks "trang_thai_da_duyet" for comment
    │
    ↓
Admin clicks Save
    │
    ↓
BinhLuan.trang_thai_da_duyet = True
    │
    ↓
Next time user views blog post:
    - Comment appears in list
    - Filtered by trang_thai_da_duyet=True in view
```

---

## Search Flow

```
User searches for "thuốc"
    │
    ↓
Submits form to /blog/tim-kiem/?q=thuốc
    │
    ↓
blog_search() view executes
    │
    ├─ Build SearchVector:
    │  SearchVector("ten", "ten_tieng_anh", 
    │              "mo_ta", "mo_ta_tieng_anh",
    │              "noi_dung", "noi_dung_tieng_anh")
    │
    ├─ Build SearchQuery("thuốc")
    │
    ├─ Use PostgreSQL Full-Text Search:
    │  KienThuc.objects.annotate(
    │      search=search_vector,
    │      rank=SearchRank(search_vector, search_query)
    │  ).filter(search=search_query).order_by("-rank")
    │
    ├─ Results ranked by relevance
    ├─ Paginate 10/page
    │
    ↓
Render blog_search_results.html with:
    {
        'search_results': [paginated results],
        'total_results': count,
        'query': "thuốc"
    }
    │
    ↓
Template displays:
    - Search query in title
    - Result count
    - List of matching posts (ranked)
    - Pagination
```

---

## File Upload Flow

```
User submits contact form with file
    │
    ├─ name, email, phone, message, file
    │
    ↓
form_submit() view receives POST
    │
    ├─ Extract form data
    ├─ Check if file attached
    │  │
    │  ├─ Call _extract_original_upload_name(file)
    │  │  └─ Get: "Báo cáo.pdf"
    │  │  └─ Store in: original_file_name
    │  │
    │  ├─ Call _build_safe_upload_name(file)
    │  │  └─ slugify("Báo cáo") → "bao-cao"
    │  │  └─ Generate UUID[:10] → "a1b2c3d4e5"
    │  │  └─ Return: "bao-cao-a1b2c3d4e5.pdf"
    │  │
    │  ├─ Save to /media/contacts/bao-cao-a1b2c3d4e5.pdf
    │  │
    │  └─ Store in model: submission.file
    │
    ├─ Create FormLienHe record:
    │  {
    │      ten: "John",
    │      email: "john@example.com",
    │      so_dien_thoai: "0123456789",
    │      loai_khach_hang: "khach_hang_moi",
    │      noi_dung: "Hello...",
    │      original_file_name: "Báo cáo.pdf",
    │      file: "contacts/bao-cao-a1b2c3d4e5.pdf"
    │  }
    │
    ↓
submission.save()
    │
    ├─ Data saved to database
    ├─ File safely stored with unique name
    └─ No directory traversal possible
    │
    ↓
Redirect to /
    │
    ↓
Admin can download file from:
    /admin/BmcBase/formlienhe/
```

---

## Pagination Pattern Used

```
products() view (6 separate paginators)
    │
    ├─ All Products:
    │  Paginator(SanPham.objects.all(), 12)
    │  Page param: ?products_page=2
    │
    ├─ Insecticides (thuốc sâu):
    │  Paginator(SanPham.objects.filter(loai="thuốc sâu"), 12)
    │  Page param: ?thuocsaus_page=2
    │
    ├─ Disease Control (thuốc trừ bệnh):
    │  Paginator(SanPham.objects.filter(loai="thuốc trừ bệnh"), 12)
    │  Page param: ?thuoctrubenhs_page=2
    │
    ├─ Herbicides (thuốc cỏ):
    │  Paginator(SanPham.objects.filter(loai="thuốc cỏ"), 12)
    │  Page param: ?thuoccos_page=2
    │
    ├─ Growth Stimulants (thuốc sinh trưởng):
    │  Paginator(SanPham.objects.filter(loai="thuốc sinh trưởng"), 12)
    │  Page param: ?thuocsinhtruongs_page=2
    │
    └─ Pumps (bình bơm):
       Paginator(SanPhamBinhBom.objects.all(), 12)
       Page param: ?binh_bom_page=2

Note: This pattern works but is complex.
Better approach: Use AJAX tabs or separate pages.
```

---

## Database Relationships

```
                      TheLoaiBaiViet
                      ┌──────────────┐
                      │ id (PK)      │
                      │ ten          │
                      │ ten_tieng_anh│
                      │ mo_ta        │
                      └──────┬───────┘
                             │ (M2M)
                             │
                             ↕ through KienThuc_the_loai
                             │
                      ┌──────┴───────┐
                      │  KienThuc    │
                      ├──────────────┤
                      │ id (PK)      │
                      │ ten          │
                      │ ten_tieng_anh│
                      │ ngay_dang    │
                      │ mo_ta        │
                      │ noi_dung     │
                      │ banner       │
                      └──────┬───────┘
                             │ (1:M via related_name)
                             │
                             ↓
                      ┌──────────────┐
                      │  BinhLuan    │
                      ├──────────────┤
                      │ id (PK)      │
                      │ ten_nguoi... │
                      │ tieu_de      │
                      │ noi_dung     │
                      │ ngay_dang    │
                      │ trang_thai..│
                      │ bai_viet(FK) │
                      └──────────────┘


  SanPham                    SanPhamBinhBom
  ┌────────────┐            ┌────────────┐
  │ id (PK)    │            │ id (PK)    │
  │ ten        │            │ ten        │
  │ ten_en     │            │ ac_quy     │
  │ hinh_anh   │            │ dung_tich  │
  │ loai       │ (hardcoded)│ trong_luong│
  │ thanh_phan │            │ gia        │
  │ hang_sx    │            └────────────┘
  │ dac_tinh   │
  │ hdsd       │
  │ khuyen_mai │
  │ gia        │
  └────────────┘


  Careers                    FormLienHe
  ┌────────────┐            ┌────────────┐
  │ id (PK)    │            │ id (PK)    │
  │ tieu_de    │            │ ten        │
  │ tieu_de_en │            │ email      │
  │ ngay_dang  │            │ so_dien..  │
  │ noi_dung..│            │ loai_khach │
  │ muc_luong..│            │ noi_dung   │
  │ muc_luong..│            │ file       │
  └────────────┘            │ original...│
                            └────────────┘
```

---

## Technology Stack Diagram

```
┌──────────────────────────────────────────────────────────────┐
│                    Frontend (Client)                         │
│  HTML5 + CSS3 + JavaScript                                   │
│  Bootstrap 5 Framework                                       │
│  Font Awesome Icons                                          │
│  Owl Carousel (image slider)                                 │
│  Lightbox (image gallery)                                    │
│  CKEditor 4 (rich text editor - frontend)                    │
└──────────────────────────┬───────────────────────────────────┘
                           │
┌──────────────────────────┴───────────────────────────────────┐
│                    Backend (Server)                          │
│                                                              │
│  Django 4.0 (Python Web Framework)                           │
│  ├─ URLs Routing                                             │
│  ├─ Views (Function-based)                                   │
│  ├─ Templates (Jinja2-like syntax)                           │
│  ├─ Models (ORM)                                             │
│  ├─ Forms                                                    │
│  ├─ Admin Site                                               │
│  └─ Middleware                                               │
│                                                              │
│  Additional Libraries:                                       │
│  ├─ django-ckeditor                                          │
│  ├─ django-ckeditor-uploader                                 │
│  ├─ Pillow (Image processing)                                │
│  ├─ psycopg2 (PostgreSQL driver)                              │
│  └─ Django i18n (Internationalization)                       │
└──────────────────────────┬───────────────────────────────────┘
                           │
┌──────────────────────────┴───────────────────────────────────┐
│                    Database                                  │
│                                                              │
│  PostgreSQL 12+                                              │
│  ├─ Full-Text Search (FTS)                                   │
│  ├─ JSONB support                                            │
│  ├─ Relationships (FK, M2M)                                   │
│  └─ Advanced Indexing                                        │
└──────────────────────────────────────────────────────────────┘
```

---

## Deployment Architecture (Recommended)

```
┌─────────────────────────────────────────────────────────┐
│              Client (User Browser)                      │
└──────────────────┬──────────────────────────────────────┘
                   │ HTTPS
                   ↓
┌─────────────────────────────────────────────────────────┐
│         Reverse Proxy / Load Balancer                   │
│  (Nginx, HAProxy, or CloudFlare)                        │
│  - SSL/TLS termination                                  │
│  - Cache static files                                   │
│  - Compress responses                                   │
└──────────────────┬──────────────────────────────────────┘
                   │ HTTP
                   ↓
        ┌──────────┴──────────┐
        ↓                     ↓
    ┌────────────┐      ┌────────────┐
    │ Gunicorn 1 │      │ Gunicorn 2 │ (Load balanced)
    └────┬───────┘      └────┬───────┘
         │                   │
         └──────────┬────────┘
                    ↓
         ┌──────────────────┐
         │   Django App     │
         │  (BMC Website)   │
         └──────────┬───────┘
                    │
                    ↓
         ┌──────────────────┐
         │   PostgreSQL DB  │
         │  (Primary)       │
         │  - Main data     │
         │  - Search index  │
         └──────────────────┘
         
         ┌──────────────────┐
         │ PostgreSQL DB    │
         │ (Replica/Backup) │
         └──────────────────┘

         ┌──────────────────┐
         │  File Storage    │
         │  /media/         │
         │  /staticfiles/   │
         │  (Or S3, CDN)    │
         └──────────────────┘
```

---

**Diagram Version**: 1.0  
**Last Updated**: 18/04/2026
