Add comprehensive design document for project aliases and APK environment classification feature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.8 KiB
5.8 KiB
Design: Enhanced Download UI Readability
Date: 2026-03-04 Status: Approved
Overview
Enhance the download UI to improve readability by:
- Displaying project aliases instead of directory names
- Classifying APKs by environment (dev, sandbox, product, other)
- Displaying APKs in a list format with commit ID, file size, and creation time
- Organizing APKs into tabs by environment
Requirements
Project Aliases
- Store project display name mappings in
lib/project-aliases.json - Example:
FT→外放构建,FT_DEV→开发构建 - Fallback: Display directory name if no alias exists
APK Classification
- Categories:
dev,sandbox,product,other - APK filename format:
ft_[environment]_[version]_[commit_id].apk - Environment suffix is optional; if missing, default to
product - Unmatched formats go to
othertab
Display Format
- List view with columns: Commit ID, File Size, Creation Time, Download
- Always display all 4 tabs (dev, product, sandbox, other)
- Commit filter applies globally to all tabs
Architecture
New Files
lib/project-aliases.json- Project name alias configurationlib/apk-parser.ts- APK filename parsing utilities
Modified Files
lib/utils.ts- Add alias lookup utilityapp/api/projects/route.ts- Return projects with aliasesapp/api/apks/route.ts- Add environment metadata to responseapp/download/SearchForm.tsx- Use project aliases in dropdownapp/download/ApkList.tsx- Replace card grid with tabbed list view
Data Flow
-
Project Selection:
- Client loads projects → API reads
project-aliases.json→ returns with display names SearchFormdisplaysdisplayName, submitsnameto API
- Client loads projects → API reads
-
APK Fetching:
- User selects project/version → client fetches APKs
- API uses
parseApkFilename()to extract environment - Returns enriched APKs with
environmentfield
-
Display:
- Client receives APKs with
environmentfield - Organizes into tabs (dev, product, sandbox, other)
- Displays in list format
- Client receives APKs with
Data Structures
APK Parser Types
export type ApkEnvironment = 'dev' | 'sandbox' | 'product' | 'other';
export interface ParsedApkMetadata {
environment: ApkEnvironment;
commit: string | null;
isValid: boolean;
}
Project Alias Config
{
"FT": "外放构建",
"FT_DEV": "开发构建"
}
Enriched APK Response
{
name: string;
environment: ApkEnvironment;
commit: string | null;
size: number;
modifiedAt: string; // ISO string
downloadUrl: string;
}
Components
ApkList (Restructured)
- Replaces grid of
ApkCardwith tabbed list view - Manages tab state (active tab, filtered APKs)
- Handles commit filter globally
- Delegates list display to
ApkTablecomponent
ApkTable (New)
- Table with columns: Commit ID, File Size, Creation Time, Download
- Styled with hover effects
- Empty state handling per tab
SearchForm (Updated)
- Uses
getProjectDisplayName()for project dropdown - Maintains existing functionality
Error Handling
Project Alias Edge Cases
- Missing alias file: Fallback to directory names
- Project not in aliases: Display directory name
- Malformed JSON: Log error, fallback to directory names
APK Filename Parsing Edge Cases
- No environment in filename: Default to
product - No commit ID:
commitfield isnull - Unmatched format:
environment: "other", still display - Invalid characters: Handle gracefully
UI Edge Cases
- Empty tab: Display "暂无 APK 文件"
- All tabs empty: Show helpful message
- Loading state: Skeleton or spinner
- API error: Display error message, allow retry
APK Filename Parsing Logic
Regex Pattern
const APK_PATTERN = /^ft_([a-z]+)?_([0-9_]+)_([a-f0-9]{7,})\.apk$/;
// ^^^ ^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^
// ft env(opt) version commit id
Parsing Rules
- Try to match standard pattern:
ft_[env]_[version]_[commit].apk - Extract environment if present, otherwise default to
product - If pattern doesn't match, assign
environment: "other" - Extract commit ID from filename
- Use file system metadata for size and modified time
Testing Strategy
Unit Tests
lib/__tests__/apk-parser.test.ts: Test filename parsing for all environmentslib/__tests__/project-aliases.test.ts: Test alias lookup logic
Integration Tests
- API tests for
/api/projectswith alias data - API tests for
/api/apksreturning enriched metadata
Component Tests
ApkTable: Renders correct columns, handles empty statesApkList: Tabs work correctly, filters apply globallySearchForm: Displays project aliases correctly
Manual Testing Checklist
- Projects display with aliases (FT → 外放构建)
- Projects without aliases show directory names
- APKs grouped correctly in 4 tabs
- Product APKs (no env suffix) go to "product" tab
- Dev/sandbox APKs go to correct tabs
- Invalid format APKs go to "other" tab
- Commit filter applies to all tabs
- List shows Commit ID, File Size, Creation Time
- Download button works correctly
Implementation Approach
Selected: Approach 2 - Shared Utility Functions + Client-side Organization
Why:
- Clean separation of concerns
- Reusable parsing utilities
- Type-safe with TypeScript
- Easier to unit test parsing logic
- Client receives all APKs once, then handles tab organization
- Performance overhead is minimal for this use case
Success Criteria
- Project aliases display correctly in dropdown
- APKs are correctly classified by environment
- All 4 tabs display correctly (dev, product, sandbox, other)
- List view shows correct columns (Commit ID, File Size, Creation Time)
- Commit filter works globally across all tabs
- Edge cases handled gracefully (missing aliases, invalid formats)
- All tests pass