🎯 Goal
Implement API GET /dashboard/filters để trả về cấu hình dropdown filter dùng chung cho các dashboard screen.
API này phục vụ khung FILTERS Bar xuất hiện ở phần trên của các màn hình analytics, bao gồm:
Mục tiêu là giúp FE render filter dropdown một cách dynamic, không hard-code trực tiếp trong UI.
🖼️ UI Mapping
UI Block
Filter Items
Ví dụ UI:
[Last 5 Years ▼] [Computer Science ▼] [Global Distribution ▼]
📡 Endpoint
📥 Query Parameters
Phase 1 không bắt buộc query params.
Optional future params:
| Param |
Type |
Required |
Description |
project_id |
string / number |
No |
Nếu muốn trả filter theo project scope |
screen |
string |
No |
Nếu muốn trả filter theo từng màn hình dashboard |
include_counts |
boolean |
No |
Nếu muốn trả số lượng item tương ứng với mỗi option |
✅ Example Request
🧾 Response Contract
{
"code": 200,
"message": "Fetch filter configurations successfully",
"data": {
"timeframes": [
"Last 5 Years",
"Last 10 Years",
"All Time"
],
"domains": [
"Biological Sciences",
"Computer Science",
"Physical Sciences"
],
"regions": [
"Global Distribution",
"North America",
"Asia Pacific"
]
}
}
📌 Response Field Explanation
| Field |
Type |
Description |
timeframes |
string[] |
Danh sách khoảng thời gian cho dashboard |
domains |
string[] |
Danh sách lĩnh vực / subject area |
regions |
string[] |
Danh sách vùng địa lý / region filter |
🧠 Business Logic
1. Timeframe options
Phase 1 trả các option cố định:
Last 5 Years
Last 10 Years
All Time
Mapping gợi ý cho FE / BE khi gọi các API analytics khác:
| UI Label |
Meaning |
Last 5 Years |
from_year = currentYear - 4, to_year = currentYear |
Last 10 Years |
from_year = currentYear - 9, to_year = currentYear |
All Time |
Không truyền from_year, to_year hoặc lấy toàn bộ data |
Ví dụ nếu năm hiện tại là 2026:
Last 5 Years -> 2022-2026
Last 10 Years -> 2017-2026
2. Domain options
domains nên lấy dynamic từ bảng Subject Area.
Suggested source:
Subject_Area.display_name
Suggested filters:
Sort:
Nếu chưa có dữ liệu dynamic hoặc phase 1 cần mock:
Biological Sciences
Computer Science
Physical Sciences
3. Region options
regions dùng để lọc dữ liệu địa lý trên các analytics screen.
Phase 1 có thể trả static options:
Global Distribution
North America
Asia Pacific
Europe
Middle East & Africa
Latin America
Nếu hệ thống đã có country / affiliation data, có thể build dynamic từ country group.
Suggested source:
Institution.country
Author_Affiliation.country
Article_Affiliation.country
Sau đó map country sang region.
4. Default selected values
FE có thể dùng item đầu tiên làm default:
timeframes[0] = Last 5 Years
domains[0] = Biological Sciences hoặc All Domains nếu có
regions[0] = Global Distribution
Suggested improvement:
Add "All Domains" vào domains nếu UI cần filter toàn bộ domain.
Tuy nhiên contract hiện tại chưa có All Domains, nên phase 1 giữ đúng danh sách theo mock.
5. Data normalization
API cần đảm bảo:
- Không trả duplicate option
- Không trả string rỗng
- Không trả null
- Sort options ổn định
- Response shape luôn cố định
🔄 Filter Mapping To Analytics APIs
Các filter này sẽ được FE dùng để gọi các API analytics khác.
Timeframe mapping
Last 5 Years -> from_year / to_year
Last 10 Years -> from_year / to_year
All Time -> omit from_year / to_year
Domain mapping
Ví dụ:
GET /analytics/journals/ranking?project_id=1&subject_area=Computer Science
Region mapping
Region -> region / country_group
Ví dụ future API:
GET /analytics/geo-distribution?project_id=1®ion=Asia Pacific
📦 Data Source
Phase 1
Có thể dùng hybrid approach:
timeframes: static
domains: dynamic from Subject_Area
regions: static
Suggested tables
Subject_Area
Institution
Author_Affiliation
Article_Affiliation
Country
Region
Relevant schema flow nếu có region/country:
Institution.country_code -> Country.country_code
Country.region_id -> Region.region_id
⚠️ Edge Cases
1. No subject areas found
Nếu không có domain trong database:
{
"code": 200,
"message": "Fetch filter configurations successfully",
"data": {
"timeframes": [
"Last 5 Years",
"Last 10 Years",
"All Time"
],
"domains": [],
"regions": [
"Global Distribution",
"North America",
"Asia Pacific"
]
}
}
2. Database query failure for domains
Nếu query domain lỗi, API có thể:
Option A: Return error
{
"code": 500,
"message": "Failed to fetch filter configurations",
"data": null
}
Option B: Fallback static domains
{
"code": 200,
"message": "Fetch filter configurations successfully",
"data": {
"timeframes": [
"Last 5 Years",
"Last 10 Years",
"All Time"
],
"domains": [
"Biological Sciences",
"Computer Science",
"Physical Sciences"
],
"regions": [
"Global Distribution",
"North America",
"Asia Pacific"
]
}
}
Suggested phase 1:
Use fallback static domains if dynamic source unavailable.
3. Duplicate domains
Nếu database có duplicate display name:
Return unique domain names only
4. Deleted subject areas
Nếu Subject_Area.is_deleted = true:
Do not include in domains
5. Empty strings or null values
Nếu option bị null hoặc empty string:
🧪 Acceptance Criteria
🧪 Test Cases
TC-01: Fetch filters successfully
Request
Expected
{
"code": 200,
"message": "Fetch filter configurations successfully",
"data": {
"timeframes": [
"Last 5 Years",
"Last 10 Years",
"All Time"
],
"domains": [
"Biological Sciences",
"Computer Science",
"Physical Sciences"
],
"regions": [
"Global Distribution",
"North America",
"Asia Pacific"
]
}
}
TC-02: Domains are loaded from Subject_Area
Input
Database has:
Computer Science
Biological Sciences
Physical Sciences
Expected
Response contains:
{
"domains": [
"Biological Sciences",
"Computer Science",
"Physical Sciences"
]
}
Sorted alphabetically.
TC-03: Ignore deleted subject areas
Input
Computer Science, is_deleted = false
Outdated Domain, is_deleted = true
Expected
Computer Science is returned
Outdated Domain is not returned
TC-04: No domains found
Input
No active Subject_Area rows.
Expected
{
"code": 200,
"message": "Fetch filter configurations successfully",
"data": {
"timeframes": [
"Last 5 Years",
"Last 10 Years",
"All Time"
],
"domains": [],
"regions": [
"Global Distribution",
"North America",
"Asia Pacific"
]
}
}
TC-05: Duplicate domain names
Input
Database has duplicate:
Computer Science
Computer Science
Expected
Response only includes one:
{
"domains": [
"Computer Science"
]
}
TC-06: FE can render dropdowns directly
Steps
- Call
GET /dashboard/filters
- Pass
timeframes to Timeframe dropdown
- Pass
domains to Domain dropdown
- Pass
regions to Region dropdown
Expected
- Dropdowns render without additional transformation
- No null option appears
- No duplicate option appears
📌 Implementation Notes
Nên tách logic thành các phần riêng:
Controller
-> call service
Service
-> get timeframe options
-> get domain options
-> get region options
-> normalize options
-> build response contract
Gợi ý function:
getDashboardFilters()
getTimeframeOptions()
getDomainOptions()
getRegionOptions()
normalizeFilterOptions(options)
buildDashboardFiltersResponse(timeframes, domains, regions)
📦 Suggested Mock Data
const mockDashboardFilters = {
timeframes: [
"Last 5 Years",
"Last 10 Years",
"All Time"
],
domains: [
"Biological Sciences",
"Computer Science",
"Physical Sciences"
],
regions: [
"Global Distribution",
"North America",
"Asia Pacific"
]
};
🚀 Future Improvements
- Return
label and value instead of raw strings:
{
"timeframes": [
{
"label": "Last 5 Years",
"value": "last_5_years",
"fromYear": 2022,
"toYear": 2026
}
]
}
- Add counts per filter option:
{
"label": "Computer Science",
"value": "computer_science",
"count": 1200
}
{
"defaultValues": {
"timeframe": "Last 5 Years",
"domain": "Computer Science",
"region": "Global Distribution"
}
}
- Add project-aware filters:
GET /dashboard/filters?project_id=1
- Add screen-specific filters:
GET /dashboard/filters?screen=journals
dashboard:filters:v1
dashboard:filters:{project_id}:{screen}
- Optimize query with indexes on:
subject_area_id
display_name
is_deleted
🎯 Goal
Implement API
GET /dashboard/filtersđể trả về cấu hình dropdown filter dùng chung cho các dashboard screen.API này phục vụ khung FILTERS Bar xuất hiện ở phần trên của các màn hình analytics, bao gồm:
TimeframeDomainRegionMục tiêu là giúp FE render filter dropdown một cách dynamic, không hard-code trực tiếp trong UI.
🖼️ UI Mapping
UI Block
Filter Items
Ví dụ UI:
📡 Endpoint
📥 Query Parameters
Phase 1 không bắt buộc query params.
Optional future params:
project_idscreeninclude_counts✅ Example Request
🧾 Response Contract
{ "code": 200, "message": "Fetch filter configurations successfully", "data": { "timeframes": [ "Last 5 Years", "Last 10 Years", "All Time" ], "domains": [ "Biological Sciences", "Computer Science", "Physical Sciences" ], "regions": [ "Global Distribution", "North America", "Asia Pacific" ] } }📌 Response Field Explanation
timeframesdomainsregions🧠 Business Logic
1. Timeframe options
Phase 1 trả các option cố định:
Mapping gợi ý cho FE / BE khi gọi các API analytics khác:
Last 5 Yearsfrom_year = currentYear - 4,to_year = currentYearLast 10 Yearsfrom_year = currentYear - 9,to_year = currentYearAll Timefrom_year,to_yearhoặc lấy toàn bộ dataVí dụ nếu năm hiện tại là
2026:2. Domain options
domainsnên lấy dynamic từ bảng Subject Area.Suggested source:
Suggested filters:
Sort:
Nếu chưa có dữ liệu dynamic hoặc phase 1 cần mock:
3. Region options
regionsdùng để lọc dữ liệu địa lý trên các analytics screen.Phase 1 có thể trả static options:
Nếu hệ thống đã có country / affiliation data, có thể build dynamic từ country group.
Suggested source:
Sau đó map country sang region.
4. Default selected values
FE có thể dùng item đầu tiên làm default:
Suggested improvement:
Tuy nhiên contract hiện tại chưa có
All Domains, nên phase 1 giữ đúng danh sách theo mock.5. Data normalization
API cần đảm bảo:
🔄 Filter Mapping To Analytics APIs
Các filter này sẽ được FE dùng để gọi các API analytics khác.
Timeframe mapping
Domain mapping
Ví dụ:
Region mapping
Ví dụ future API:
📦 Data Source
Phase 1
Có thể dùng hybrid approach:
Suggested tables
Relevant schema flow nếu có region/country:
1. No subject areas found
Nếu không có domain trong database:
{ "code": 200, "message": "Fetch filter configurations successfully", "data": { "timeframes": [ "Last 5 Years", "Last 10 Years", "All Time" ], "domains": [], "regions": [ "Global Distribution", "North America", "Asia Pacific" ] } }2. Database query failure for domains
Nếu query domain lỗi, API có thể:
Option A: Return error
{ "code": 500, "message": "Failed to fetch filter configurations", "data": null }Option B: Fallback static domains
{ "code": 200, "message": "Fetch filter configurations successfully", "data": { "timeframes": [ "Last 5 Years", "Last 10 Years", "All Time" ], "domains": [ "Biological Sciences", "Computer Science", "Physical Sciences" ], "regions": [ "Global Distribution", "North America", "Asia Pacific" ] } }Suggested phase 1:
3. Duplicate domains
Nếu database có duplicate display name:
4. Deleted subject areas
Nếu
Subject_Area.is_deleted = true:5. Empty strings or null values
Nếu option bị null hoặc empty string:
🧪 Acceptance Criteria
GET /dashboard/filtershoạt độngcode,message,datadata.timeframesluôn là arraydata.domainsluôn là arraydata.regionsluôn là arraytimeframescóLast 5 YearstimeframescóLast 10 YearstimeframescóAll Timedomainslấy từSubject_Area.display_namenếu có dữ liệudomainskhông chứa null hoặc empty stringdomainskhông duplicateregionscóGlobal DistributionregionscóNorth AmericaregionscóAsia Pacific100ms🧪 Test Cases
TC-01: Fetch filters successfully
Request
Expected
{ "code": 200, "message": "Fetch filter configurations successfully", "data": { "timeframes": [ "Last 5 Years", "Last 10 Years", "All Time" ], "domains": [ "Biological Sciences", "Computer Science", "Physical Sciences" ], "regions": [ "Global Distribution", "North America", "Asia Pacific" ] } }TC-02: Domains are loaded from Subject_Area
Input
Database has:
Expected
Response contains:
{ "domains": [ "Biological Sciences", "Computer Science", "Physical Sciences" ] }Sorted alphabetically.
TC-03: Ignore deleted subject areas
Input
Expected
TC-04: No domains found
Input
No active Subject_Area rows.
Expected
{ "code": 200, "message": "Fetch filter configurations successfully", "data": { "timeframes": [ "Last 5 Years", "Last 10 Years", "All Time" ], "domains": [], "regions": [ "Global Distribution", "North America", "Asia Pacific" ] } }TC-05: Duplicate domain names
Input
Database has duplicate:
Expected
Response only includes one:
{ "domains": [ "Computer Science" ] }TC-06: FE can render dropdowns directly
Steps
GET /dashboard/filterstimeframesto Timeframe dropdowndomainsto Domain dropdownregionsto Region dropdownExpected
📌 Implementation Notes
Nên tách logic thành các phần riêng:
Gợi ý function:
📦 Suggested Mock Data
🚀 Future Improvements
labelandvalueinstead of raw strings:{ "timeframes": [ { "label": "Last 5 Years", "value": "last_5_years", "fromYear": 2022, "toYear": 2026 } ] }{ "label": "Computer Science", "value": "computer_science", "count": 1200 }defaultValues:{ "defaultValues": { "timeframe": "Last 5 Years", "domain": "Computer Science", "region": "Global Distribution" } }dashboard:filters:v1 dashboard:filters:{project_id}:{screen}subject_area_iddisplay_nameis_deleted