# Daily Timer - AI Assistant Instructions ## Project Overview - **Purpose**: Desktop meeting timer application with speaker management - **Framework**: Wails v2.11.0 (Go backend + Svelte frontend) - **Status**: Active development ## Technology Stack | Component | Technology | | ------------- | --------------------------- | | **Backend** | Go 1.21+ | | **Framework** | Wails v2.11.0 | | **Frontend** | Svelte 4 + Vite | | **Database** | SQLite via GORM | | **Audio** | Web Audio API (oscillators) | | **Linter** | golangci-lint | ## Project Structure ``` daily-timer/ ├── main.go # App entry point ├── wails.json # Wails configuration ├── internal/ │ ├── app/ │ │ └── app.go # Main App struct, Wails bindings │ ├── models/ │ │ └── models.go # Data models (Participant, Meeting, etc.) │ ├── storage/ │ │ └── storage.go # GORM database operations │ └── timer/ │ └── timer.go # Timer logic, event emission ├── frontend/ │ ├── src/ │ │ ├── App.svelte # Main component, event handlers │ │ ├── components/ │ │ │ ├── Timer.svelte │ │ │ ├── ParticipantList.svelte │ │ │ ├── Controls.svelte │ │ │ ├── Settings.svelte │ │ │ ├── History.svelte │ │ │ └── Setup.svelte │ │ └── lib/ │ │ └── i18n.js # Translations (RU/EN) │ └── wailsjs/ # Auto-generated Go bindings └── build/ # Build output ``` ## Critical Rules - MUST FOLLOW ### 1. Wails Terminal Directory **ALWAYS run `wails dev` from project root**, not from subdirectories: ```bash # ✅ CORRECT cd /Users/admin-msk/git/daily-timer && wails dev # ❌ WRONG - causes "wails.json not found" error cd /Users/admin-msk/git/daily-timer/internal/timer && wails dev ``` ### 2. TypeScript Model Casing Go structs use PascalCase, but Wails generates TypeScript with camelCase: ```go // Go model type Session struct { ID uint StartTime time.Time } ``` ```typescript // Generated TypeScript - use lowercase! session.id; // ✅ CORRECT session.ID; // ❌ WRONG - undefined session.startTime; // ✅ CORRECT session.StartTime; // ❌ WRONG - undefined ``` ### 3. GORM Partial Updates **NEVER use `db.Save()` for partial updates** - it overwrites ALL fields with zero values: ```go // ❌ WRONG - overwrites Active, Order, etc. with zero values func (s *Storage) UpdateParticipant(p *models.Participant) error { return s.db.Save(p).Error } // ✅ CORRECT - updates only specified fields func (s *Storage) UpdateParticipant(p *models.Participant) error { return s.db.Model(p).Updates(map[string]interface{}{ "name": p.Name, "email": p.Email, "time_limit": p.TimeLimit, }).Error } ``` ### 4. Timer Event Flags Use separate flags for different event types to prevent blocking: ```go // ❌ WRONG - one flag blocks both events speakerWarned bool // After warning, timeup never fires // ✅ CORRECT - separate flags speakerWarned bool // For warning event speakerTimeUpEmitted bool // For timeup event ``` ### 5. Sound in Wails (macOS) - Use Web Audio API oscillators, not audio files - macOS "Do Not Disturb" mode blocks sounds - Always add test buttons in Settings for verification ```javascript function playBeep(frequency, duration) { const ctx = new AudioContext(); const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.connect(gain); gain.connect(ctx.destination); osc.frequency.value = frequency; gain.gain.setValueAtTime(0.3, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + duration); osc.start(); osc.stop(ctx.currentTime + duration); } ``` ### 6. Svelte Event Dispatching When adding interactivity to list items: ```svelte ``` ### 7. i18n Translations Always update BOTH languages (RU and EN) in `frontend/src/lib/i18n.js`: ```javascript translations: { ru: { history: { deleteAll: 'Удалить историю', } }, en: { history: { deleteAll: 'Delete History', } } } ``` ### 8. Go Linter (golangci-lint) Run before committing: ```bash /opt/homebrew/bin/golangci-lint run ./... ``` Common fixes: - Remove explicit types when inferring: `idx := -1` not `var idx int = -1` - Remove unused functions - Handle all error returns ## Common Bugs & Solutions | Bug | Cause | Solution | | ----------------------- | --------------------------- | ------------------------------------- | | `wails.json not found` | Wrong directory | Run from project root | | Data disappears on edit | `db.Save()` overwrites | Use `Updates(map[string]interface{})` | | Event never fires | Shared flag blocks | Use separate flags per event | | Sounds don't play | DND mode or no AudioContext | Add test buttons, check DND | | `undefined` in template | Wrong case (ID vs id) | Check generated TS types | | Drag-drop doesn't save | Missing backend call | Call `ReorderParticipants()` | | "App is damaged" error | macOS Gatekeeper | Run `xattr -cr "Daily Timer.app"` | ## Development Commands ```bash # Run in development mode (ALWAYS run manually from clean shell!) cd /Users/admin-msk/git/daily-timer && wails dev # Build for production wails build # Run linter /opt/homebrew/bin/golangci-lint run ./... # Generate bindings (automatic in wails dev) wails generate module ``` ## Release Workflow ### Building Release ```bash # Build and package for current architecture make release # Build for all macOS architectures (arm64 + amd64) make release-all ``` Output: `dist/Daily-Timer-vX.X.X-macos-arm64.zip` ### Publishing Release to Gitea ```bash # Create and push tag git tag -a v0.2.0 -m "Release description" git push origin v0.2.0 # Build and upload to Gitea (requires GITEA_TOKEN) GITEA_TOKEN=your_token make release-publish ``` ### Rebuilding Existing Release If you need to rebuild a release (e.g., after fixing icon or bugs): ```bash # 1. Delete old dist folder rm -rf dist # 2. Delete local and remote tag git tag -d v0.1.0 git push origin :refs/tags/v0.1.0 # 3. Delete old release on Gitea (get release ID from web UI or API) curl -s -X DELETE \ -H "Authorization: token $GITEA_TOKEN" \ "https://git.movida.biz/api/v1/repos/bell/daily-timer/releases/RELEASE_ID" # 4. Create new tag git tag -a v0.1.0 -m "Release description" git push origin v0.1.0 # 5. Build and upload GITEA_TOKEN=your_token make release-publish ``` ### macOS Gatekeeper Fix **IMPORTANT**: Built app is not signed. macOS shows "app is damaged" error. Fix for users after downloading: ```bash xattr -cr "Daily Timer.app" ``` Or: Right-click → Open → Open (first launch only) For apps in /Applications: ```bash xattr -cr "/Applications/Daily Timer.app" ``` ## Event System Timer emits events via Wails runtime: - `timer:tick` - Every 100ms during active timer - `timer:speaker_warning` - When speaker time is running low - `timer:speaker_timeup` - When speaker time expired - `timer:meeting_warning` - When meeting time running low - `timer:meeting_ended` - When meeting ends - `timer:speaker_changed` - When switching speakers Frontend listens in App.svelte: ```javascript EventsOn('timer:speaker_warning', handleWarning); ``` ## Debugging Open DevTools in Wails app: `Cmd+Option+I` Add console.log for event debugging: ```javascript function handleWarning(state) { console.log('=== handleWarning EVENT RECEIVED ==='); console.log('settings:', settings); // ... } ``` --- **Last Updated**: February 2026