Có định hướng
Mỗi màn hình có một hành động chính màu Lime. Thứ bậc rõ ràng từ tiêu đề đến nội dung phụ.
Hệ thống thiết kế PineCoco: màu sắc có mục đích, thành phần nhất quán và trải nghiệm được xây từ chính token của sản phẩm.
01 / FOUNDATIONS
Lime tạo điểm nhấn. Ink giúp dễ đọc.
Canvas xám dịu dành không gian cho nội dung.
Mỗi màn hình có một hành động chính màu Lime. Thứ bậc rõ ràng từ tiêu đề đến nội dung phụ.
Dùng token ngữ nghĩa (bg-primary, text-muted-foreground) thay vì mã màu riêng cho từng component.
Chữ đạt tương phản 4.5:1, trạng thái có cả icon và nhãn, vùng chạm tối thiểu 44 px, focus luôn nhìn thấy.
Hành động chính, trạng thái đang chọn và focus ring. Luôn đặt chữ Ink lên trên.
--primarybg-primary--pc-accentInk trên Lime · 12.6:1 · AAA
Trạng thái hover và pressed của nút Lime.
Chỉ có trong Tailwindbg-lime-600--pc-accent-hoverInk trên Lime đậm · 10.1:1 · AAA
Tiêu đề, nội dung chính và nút tương phản cao.
--foregroundtext-foreground--pc-inkInk trên Canvas · 14.7:1 · AAA
Nền trang. Cũng là --secondary và --muted cho vùng nền phụ.
--backgroundbg-background--pc-pageInk trên Canvas (tối) · 15.3:1 · AAA
Thẻ, popover, sheet và ô nhập liệu.
--cardbg-card--pc-surfaceInk trên Surface · 16.3:1 · AAA
Chữ phụ, chú thích, placeholder.
--muted-foregroundtext-muted-foreground--pc-muted = #626871Trang public đặt chữ phụ cỡ nhỏ trên Canvas nên dùng sắc đậm hơn để đạt 4.5:1.
Muted trên Surface · 4.7:1 · AA
Đường viền thẻ, ô nhập liệu và đường phân tách.
--borderborder-border--pc-borderViền trang trí, không mang nghĩa. Ô nhập liệu luôn có nhãn hiển thị.
Nền của thao tác xóa, rời chuyến đi. Chữ lỗi dùng Danger.
--destructivebg-destructive--pc-destructiveChữ trắng trên Destructive · 3.8:1 · Chỉ chữ lớn
text-emerald-700 bg-emerald-50--pc-success · 5.2:1text-amber-700 bg-amber-50--pc-warning · 4.8:1text-red-700 bg-red-50--pc-danger · 5.9:1text-blue-700 bg-blue-50--pc-info · 6.2:1Lime luôn đi với chữ Ink. Không dùng text-primary cho chữ trên nền sáng: Lime trên trắng chỉ đạt 1.3:1. Trạng thái luôn kết hợp icon và nhãn, không chỉ dựa vào màu. Trang public hiện chỉ dùng chế độ sáng; ứng dụng hỗ trợ cả hai qua lớp .dark.
TYPOGRAPHY / MANROPE
Manrope qua next/font, biến --font-manrope. Hỗ trợ tiếng Việt đầy đủ, tiêu đề gọn và ưu tiên khả năng đọc.
text-4xl font-boldtext-xl font-boldtext-sm / text-basetext-xstext-[10px] tracking-widestGEOMETRY / NHỊP 4 PX
142831241662483212481664rounded-lgÔ nhập, nút nhỏrounded-xlÔ icon, chiprounded-2xlThẻrounded-3xlSheet, khối lớnrounded-fullPill, avatar, nút trònSpacing theo thang Tailwind: 1 bước = 4 px. Bo góc lấy từ tailwind.config.ts; thẻ dùng rounded-2xl, nút hành động dùng rounded-full.
Import theo tên từ lucide-react. Icon trang trí có aria-hidden; nút chỉ chứa icon phải có aria-label. Không dùng emoji hay ký tự mũi tên làm icon giao diện.
02 / COMPONENTS
Thử trạng thái trực tiếp.
Các ví dụ này không tạo dữ liệu chuyến đi.
Trạng thái ví dụ: sẵn sàng.
// Trong ứng dụng: class Tailwind gắn với token
<button className="bg-primary text-primary-foreground rounded-full">
Thêm khoản chi
</button>
<div className="bg-card border border-border rounded-2xl p-4">
<p className="text-muted-foreground text-sm">Chữ phụ</p>
</div>/* styles/marketing-tokens.css */
--pc-accent: #c9f158;
--pc-accent-hover: #b5d94e;
--pc-ink: #202020;
--pc-page: #f2f3f5;
--pc-surface: #ffffff;
--pc-muted: #626871;
--pc-border: #e6e6e6;
--pc-destructive: #ef4444;
--pc-success: #047857;
--pc-success-soft: #ecfdf5;
--pc-warning: #b45309;
--pc-warning-soft: #fffbeb;
--pc-danger: #b91c1c;
--pc-danger-soft: #fef2f2;
--pc-info: #1d4ed8;
--pc-info-soft: #eff6ff;Nút sao chép lấy khối --pc-* dành cho trang public.
03 / PRODUCT IN PRACTICE
Ảnh chụp trực tiếp ứng dụng hiện tại.
Viewport 440 × 956 · Chế độ khách.



