Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
234
native/desktop/maplefile/docs/CODE_SIGNING.md
Normal file
234
native/desktop/maplefile/docs/CODE_SIGNING.md
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
# Code Signing Guide for MapleFile Desktop
|
||||
|
||||
This document outlines the code signing requirements and procedures for MapleFile desktop application releases.
|
||||
|
||||
## Why Code Signing is Important
|
||||
|
||||
Code signing provides:
|
||||
1. **Integrity Verification**: Ensures the binary hasn't been tampered with since signing
|
||||
2. **Publisher Authentication**: Confirms the software comes from MapleFile/Maple Open Technologies
|
||||
3. **User Trust**: Operating systems trust signed applications more readily
|
||||
4. **Malware Protection**: Unsigned apps trigger security warnings that users may ignore
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
### macOS
|
||||
|
||||
**Certificate Types:**
|
||||
- **Developer ID Application**: Required for distribution outside the Mac App Store
|
||||
- **Developer ID Installer**: Required for signed `.pkg` installers
|
||||
|
||||
**Requirements:**
|
||||
1. Apple Developer Program membership ($99/year)
|
||||
2. Developer ID certificates from Apple Developer portal
|
||||
3. Notarization through Apple's notary service
|
||||
|
||||
**Signing Process:**
|
||||
```bash
|
||||
# Sign the application
|
||||
codesign --force --options runtime --sign "Developer ID Application: Your Name (TEAM_ID)" \
|
||||
--timestamp MapleFile.app
|
||||
|
||||
# Create a signed DMG
|
||||
hdiutil create -volname "MapleFile" -srcfolder MapleFile.app -ov -format UDZO MapleFile.dmg
|
||||
codesign --sign "Developer ID Application: Your Name (TEAM_ID)" MapleFile.dmg
|
||||
|
||||
# Notarize (required for macOS 10.15+)
|
||||
xcrun notarytool submit MapleFile.dmg --apple-id your@email.com --team-id TEAM_ID --wait
|
||||
xcrun stapler staple MapleFile.dmg
|
||||
```
|
||||
|
||||
**Wails Build Integration:**
|
||||
```bash
|
||||
# Wails supports code signing via environment variables
|
||||
export MACOS_SIGNING_IDENTITY="Developer ID Application: Your Name (TEAM_ID)"
|
||||
export MACOS_NOTARIZATION_TEAM_ID="TEAM_ID"
|
||||
export MACOS_NOTARIZATION_APPLE_ID="your@email.com"
|
||||
export MACOS_NOTARIZATION_PASSWORD="@keychain:AC_PASSWORD"
|
||||
|
||||
wails build -platform darwin/universal
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
**Certificate Types:**
|
||||
- **EV Code Signing Certificate**: Extended Validation - highest trust, required for SmartScreen reputation
|
||||
- **Standard Code Signing Certificate**: Basic signing, builds reputation over time
|
||||
|
||||
**Requirements:**
|
||||
1. Code signing certificate from a trusted CA (DigiCert, Sectigo, GlobalSign, etc.)
|
||||
2. Hardware token (required for EV certificates)
|
||||
3. SignTool from Windows SDK
|
||||
|
||||
**Signing Process:**
|
||||
```powershell
|
||||
# Sign with timestamp (important for validity after certificate expiry)
|
||||
signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 ^
|
||||
/a /n "Maple Open Technologies" MapleFile.exe
|
||||
|
||||
# Verify signature
|
||||
signtool verify /pa /v MapleFile.exe
|
||||
```
|
||||
|
||||
**Wails Build Integration:**
|
||||
```powershell
|
||||
# Set environment variables before build
|
||||
$env:WINDOWS_SIGNING_CERTIFICATE = "path/to/certificate.pfx"
|
||||
$env:WINDOWS_SIGNING_PASSWORD = "certificate_password"
|
||||
|
||||
wails build -platform windows/amd64
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
Linux doesn't have a universal code signing requirement, but you can:
|
||||
|
||||
1. **GPG Signing**: Sign release artifacts with GPG
|
||||
```bash
|
||||
gpg --armor --detach-sign MapleFile.tar.gz
|
||||
```
|
||||
|
||||
2. **AppImage Signing**: Sign AppImage files
|
||||
```bash
|
||||
# Import your signing key
|
||||
./appimagetool --sign MapleFile.AppImage
|
||||
```
|
||||
|
||||
3. **Package Signatures**: Use distribution-specific signing
|
||||
- `.deb`: `dpkg-sig --sign builder package.deb`
|
||||
- `.rpm`: `rpm --addsign package.rpm`
|
||||
|
||||
## Secure Update Mechanism
|
||||
|
||||
### Current State
|
||||
MapleFile currently does not include automatic updates.
|
||||
|
||||
### Recommended Implementation
|
||||
|
||||
1. **Update Server**: Host update manifests with signed checksums
|
||||
2. **Version Checking**: Application checks for updates on startup (optional)
|
||||
3. **Download Verification**: Verify signature before applying update
|
||||
4. **Rollback Support**: Keep previous version for rollback on failure
|
||||
|
||||
**Update Manifest Format:**
|
||||
```json
|
||||
{
|
||||
"version": "1.2.3",
|
||||
"release_date": "2025-01-15",
|
||||
"platforms": {
|
||||
"darwin-arm64": {
|
||||
"url": "https://releases.maplefile.com/v1.2.3/MapleFile-darwin-arm64.dmg",
|
||||
"sha256": "abc123...",
|
||||
"signature": "base64-encoded-signature"
|
||||
},
|
||||
"darwin-amd64": {
|
||||
"url": "https://releases.maplefile.com/v1.2.3/MapleFile-darwin-amd64.dmg",
|
||||
"sha256": "def456...",
|
||||
"signature": "base64-encoded-signature"
|
||||
},
|
||||
"windows-amd64": {
|
||||
"url": "https://releases.maplefile.com/v1.2.3/MapleFile-windows-amd64.exe",
|
||||
"sha256": "ghi789...",
|
||||
"signature": "base64-encoded-signature"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Verification Process:**
|
||||
```go
|
||||
// Pseudocode for update verification
|
||||
func verifyUpdate(downloadPath, expectedSHA256, signature string) error {
|
||||
// 1. Verify SHA256 hash
|
||||
actualHash := sha256sum(downloadPath)
|
||||
if actualHash != expectedSHA256 {
|
||||
return errors.New("hash mismatch")
|
||||
}
|
||||
|
||||
// 2. Verify signature (using embedded public key)
|
||||
if !verifySignature(downloadPath, signature, publicKey) {
|
||||
return errors.New("signature verification failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
## Certificate Management
|
||||
|
||||
### Storage
|
||||
- **Never** commit private keys to version control
|
||||
- Store certificates in secure vault (e.g., HashiCorp Vault, AWS Secrets Manager)
|
||||
- Use CI/CD secrets for automated builds
|
||||
|
||||
### Rotation
|
||||
- Set calendar reminders for certificate expiry (typically 1-3 years)
|
||||
- Plan for certificate rotation before expiry
|
||||
- Test signing process after certificate renewal
|
||||
|
||||
### Revocation
|
||||
- Maintain list of compromised certificates
|
||||
- Have incident response plan for key compromise
|
||||
- Document process for certificate revocation
|
||||
|
||||
## Build Pipeline Integration
|
||||
|
||||
### GitHub Actions Example
|
||||
```yaml
|
||||
name: Release Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Import Code Signing Certificate
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
echo $CERTIFICATE_BASE64 | base64 --decode > certificate.p12
|
||||
security create-keychain -p "" build.keychain
|
||||
security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" build.keychain
|
||||
|
||||
- name: Build and Sign
|
||||
env:
|
||||
MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
|
||||
run: |
|
||||
wails build -platform darwin/universal
|
||||
# Notarize here...
|
||||
```
|
||||
|
||||
## Verification Commands
|
||||
|
||||
### macOS
|
||||
```bash
|
||||
# Check signature
|
||||
codesign -dvv MapleFile.app
|
||||
|
||||
# Verify notarization
|
||||
spctl -a -vv MapleFile.app
|
||||
```
|
||||
|
||||
### Windows
|
||||
```powershell
|
||||
# Check signature
|
||||
signtool verify /pa /v MapleFile.exe
|
||||
|
||||
# PowerShell alternative
|
||||
Get-AuthenticodeSignature MapleFile.exe
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Apple Developer Code Signing](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution)
|
||||
- [Microsoft Authenticode](https://docs.microsoft.com/en-us/windows/win32/seccrypto/cryptography-tools)
|
||||
- [Wails Build Documentation](https://wails.io/docs/guides/signing)
|
||||
- [OWASP Code Signing Guidelines](https://cheatsheetseries.owasp.org/cheatsheets/Code_Signing_Cheat_Sheet.html)
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
# Collection Icon Customization Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Add the ability to customize collection (folder) icons with emojis or predefined icons. This feature enhances the user experience by allowing visual differentiation between collections.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. **Customization Options**:
|
||||
- Custom emoji (e.g., 📁, 🎵, 📷, 💼, 🏠)
|
||||
- Predefined cross-browser icons from a curated set
|
||||
- Default folder icon when no customization is set
|
||||
|
||||
2. **Behavior**:
|
||||
- Default to standard folder icon if no customization
|
||||
- Persist across browser sessions (stored in database)
|
||||
- Easy to change or revert to default
|
||||
- Intuitive, user-friendly UI
|
||||
|
||||
3. **Security Consideration**:
|
||||
- Icon data should be encrypted (E2EE) like collection name
|
||||
- Only emoji characters or predefined icon identifiers allowed
|
||||
|
||||
---
|
||||
|
||||
## Data Model Design
|
||||
|
||||
### New Field: `custom_icon`
|
||||
|
||||
Add a new encrypted field to the Collection model that stores icon customization data.
|
||||
|
||||
```go
|
||||
// CustomIcon stores the collection's custom icon configuration
|
||||
type CustomIcon struct {
|
||||
Type string `json:"type"` // "emoji", "icon", or "" (empty = default)
|
||||
Value string `json:"value"` // Emoji character or icon identifier
|
||||
}
|
||||
```
|
||||
|
||||
**Field Storage Options**:
|
||||
|
||||
| Option | Pros | Cons |
|
||||
|--------|------|------|
|
||||
| A) Single encrypted JSON field | Simple, one field | Requires parsing |
|
||||
| B) Two fields (type + value) | Clear structure | More columns |
|
||||
| C) Single string field | Simplest | Limited validation |
|
||||
|
||||
**Recommended: Option C** - Single `encrypted_custom_icon` field storing either:
|
||||
- Empty string `""` → Default folder icon
|
||||
- Emoji character (e.g., `"📷"`) → Display as emoji
|
||||
- Icon identifier (e.g., `"icon:briefcase"`) → Predefined icon
|
||||
|
||||
This keeps the schema simple and the client handles interpretation.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Backend (cloud/maplefile-backend)
|
||||
|
||||
#### 1.1 Database Schema Update
|
||||
|
||||
**Note:** No new migration files needed - updating existing migration `012_create_collections_by_id.up.cql` directly (assumes full database wipe).
|
||||
|
||||
Add to `collections_by_id` table:
|
||||
```sql
|
||||
encrypted_custom_icon TEXT,
|
||||
```
|
||||
|
||||
#### 1.2 Update Domain Model
|
||||
|
||||
File: `internal/domain/collection/model.go`
|
||||
|
||||
```go
|
||||
type Collection struct {
|
||||
// ... existing fields ...
|
||||
|
||||
// EncryptedCustomIcon stores the custom icon for this collection.
|
||||
// Empty string means use default folder icon.
|
||||
// Contains either an emoji character or "icon:<identifier>" for predefined icons.
|
||||
// Encrypted with the collection key for E2EE.
|
||||
EncryptedCustomIcon string `bson:"encrypted_custom_icon" json:"encrypted_custom_icon"`
|
||||
}
|
||||
```
|
||||
|
||||
Also add to `CollectionSyncItem` for sync operations:
|
||||
```go
|
||||
type CollectionSyncItem struct {
|
||||
// ... existing fields ...
|
||||
EncryptedCustomIcon string `json:"encrypted_custom_icon,omitempty" bson:"encrypted_custom_icon,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** The sync query in `collectionsync.go:getCollectionSyncItem()` fetches minimal data from `collections_by_id`. This query will need to include `encrypted_custom_icon` so clients can display the correct icon during sync.
|
||||
|
||||
#### 1.3 Update Repository Layer
|
||||
|
||||
Files to modify:
|
||||
- `internal/repo/collection/create.go` - Include new field in INSERT
|
||||
- `internal/repo/collection/update.go` - Include new field in UPDATE
|
||||
- `internal/repo/collection/get.go` - Include new field in SELECT
|
||||
- `internal/repo/collection/sync.go` - Include new field in sync queries
|
||||
|
||||
#### 1.4 Update HTTP Handlers (if needed)
|
||||
|
||||
The existing create/update endpoints should automatically handle the new field since they accept the full Collection struct.
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Frontend (web/maplefile-frontend)
|
||||
|
||||
#### 2.1 Create Icon Picker Component
|
||||
|
||||
New file: `src/components/IconPicker/IconPicker.jsx`
|
||||
|
||||
Features:
|
||||
- Emoji picker tab with common categories (objects, activities, symbols)
|
||||
- Predefined icons tab (Heroicons subset)
|
||||
- "Default" option to revert to folder icon
|
||||
- Search/filter functionality
|
||||
- Recently used icons
|
||||
|
||||
```jsx
|
||||
// Example structure
|
||||
const IconPicker = ({ value, onChange, onClose }) => {
|
||||
const [activeTab, setActiveTab] = useState('emoji'); // 'emoji' | 'icons'
|
||||
|
||||
const predefinedIcons = [
|
||||
{ id: 'briefcase', icon: BriefcaseIcon, label: 'Work' },
|
||||
{ id: 'photo', icon: PhotoIcon, label: 'Photos' },
|
||||
{ id: 'music', icon: MusicalNoteIcon, label: 'Music' },
|
||||
{ id: 'document', icon: DocumentIcon, label: 'Documents' },
|
||||
{ id: 'archive', icon: ArchiveBoxIcon, label: 'Archive' },
|
||||
// ... more icons
|
||||
];
|
||||
|
||||
const popularEmojis = ['📁', '📷', '🎵', '💼', '🏠', '❤️', '⭐', '🎮', '📚', '🎨'];
|
||||
|
||||
return (
|
||||
// ... picker UI
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
#### 2.2 Update CollectionEdit Page
|
||||
|
||||
File: `src/pages/User/FileManager/Collections/CollectionEdit.jsx`
|
||||
|
||||
Add icon customization section:
|
||||
|
||||
```jsx
|
||||
{/* Icon Customization Section */}
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
|
||||
<SparklesIcon className="h-5 w-5 mr-2 text-gray-500" />
|
||||
Customize Icon
|
||||
</h2>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Current Icon Preview */}
|
||||
<div className="flex items-center justify-center h-16 w-16 bg-gray-100 rounded-xl border-2 border-dashed border-gray-300">
|
||||
<CollectionIcon icon={formData.customIcon} size="lg" />
|
||||
</div>
|
||||
|
||||
{/* Change/Reset Buttons */}
|
||||
<div className="space-y-2">
|
||||
<button onClick={() => setShowIconPicker(true)} className="...">
|
||||
Change Icon
|
||||
</button>
|
||||
{formData.customIcon && (
|
||||
<button onClick={() => setFormData({...formData, customIcon: ''})} className="...">
|
||||
Reset to Default
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 2.3 Create CollectionIcon Component
|
||||
|
||||
New file: `src/components/CollectionIcon/CollectionIcon.jsx`
|
||||
|
||||
Renders the appropriate icon based on the customIcon value:
|
||||
|
||||
```jsx
|
||||
const CollectionIcon = ({ icon, collectionType = 'folder', size = 'md', className = '' }) => {
|
||||
const sizes = {
|
||||
sm: 'h-4 w-4',
|
||||
md: 'h-6 w-6',
|
||||
lg: 'h-10 w-10',
|
||||
};
|
||||
|
||||
// Default folder/album icon
|
||||
if (!icon || icon === '') {
|
||||
const Icon = collectionType === 'album' ? PhotoIcon : FolderIcon;
|
||||
return <Icon className={`${sizes[size]} ${className}`} />;
|
||||
}
|
||||
|
||||
// Predefined icon
|
||||
if (icon.startsWith('icon:')) {
|
||||
const iconId = icon.replace('icon:', '');
|
||||
const IconComponent = predefinedIconMap[iconId];
|
||||
return IconComponent ? <IconComponent className={`${sizes[size]} ${className}`} /> : <FolderIcon className={`${sizes[size]} ${className}`} />;
|
||||
}
|
||||
|
||||
// Emoji
|
||||
return <span className={`${emojiSizes[size]} ${className}`}>{icon}</span>;
|
||||
};
|
||||
```
|
||||
|
||||
#### 2.4 Update Collection List/Grid Views
|
||||
|
||||
Update anywhere collections are displayed to use the new `CollectionIcon` component:
|
||||
- `FileManagerIndex.jsx`
|
||||
- `CollectionDetails.jsx`
|
||||
- Sidebar navigation (if applicable)
|
||||
|
||||
#### 2.5 Update Encryption/Decryption
|
||||
|
||||
Update the collection encryption service to handle the new field:
|
||||
- Encrypt `customIcon` when saving
|
||||
- Decrypt `encrypted_custom_icon` when loading
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Native Desktop (native/desktop/maplefile)
|
||||
|
||||
#### 3.1 Update Domain Model
|
||||
|
||||
File: `internal/domain/collection/model.go`
|
||||
|
||||
```go
|
||||
type Collection struct {
|
||||
// ... existing fields ...
|
||||
|
||||
// CustomIcon stores the decrypted custom icon for this collection.
|
||||
// Empty string means use default folder icon.
|
||||
// Contains either an emoji character or "icon:<identifier>" for predefined icons.
|
||||
CustomIcon string `json:"custom_icon,omitempty"`
|
||||
|
||||
// EncryptedCustomIcon is the encrypted version from cloud
|
||||
EncryptedCustomIcon string `json:"encrypted_custom_icon,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 Update Sync Service
|
||||
|
||||
Ensure the sync service handles the new field when syncing collections from the cloud.
|
||||
|
||||
#### 3.3 Update Frontend (Wails)
|
||||
|
||||
The desktop frontend uses the same React patterns, so the IconPicker and CollectionIcon components can be shared or adapted.
|
||||
|
||||
---
|
||||
|
||||
## Predefined Icon Set
|
||||
|
||||
A curated set of cross-browser compatible icons:
|
||||
|
||||
| ID | Icon | Use Case |
|
||||
|----|------|----------|
|
||||
| `briefcase` | BriefcaseIcon | Work |
|
||||
| `photo` | PhotoIcon | Photos |
|
||||
| `music` | MusicalNoteIcon | Music |
|
||||
| `video` | VideoCameraIcon | Videos |
|
||||
| `document` | DocumentTextIcon | Documents |
|
||||
| `archive` | ArchiveBoxIcon | Archive |
|
||||
| `star` | StarIcon | Favorites |
|
||||
| `heart` | HeartIcon | Personal |
|
||||
| `home` | HomeIcon | Home |
|
||||
| `academic` | AcademicCapIcon | School |
|
||||
| `code` | CodeBracketIcon | Code |
|
||||
| `cloud` | CloudIcon | Cloud |
|
||||
| `lock` | LockClosedIcon | Private |
|
||||
| `gift` | GiftIcon | Gifts |
|
||||
| `calendar` | CalendarIcon | Events |
|
||||
|
||||
---
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
1. **Backward Compatible**: Empty `encrypted_custom_icon` means default icon
|
||||
2. **No Data Migration Needed**: New collections get the field, old collections have NULL/empty
|
||||
3. **Clients Handle Missing Field**: Treat NULL/empty as default
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
### Backend
|
||||
- [ ] Migration runs successfully
|
||||
- [ ] Create collection with custom icon
|
||||
- [ ] Update collection custom icon
|
||||
- [ ] Revert to default icon
|
||||
- [ ] Sync includes custom icon field
|
||||
- [ ] E2EE encryption/decryption works
|
||||
|
||||
### Frontend (Web)
|
||||
- [ ] Icon picker opens and closes
|
||||
- [ ] Emoji selection works
|
||||
- [ ] Predefined icon selection works
|
||||
- [ ] Reset to default works
|
||||
- [ ] Icon persists after page reload
|
||||
- [ ] Icon displays correctly in list/grid views
|
||||
- [ ] Works across different browsers
|
||||
|
||||
### Native Desktop
|
||||
- [ ] Sync downloads custom icon
|
||||
- [ ] Icon displays correctly
|
||||
- [ ] Edit icon works (if implemented)
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **E2EE**: Custom icon is encrypted with collection key
|
||||
2. **Input Validation**: Only allow valid emoji or predefined icon IDs
|
||||
3. **XSS Prevention**: Sanitize icon display (emoji rendering, no HTML)
|
||||
4. **Size Limits**: Max length for custom icon field (e.g., 50 chars)
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Custom uploaded icons** (requires more complex storage)
|
||||
2. **Icon color customization**
|
||||
3. **Icon packs/themes**
|
||||
4. **Bulk icon changes** (apply to multiple collections)
|
||||
|
||||
---
|
||||
|
||||
## Files to Modify
|
||||
|
||||
### Backend (cloud/maplefile-backend)
|
||||
|
||||
**Schema Update (modify existing migration):**
|
||||
1. `migrations/012_create_collections_by_id.up.cql` - Add `encrypted_custom_icon TEXT` column
|
||||
|
||||
**Domain Layer:**
|
||||
2. `internal/domain/collection/model.go` - Add `EncryptedCustomIcon` field to `Collection` and `CollectionSyncItem` structs
|
||||
|
||||
**Repository Layer:**
|
||||
4. `internal/repo/collection/create.go` - Add `encrypted_custom_icon` to INSERT query (line ~57-66)
|
||||
5. `internal/repo/collection/update.go` - Add `encrypted_custom_icon` to UPDATE query (line ~64-73)
|
||||
6. `internal/repo/collection/get.go` - Add `encrypted_custom_icon` to SELECT query and scan (line ~44-52, ~72-90)
|
||||
7. `internal/repo/collection/collectionsync.go` - Add field to sync queries
|
||||
|
||||
**Note:** Secondary tables (013-017) do NOT need modification - they are lookup/index tables that only store keys and minimal fields. The `encrypted_custom_icon` is stored only in `collections_by_id`.
|
||||
|
||||
### Frontend (web/maplefile-frontend)
|
||||
|
||||
**New Components:**
|
||||
1. `src/components/IconPicker/IconPicker.jsx` - Modal with emoji grid + predefined icons
|
||||
2. `src/components/CollectionIcon/CollectionIcon.jsx` - Renders appropriate icon based on value
|
||||
|
||||
**Modified Pages:**
|
||||
3. `src/pages/User/FileManager/Collections/CollectionEdit.jsx` - Add icon customization section
|
||||
4. `src/pages/User/FileManager/Collections/CollectionDetails.jsx` - Display custom icon
|
||||
5. `src/pages/User/FileManager/Collections/CollectionCreate.jsx` - Optional icon selection on create
|
||||
6. `src/pages/User/FileManager/FileManagerIndex.jsx` - Display custom icons in list/grid
|
||||
|
||||
**Services:**
|
||||
7. Collection encryption service - Handle `customIcon` field encryption/decryption
|
||||
|
||||
### Native Desktop (native/desktop/maplefile)
|
||||
|
||||
**Domain:**
|
||||
1. `internal/domain/collection/model.go` - Add `CustomIcon` and `EncryptedCustomIcon` fields
|
||||
|
||||
**Repository:**
|
||||
2. `internal/repo/collection/repository.go` - Handle new field in CRUD operations
|
||||
|
||||
**Sync:**
|
||||
3. `internal/service/sync/collection.go` - Include field in sync operations
|
||||
|
||||
**Frontend:**
|
||||
4. `frontend/src/` - Adapt IconPicker and CollectionIcon components (if not shared with web)
|
||||
|
||||
---
|
||||
|
||||
## Estimated Effort
|
||||
|
||||
| Phase | Effort |
|
||||
|-------|--------|
|
||||
| Backend (migration + model) | 2-3 hours |
|
||||
| Frontend components | 4-6 hours |
|
||||
| Frontend integration | 2-3 hours |
|
||||
| Native desktop | 2-3 hours |
|
||||
| Testing | 2-3 hours |
|
||||
| **Total** | **12-18 hours** |
|
||||
Loading…
Add table
Add a link
Reference in a new issue