chore: remove copilot-instructions, fix dev port
This commit is contained in:
320
.github/copilot-instructions.md
vendored
320
.github/copilot-instructions.md
vendored
@@ -1,320 +0,0 @@
|
|||||||
# 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
|
|
||||||
<!-- Parent component -->
|
|
||||||
<ChildList on:customEvent={handleEvent} />
|
|
||||||
|
|
||||||
<!-- Child component -->
|
|
||||||
<script>
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
function handleClick(id) {
|
|
||||||
dispatch('customEvent', { id })
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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
|
|
||||||
4
Makefile
4
Makefile
@@ -1,8 +1,8 @@
|
|||||||
.PHONY: dev build clean install frontend
|
.PHONY: dev build clean install frontend
|
||||||
|
|
||||||
# Development
|
# Development (fixed ports: Vite 5173, Wails DevServer 34115)
|
||||||
dev:
|
dev:
|
||||||
wails dev
|
wails dev -devserver localhost:34115
|
||||||
|
|
||||||
# Build for macOS
|
# Build for macOS
|
||||||
build:
|
build:
|
||||||
|
|||||||
Reference in New Issue
Block a user