Chụp từ bản web responsive trên Chromium ở chế độ khách với một chuyến đi minh họa; đây không phải ảnh chụp từ thiết bị iOS vật lý.
04 / DEVELOPMENT
PineCoco dùng phiên NextAuth hoặc phiên khách có chữ ký do máy chủ cấp. Mỗi endpoint kiểm tra quyền truy cập tương ứng.
Tài liệu bên dưới là tham khảo API nội bộ. Đối chiếu route handler trước khi tích hợp; đây chưa phải hợp đồng API công khai cho bên thứ ba.
Mở ứng dụngconst response = await fetch('/api/v3/trips/list', {
credentials: 'same-origin',
headers: { Accept: 'application/json' },
});
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
const trips = await response.json();Chạy trong ứng dụng sau khi có phiên đăng nhập hợp lệ.
05 / API REFERENCE
API nội bộ · JSON · Quyền theo phiên
9 endpoint phù hợp.
/api/v1/auth/send-otpGửi mã OTP 6 chữ số đến emailQuyền truy cập: none
Rate limited: 5 req/min per email
emailsuccessmessage/api/v1/auth/verify-otpXác thực mã OTP, nhận token một lầnQuyền truy cập: none
emailcodeverifiedtempToken/api/v1/auth/signupTạo tài khoản mới sau khi verify OTPQuyền truy cập: none
emailnamepasscodeusersession/api/v1/auth/signinĐăng nhập bằng email + 4-digit passcodeQuyền truy cập: none
emailpasscodeusertoken/api/v1/uploadUpload ảnh hoặc video lên S3 storageQuyền truy cập: user
multipart/form-data · max 10 MB
filetypeurlpublicId/api/v1/upload-avatarUpload avatar, tự động crop và resizeQuyền truy cập: user
fileavatarUrlpublicId/api/v1/scan-billĐọc hóa đơn: danh sách món, phí, thuế và tổng tiền (Gemini Flash-Lite, ~2-3 giây)Quyền truy cập: user
Chỉ tài khoản Pro · multipart/form-data hoặc JSON {text} cho OCR chạy trên thiết bị
imagetextreceiptemptymeta/api/v1/scan-ticketĐọc vé máy bay (Pro): ảnh boarding pass hoặc chữ đã đọc sẵn trên máyQuyền truy cập: user
Lỗi: 403 PRO_REQUIRED · 429 AI_QUOTA (hết lượt trong tháng, details.resetsAt) · 503 AI_PAUSED · 503 SCAN_BUSY · 504 SCAN_TIMEOUT
imageBase64mimeTypetextpassengerfromCodetoCodeflightNumberdepartureTimearrivalTimeseatbookingRef.../api/v1/mapbox/searchAutocomplete địa điểm (Mapbox Geocoding, fallback OSM Nominatim)Quyền truy cập: user
querylatlnglimit[]