-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
432 lines (415 loc) · 31.5 KB
/
index.html
File metadata and controls
432 lines (415 loc) · 31.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tài liệu vận hành hệ thống WordPress</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Chosen Palette: Calm Harmony -->
<!-- Application Structure Plan: The application uses a tabbed navigation structure on a left sidebar (on desktop) to break down the dense technical document into logical, self-contained sections (Source Code, Development, Deployment, etc.). On mobile, these tabs collapse to a top navigation. This task-oriented design allows users (developers) to quickly find specific procedures without linear scrolling, which is more efficient for a reference guide. Key processes like the Git branching model are visualized for better comprehension. -->
<!-- Visualization & Content Choices: Git Branching Model -> Goal: Organize -> Viz: HTML/CSS diagram with hover tooltips for intuitive understanding of branch relationships. Workflows -> Goal: Inform -> Viz: HTML/CSS flowcharts to clarify the sequence of actions. LocalWP Setup -> Goal: Inform -> Presentation: Checklist with copyable code blocks containing individually copyable lines to make technical steps easy to follow and reduce errors. CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
<!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f8fafc; /* slate-50 */
}
.tab-active {
border-left-color: #0d9488; /* teal-600 */
color: #0d9488;
background-color: #f0fdfa; /* teal-50 */
}
.tab-inactive {
border-left-color: transparent;
color: #475569; /* slate-600 */
}
/* Mobile: Top tabs */
@media (max-width: 767px) {
.tab-btn {
border-left-color: transparent !important; /* Override for mobile */
border-bottom-color: transparent !important; /* Reset default */
}
.tab-active {
border-bottom-color: #0d9488 !important; /* Active bottom border for mobile */
}
}
.code-block {
background-color: #1e293b; /* slate-800 */
color: #e2e8f0; /* slate-200 */
padding: 1rem;
border-radius: 0.5rem;
position: relative;
font-family: 'Courier New', Courier, monospace;
}
.code-line {
line-height: 1.5;
padding-right: 2.5rem; /* Space for copy button */
}
.copy-line-btn {
position: absolute;
right: 0.5rem;
top: 50%;
transform: translateY(-50%);
background-color: #334155; /* slate-700 */
color: #cbd5e1; /* slate-300 */
border: none;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
cursor: pointer;
font-size: 0.8rem;
display: none; /* Hidden by default */
}
.code-line:hover .copy-line-btn {
display: block; /* Show on hover */
}
.flowchart-step {
border: 1px solid #cbd5e1; /* slate-300 */
border-radius: 0.5rem;
padding: 1rem;
text-align: center;
background-color: white;
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
}
.flowchart-arrow {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: #94a3b8; /* slate-400 */
}
</style>
</head>
<body class="text-slate-800">
<div class="container mx-auto p-4 md:p-8">
<header class="text-center mb-8">
<h1 class="text-3xl md:text-4xl font-bold text-teal-700">Tài liệu vận hành hệ thống WordPress</h1>
<p class="mt-2 text-lg text-slate-600">Hướng dẫn tương tác về quy trình làm việc và triển khai dự án.</p>
</header>
<div class="md:grid md:grid-cols-[250px_1fr] md:gap-8">
<!-- Sidebar Navigation -->
<nav class="flex flex-wrap md:flex-col md:items-start border-b border-slate-300 md:border-b-0 md:border-r md:pr-4 mb-4 md:mb-0">
<button data-tab="tab-source-code" class="tab-btn py-2 px-4 md:px-6 font-semibold border-b-2 md:border-b-0 md:border-l-2 transition-colors duration-200 tab-active w-full text-left">Quản lý Source Code</button>
<button data-tab="tab-development" class="tab-btn py-2 px-4 md:px-6 font-semibold border-b-2 md:border-b-0 md:border-l-2 transition-colors duration-200 tab-inactive w-full text-left">Quy trình Development</button>
<button data-tab="tab-deployment" class="tab-btn py-2 px-4 md:px-6 font-semibold border-b-2 md:border-b-0 md:border-l-2 transition-colors duration-200 tab-inactive w-full text-left">Quy trình Deployment</button>
<button data-tab="tab-backup" class="tab-btn py-2 px-4 md:px-6 font-semibold border-b-2 md:border-b-0 md:border-l-2 transition-colors duration-200 tab-inactive w-full text-left">Backup & Phục hồi</button>
<button data-tab="tab-database" class="tab-btn py-2 px-4 md:px-6 font-semibold border-b-2 md:border-b-0 md:border-l-2 transition-colors duration-200 tab-inactive w-full text-left">Quản lý Database</button>
</nav>
<!-- Main Content Area -->
<main class="md:col-span-1">
<!-- Tab: Quản lý Source Code -->
<section id="tab-source-code" class="tab-content space-y-8">
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Cấu trúc Repository</h2>
<p class="mb-6 text-slate-600">Dự án tuân thủ một cấu trúc phân nhánh rõ ràng để đảm bảo sự ổn định và dễ quản lý. Sơ đồ dưới đây minh họa mối quan hệ giữa các nhánh chính.</p>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200 overflow-x-auto">
<div class="grid grid-cols-6 gap-4 text-center text-sm font-medium min-w-[720px]">
<div class="p-3 bg-red-100 text-red-800 rounded-md border border-red-200">production</div>
<div class="p-3 bg-blue-100 text-blue-800 rounded-md border border-blue-200">master</div>
<div class="p-3 bg-green-100 text-green-800 rounded-md border border-green-200">feature/*</div>
<div class="p-3 bg-orange-100 text-orange-800 rounded-md border border-orange-200">hotfix/*</div>
<div class="p-3 bg-purple-100 text-purple-800 rounded-md border border-purple-200">production-temp</div>
<div class="p-3 bg-yellow-100 text-yellow-800 rounded-md border border-yellow-200">bugfix/*</div>
</div>
<div class="mt-4 text-slate-500 text-xs text-center">
<p><span class="font-bold text-red-800">production:</span> Nhánh chính cho môi trường Production.</p>
<p><span class="font-bold text-blue-800">master:</span> Nhánh chính cho môi trường Staging/Development.</p>
<p><span class="font-bold text-green-800">feature/*:</span> Nhánh phát triển tính năng mới, tạo từ `master`.</p>
<p><span class="font-bold text-orange-800">hotfix/*:</span> Nhánh sửa lỗi khẩn cấp, tạo từ `production`.</p>
<p><span class="font-bold text-purple-800">production-temp:</span> Nhánh chuẩn bị cho bản phát hành, tạo từ `master`.</p>
<p><span class="font-bold text-yellow-800">bugfix/*:</span> Nhánh sửa lỗi thông thường, tạo từ `master`.</p>
</div>
</div>
</div>
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Quy trình làm việc với Git</h2>
<p class="mb-6 text-slate-600">Dưới đây là các luồng công việc chính khi phát triển tính năng mới và sửa lỗi.</p>
<div class="grid md:grid-cols-2 gap-8">
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-4">Phát triển tính năng mới</h3>
<div class="space-y-4">
<div class="flowchart-step">Tạo nhánh `feature/*` từ `master`</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Viết code & commit</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Tạo Pull Request (PR) vào `master`</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Review code & gộp (merge)</div>
</div>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-4">Sửa lỗi khẩn cấp (Hotfix từ `production`)</h3>
<div class="space-y-4">
<div class="flowchart-step">Tạo nhánh `hotfix/*` từ `production`</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Sửa lỗi & commit</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Tạo PR vào `production`</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Review code & gộp (merge)</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Gộp `hotfix` vào `master` để đồng bộ</div>
</div>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200 md:col-span-2">
<h3 class="text-xl font-semibold mb-4">Sửa lỗi thông thường (Bugfix từ `master`)</h3>
<p class="mb-4 text-slate-600">Đây là quy trình để sửa các lỗi được phát hiện trong quá trình phát triển hoặc trên môi trường Staging/Development.</p>
<div class="space-y-4 max-w-lg mx-auto">
<div class="flowchart-step">Tạo nhánh `bugfix/*` từ `master`</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Sửa lỗi & commit</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Tạo Pull Request (PR) vào `master`</div>
<div class="flowchart-arrow">↓</div>
<div class="flowchart-step">Review code & gộp (merge)</div>
</div>
</div>
</div>
</div>
</section>
<!-- Tab: Quy trình Development -->
<section id="tab-development" class="tab-content space-y-8 hidden">
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Môi trường phát triển</h2>
<p class="mb-6 text-slate-600">Dự án sử dụng ba môi trường riêng biệt để đảm bảo chất lượng và sự ổn định từ lúc phát triển đến khi triển khai.</p>
<div class="grid md:grid-cols-3 gap-6">
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Local Development</h3>
<p class="text-slate-600">Môi trường làm việc trên máy tính cá nhân của lập trình viên. Sử dụng LocalWP để tạo và quản lý.</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Staging/Test</h3>
<p class="text-slate-600">Môi trường thử nghiệm, mô phỏng môi trường Production. Triển khai từ nhánh `master` để kiểm thử tích hợp.</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Production</h3>
<p class="text-slate-600">Môi trường thật, nơi người dùng cuối truy cập. Triển khai từ nhánh `production` sau khi đã kiểm thử kỹ lưỡng.</p>
</div>
</div>
</div>
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Các bước khởi tạo dự án trên LocalWP</h2>
<p class="mb-6 text-slate-600">Để thiết lập một dự án WordPress hiện có trên môi trường LocalWP, hãy làm theo các bước sau:</p>
<ol class="space-y-6">
<li class="flex items-start">
<span class="flex-shrink-0 w-8 h-8 bg-teal-600 text-white font-bold rounded-full flex items-center justify-center mr-4">1</span>
<div>
<h4 class="font-semibold">Tạo dự án WordPress mặc định trong LocalWP</h4>
<p class="text-slate-600">Mở LocalWP, chọn "Add Local Site", đặt tên và tạo một trang WordPress mới với cấu hình mặc định.</p>
</div>
</li>
<li class="flex items-start">
<span class="flex-shrink-0 w-8 h-8 bg-teal-600 text-white font-bold rounded-full flex items-center justify-center mr-4">2</span>
<div>
<h4 class="font-semibold">Sao chép mã nguồn từ Git</h4>
<p class="text-slate-600 mb-2">Điều hướng đến thư mục `app/public` của dự án vừa tạo. Giữ lại file `wp-config.php`, xóa các file còn lại. Mở terminal và chạy các lệnh sau:</p>
<div class="code-block">
<div class="code-line relative group">
<span>git init</span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
<div class="code-line relative group">
<span>git remote add origin <URL_repository_của_bạn></span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
<div class="code-line relative group">
<span>git fetch origin</span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
<div class="code-line relative group">
<span>git reset --hard origin/master</span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
</div>
</div>
</li>
<li class="flex items-start">
<span class="flex-shrink-0 w-8 h-8 bg-teal-600 text-white font-bold rounded-full flex items-center justify-center mr-4">3</span>
<div>
<h4 class="font-semibold">Import cơ sở dữ liệu dự án</h4>
<p class="text-slate-600 mb-2">Đầu tiên, sao chép file `.sql` của cơ sở dữ liệu dự án vào thư mục `app/public` (hoặc bất kỳ thư mục nào bạn dễ dàng truy cập). Sau đó, mở "Site Shell" (WP-CLI) trong LocalWP và chạy lệnh sau để import database:</p>
<div class="code-block">
<div class="code-line relative group">
<span>wp db import <ten_file_backup.sql></span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
</div>
<p class="text-slate-600 mt-2">Thay thế `<ten_file_backup.sql>` bằng tên file `.sql` của bạn.</p>
</div>
</li>
<li class="flex items-start">
<span class="flex-shrink-0 w-8 h-8 bg-teal-600 text-white font-bold rounded-full flex items-center justify-center mr-4">4</span>
<div>
<h4 class="font-semibold">Cập nhật URL trong cơ sở dữ liệu</h4>
<p class="text-slate-600 mb-2">Mở "Site Shell" (WP-CLI) trong LocalWP và chạy các lệnh sau để cập nhật URL cho môi trường local:</p>
<div class="code-block">
<div class="code-line relative group">
<span>wp option update siteurl "http://your-project-name.local"</span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
<div class="code-line relative group">
<span>wp option update home "http://your-project-name.local"</span>
<button class="copy-line-btn" onclick="copySingleLine(this)">Copy</button>
</div>
</div>
</div>
</li>
<li class="flex items-start">
<span class="flex-shrink-0 w-8 h-8 bg-teal-600 text-white font-bold rounded-full flex items-center justify-center mr-4">5</span>
<div>
<h4 class="font-semibold">Khởi động lại và kiểm tra</h4>
<p class="text-slate-600">Dừng và khởi động lại dự án trong LocalWP. Sau đó, **mở trình duyệt và gõ local domain của dự án** (ví dụ: `your-project-name.local`) để xem website đã hiển thị chính xác chưa.</p>
</div>
</li>
</ol>
</div>
</section>
<!-- Tab: Quy trình Deployment -->
<section id="tab-deployment" class="tab-content space-y-8 hidden">
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Điều kiện môi trường Hosting</h2>
<p class="mb-6 text-slate-600">Để đảm bảo quá trình triển khai và vận hành diễn ra suôn sẻ, môi trường hosting cần đáp ứng các điều kiện sau:</p>
<ul class="grid md:grid-cols-2 gap-x-8 gap-y-4 list-disc list-inside text-slate-600">
<li>Hỗ trợ <strong>MySQL 5.7+</strong> hoặc MariaDB 10.2+</li>
<li>Hỗ trợ <strong>PHP 8.0+</strong></li>
<li>Hỗ trợ <strong>Git Version Control</strong></li>
<li>Hỗ trợ truy cập <strong>SSH (Secure Shell)</strong></li>
<li>Dung lượng đĩa và RAM đủ lớn</li>
<li>Hỗ trợ cài đặt chứng chỉ <strong>SSL/TLS (HTTPS)</strong></li>
</ul>
</div>
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Phương pháp triển khai</h2>
<p class="mb-6 text-slate-600">Dự án có thể được triển khai thủ công hoặc tự động hóa bằng CI/CD.</p>
<div class="grid md:grid-cols-2 gap-8">
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-4">Triển khai thủ công</h3>
<p class="text-slate-600 mb-2"><strong>Lên Staging (từ `master`):</strong></p>
<ol class="list-decimal list-inside text-slate-600 space-y-1">
<li>Kết nối server qua SSH.</li>
<li>Điều hướng đến thư mục dự án.</li>
<li>Chạy `git pull origin master`.</li>
<li>Chạy các lệnh cần thiết (composer, wp-cli).</li>
</ol>
<p class="text-slate-600 mt-4 mb-2"><strong>Lên Production (từ `production`):</strong></p>
<ol class="list-decimal list-inside text-slate-600 space-y-1">
<li>Sao lưu Production.</li>
<li>Kết nối server qua SSH.</li>
<li>Điều hướng đến thư mục dự án.</li>
<li>Chạy `git pull origin production`.</li>
<li>Chạy các lệnh cần thiết và kiểm tra.</li>
</ol>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-4">Triển khai tự động (CI/CD)</h3>
<p class="text-slate-600 mb-2">Sử dụng các công cụ như GitHub Actions, Jenkins để tự động hóa quy trình:</p>
<ul class="list-disc list-inside text-slate-600 space-y-1">
<li><strong>Tích hợp liên tục (CI):</strong> Tự động chạy kiểm thử khi có code mới.</li>
<li><strong>Triển khai lên Staging:</strong> Tự động triển khai lên Staging khi `master` được cập nhật.</li>
<li><strong>Triển khai lên Production:</strong> Kích hoạt thủ công sau khi đã kiểm thử trên Staging, triển khai từ nhánh `production`.</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Tab: Backup & Phục hồi -->
<section id="tab-backup" class="tab-content space-y-8 hidden">
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Những gì cần sao lưu</h2>
<p class="mb-6 text-slate-600">Sao lưu dữ liệu là cực kỳ quan trọng. Hai thành phần chính cần được sao lưu định kỳ là:</p>
<div class="grid md:grid-cols-2 gap-6">
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Cơ sở dữ liệu (Database)</h3>
<p class="text-slate-600">Chứa tất cả nội dung, bài viết, trang, cài đặt, và dữ liệu người dùng. Đây là phần quan trọng nhất.</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Source code & File Media</h3>
<p class="text-slate-600">Toàn bộ các file WordPress, theme, plugin, và các file media được tải lên trong thư mục `wp-content/uploads`.</p>
</div>
</div>
</div>
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Cách thực hiện sao lưu</h2>
<p class="mb-6 text-slate-600">Nên kết hợp cả hai phương pháp sao lưu tự động và thủ công để đảm bảo an toàn tối đa.</p>
<div class="grid md:grid-cols-2 gap-8">
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-4">Sao lưu tự động (Khuyến nghị)</h3>
<ul class="list-disc list-inside text-slate-600 space-y-2">
<li><strong>Sử dụng Plugin:</strong> Cài đặt các plugin như UpdraftPlus, Duplicator để tự động sao lưu và lưu trữ trên đám mây (Google Drive, S3).</li>
<li><strong>Dịch vụ Hosting:</strong> Tận dụng tính năng sao lưu tự động hàng ngày của nhà cung cấp hosting.</li>
<li><strong>Script Cronjob:</strong> Tự động hóa các lệnh sao lưu database và nén file bằng script.</li>
</ul>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-4">Sao lưu thủ công</h3>
<ul class="list-disc list-inside text-slate-600 space-y-2">
<li><strong>Database:</strong> Sử dụng phpMyAdmin hoặc WP-CLI (`wp db export`) để xuất file `.sql`.</li>
<li><strong>Files:</strong> Sử dụng FTP/SFTP để tải toàn bộ thư mục website về máy tính.</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Tab: Quản lý Database -->
<section id="tab-database" class="tab-content space-y-8 hidden">
<div>
<h2 class="text-2xl font-bold mb-4 text-teal-700">Nguyên tắc quản lý Database</h2>
<p class="mb-6 text-slate-600">Quản lý cơ sở dữ liệu đúng cách là rất quan trọng để tránh các vấn đề về dữ liệu và đồng bộ hóa giữa các môi trường.</p>
<div class="space-y-4">
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Sử dụng Database Migration</h3>
<p class="text-slate-600">Khi có thay đổi về cấu trúc cơ sở dữ liệu (thêm bảng, thay đổi cột), nên sử dụng các công cụ hoặc plugin hỗ trợ migration để đảm bảo các thay đổi này được áp dụng nhất quán trên tất cả các môi trường.</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
<h3 class="text-xl font-semibold mb-2">Tránh chỉnh sửa trực tiếp trên Production</h3>
<p class="text-slate-600">Tuyệt đối không chỉnh sửa cơ sở dữ liệu trực tiếp trên môi trường Production trừ trường hợp khẩn cấp. Mọi thay đổi nên được thực hiện thông qua mã nguồn và quy trình deployment để đảm bảo tính nhất quán và khả năng truy vết.</p>
</div>
</div>
</div>
</section>
</main>
</div>
</div>
<script>
const tabs = document.querySelectorAll('.tab-btn');
const contents = document.querySelectorAll('.tab-content');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const targetId = tab.dataset.tab;
// Update tab active/inactive classes for desktop (left border)
tabs.forEach(t => {
t.classList.remove('tab-active');
t.classList.add('tab-inactive');
});
tab.classList.add('tab-active');
tab.classList.remove('tab-inactive');
// Update content visibility
contents.forEach(content => {
if (content.id === targetId) {
content.classList.remove('hidden');
} else {
content.classList.add('hidden');
}
});
});
});
// Function to copy a single line of code
function copySingleLine(button) {
const lineText = button.previousElementSibling.innerText.trim(); // Get text from the sibling span
const tempTextArea = document.createElement('textarea');
tempTextArea.value = lineText;
document.body.appendChild(tempTextArea);
tempTextArea.select();
document.execCommand('copy');
document.body.removeChild(tempTextArea);
const originalText = button.innerText;
button.innerText = 'Đã chép!';
setTimeout(() => {
button.innerText = originalText;
}, 1500);
}
</script>
</body>
</html>