Compare commits
2 Commits
8eddbed00b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a91a8e9dfa | ||
|
|
fb94745588 |
251
.agents/skills/feature-planning/SKILL.md
Normal file
251
.agents/skills/feature-planning/SKILL.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Feature Planning Skill
|
||||
|
||||
This skill provides a structured workflow for implementing new features in the TimeTracker project. Use this skill when the user requests a new feature or significant functionality change.
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
```
|
||||
1. Requirements Discovery (iterative)
|
||||
└── Clarify edge cases, acceptance criteria, constraints
|
||||
|
||||
2. Feature Plan Creation
|
||||
└── docs/features/{feature-name}.md
|
||||
|
||||
3. Implementation
|
||||
└── Use plan as single source of truth
|
||||
```
|
||||
|
||||
## Phase 1: Requirements Discovery
|
||||
|
||||
**Goal:** Understand exactly what needs to be built before writing any code.
|
||||
|
||||
### Questions to Ask
|
||||
|
||||
Ask targeted questions to clarify:
|
||||
|
||||
#### Core Functionality
|
||||
- What is the primary purpose of this feature?
|
||||
- What user problem does it solve?
|
||||
- How should users interact with this feature?
|
||||
|
||||
#### Data & API
|
||||
- What new data needs to be stored?
|
||||
- What existing data structures are affected?
|
||||
- What API endpoints are needed (if any)?
|
||||
|
||||
#### User Interface
|
||||
- Where in the UI should this feature appear?
|
||||
- What views or components are needed?
|
||||
- What user interactions are required?
|
||||
|
||||
#### Edge Cases
|
||||
- What happens when inputs are invalid?
|
||||
- How should errors be handled?
|
||||
- What are the boundary conditions?
|
||||
- Are there any race conditions to consider?
|
||||
|
||||
#### Constraints
|
||||
- Are there performance requirements?
|
||||
- Any security considerations?
|
||||
- Browser/device compatibility?
|
||||
- Integration with existing features?
|
||||
|
||||
### Iteration Process
|
||||
|
||||
1. **Initial Questions** — Ask 3-5 focused questions based on the feature description
|
||||
2. **Wait for Answers** — Let the programmer respond
|
||||
3. **Follow-up Questions** — Dig deeper based on responses
|
||||
4. **Confirm Understanding** — Summarize your understanding and ask for confirmation
|
||||
5. **Iterate** — Repeat until requirements are clear
|
||||
|
||||
### Example Question Flow
|
||||
|
||||
```
|
||||
User: "Add the ability to export time entries to CSV"
|
||||
|
||||
Agent: "Before I start planning, I have a few questions:
|
||||
|
||||
1. Should the export include all entries or only filtered entries (if filters are active)?
|
||||
2. What columns should be included in the CSV? (date, duration, project, client, description?)
|
||||
3. Should the CSV include break minutes and net duration, or just total time?
|
||||
4. Is there a date range limit, or can users export all historical data?
|
||||
5. Should the export be triggered from the Time Entries page, or from a separate Export page?"
|
||||
```
|
||||
|
||||
## Phase 2: Feature Plan
|
||||
|
||||
**Goal:** Create a comprehensive plan document before implementation.
|
||||
|
||||
### Plan Location
|
||||
|
||||
Create the plan at: `docs/features/{feature-name}.md`
|
||||
|
||||
Use kebab-case for the filename (e.g., `csv-export.md`, `dark-mode.md`).
|
||||
|
||||
### Plan Template
|
||||
|
||||
```markdown
|
||||
# Feature: {Feature Name}
|
||||
|
||||
## Overview
|
||||
|
||||
Brief description of what this feature does and why it's needed.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Functional Requirements
|
||||
- Requirement 1
|
||||
- Requirement 2
|
||||
- Requirement 3
|
||||
|
||||
### Non-Functional Requirements
|
||||
- Performance: ...
|
||||
- Security: ...
|
||||
- Usability: ...
|
||||
|
||||
### Constraints
|
||||
- Constraint 1
|
||||
- Constraint 2
|
||||
|
||||
## Technical Approach
|
||||
|
||||
### Architecture Decisions
|
||||
- Decision 1 and rationale
|
||||
- Decision 2 and rationale
|
||||
|
||||
### Database Changes
|
||||
- New tables/columns
|
||||
- Migrations needed
|
||||
- Data migration strategy (if any)
|
||||
|
||||
### API Changes
|
||||
- New endpoints
|
||||
- Modified endpoints
|
||||
- Request/response formats
|
||||
|
||||
### Frontend Changes
|
||||
- New components
|
||||
- Modified components
|
||||
- State management approach
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. **Step 1: Backend - Database**
|
||||
- Create migration
|
||||
- Update Prisma schema
|
||||
- Regenerate client
|
||||
|
||||
2. **Step 2: Backend - Service**
|
||||
- Add service methods
|
||||
- Add validation schemas
|
||||
|
||||
3. **Step 3: Backend - Routes**
|
||||
- Create route handlers
|
||||
- Add middleware
|
||||
|
||||
4. **Step 4: Frontend - API Client**
|
||||
- Add API functions
|
||||
|
||||
5. **Step 5: Frontend - Components**
|
||||
- Create/update components
|
||||
- Add to routes if needed
|
||||
|
||||
6. **Step 6: Testing**
|
||||
- Manual testing steps
|
||||
- Edge case verification
|
||||
|
||||
## File Changes
|
||||
|
||||
### New Files
|
||||
- `backend/src/services/export.service.ts`
|
||||
- `frontend/src/hooks/useExport.ts`
|
||||
|
||||
### Modified Files
|
||||
- `backend/src/routes/timeEntry.routes.ts` — Add export endpoint
|
||||
- `frontend/src/pages/TimeEntriesPage.tsx` — Add export button
|
||||
- `frontend/src/api/timeEntries.ts` — Add export function
|
||||
|
||||
### Database
|
||||
- No changes required (or specify migration)
|
||||
|
||||
## Edge Cases
|
||||
|
||||
| Case | Handling |
|
||||
|------|----------|
|
||||
| No entries match filter | Show empty state, export empty CSV with headers |
|
||||
| Very large export (>10k entries) | Stream response, show progress indicator |
|
||||
| User cancels export mid-stream | Gracefully close connection |
|
||||
| Invalid date range | Return 400 error with clear message |
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Manual Testing
|
||||
1. Navigate to Time Entries page
|
||||
2. Apply date filter
|
||||
3. Click Export button
|
||||
4. Verify CSV downloads with correct data
|
||||
5. Open CSV and verify format
|
||||
|
||||
### Edge Case Testing
|
||||
1. Export with no entries
|
||||
2. Export with 1000+ entries
|
||||
3. Export with special characters in descriptions
|
||||
4. Export while timer is running
|
||||
|
||||
## Open Questions
|
||||
|
||||
- [ ] Question 1 (to be resolved during implementation)
|
||||
- [ ] Question 2
|
||||
```
|
||||
|
||||
### Plan Review
|
||||
|
||||
After creating the plan:
|
||||
|
||||
1. Present the plan to the programmer
|
||||
2. Ask for feedback and approval
|
||||
3. Make requested changes
|
||||
4. Get final approval before proceeding to implementation
|
||||
|
||||
## Phase 3: Implementation
|
||||
|
||||
**Goal:** Implement the feature exactly as planned.
|
||||
|
||||
### Rules
|
||||
|
||||
1. **Read the plan first** — Start by reading the full plan file
|
||||
2. **Follow the plan** — Implement step by step as outlined
|
||||
3. **Update if needed** — If implementation differs from plan, update the plan file
|
||||
4. **Document changes** — After completion, update relevant documentation
|
||||
|
||||
### Implementation Checklist
|
||||
|
||||
- [ ] Read `docs/features/{feature-name}.md`
|
||||
- [ ] Implement database changes (if any)
|
||||
- [ ] Implement backend service logic
|
||||
- [ ] Implement backend routes
|
||||
- [ ] Implement frontend API client
|
||||
- [ ] Implement frontend components
|
||||
- [ ] Run linting: `npm run lint`
|
||||
- [ ] Manual testing
|
||||
- [ ] Update plan if implementation differs
|
||||
- [ ] Update `project.md` if requirements changed
|
||||
- [ ] Update `README.md` if API changed
|
||||
- [ ] Update `AGENTS.md` if patterns changed
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Commands
|
||||
- Frontend lint: `npm run lint` (in `frontend/`)
|
||||
- Backend build: `npm run build` (in `backend/`)
|
||||
- DB migration: `npm run db:migrate` (in `backend/`)
|
||||
- DB generate: `npm run db:generate` (in `backend/`)
|
||||
|
||||
### File Locations
|
||||
- Backend routes: `backend/src/routes/`
|
||||
- Backend services: `backend/src/services/`
|
||||
- Backend schemas: `backend/src/schemas/`
|
||||
- Frontend pages: `frontend/src/pages/`
|
||||
- Frontend hooks: `frontend/src/hooks/`
|
||||
- Frontend API: `frontend/src/api/`
|
||||
- Feature plans: `docs/features/`
|
||||
24
AGENTS.md
24
AGENTS.md
@@ -49,6 +49,30 @@ This document describes the structure, conventions, and commands for the `vibe_c
|
||||
### After Making Changes
|
||||
**Always update documentation.** See [Documentation Maintenance](#documentation-maintenance).
|
||||
|
||||
## Feature Development Workflow
|
||||
|
||||
**For new features, AI agents MUST follow this process before writing any code.**
|
||||
|
||||
### Phase 1: Requirements Discovery
|
||||
1. Ask clarifying questions about the feature request
|
||||
2. Identify edge cases, constraints, and acceptance criteria
|
||||
3. Confirm understanding with the programmer
|
||||
4. Iterate until requirements are clear
|
||||
|
||||
### Phase 2: Feature Plan
|
||||
1. Create `docs/features/{feature-name}.md` with the feature plan
|
||||
2. Include: overview, requirements, technical approach, file changes, edge cases, testing
|
||||
3. Present plan for review
|
||||
4. Iterate until approved by the programmer
|
||||
|
||||
### Phase 3: Implementation
|
||||
1. Use the approved plan as the single source of truth
|
||||
2. Implement step by step following the plan
|
||||
3. Update the plan if implementation differs
|
||||
4. Update documentation after completion
|
||||
|
||||
**See the `feature-planning` skill for detailed workflow and templates.**
|
||||
|
||||
## Documentation Maintenance
|
||||
|
||||
**Every code change requires a documentation review.** When you modify the codebase, check whether documentation needs updating.
|
||||
|
||||
7
DOCS.md
7
DOCS.md
@@ -8,6 +8,13 @@
|
||||
| `README.md` | Setup instructions, API reference, features list | New endpoints, config changes, new features, technology stack changes |
|
||||
| `project.md` | Requirements, data model, functional specifications | Business logic changes, new entities, validation rules, UI requirements |
|
||||
| `DOCS.md` | Documentation standards and index | Documentation process changes, new documentation files |
|
||||
| `docs/features/*.md` | Feature implementation plans | Created during feature development, updated if implementation differs |
|
||||
|
||||
## AI Agent Skills
|
||||
|
||||
| Skill | Purpose | When to Use |
|
||||
|-------|---------|-------------|
|
||||
| `feature-planning` | Structured workflow for new features | When implementing new features or significant functionality changes |
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
|
||||
0
docs/features/.gitkeep
Normal file
0
docs/features/.gitkeep
Normal file
131
docs/features/timer-breaks.md
Normal file
131
docs/features/timer-breaks.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Feature: Timer Breaks (Pause During Work)
|
||||
|
||||
## Overview
|
||||
Allow users to take breaks while a timer is running. When on break, elapsed time is frozen and break time is tracked. When resumed, break time accumulates and is subtracted from the displayed work time.
|
||||
|
||||
## User Experience
|
||||
|
||||
### Timer States
|
||||
1. **Running** — normal state, elapsed time ticking
|
||||
2. **On Break** — elapsed time frozen, break time ticking, Stop/Cancel buttons disabled
|
||||
3. **Stopped** — no timer active
|
||||
|
||||
### UI Changes (TimerWidget)
|
||||
- Add a **"Break"** button (amber, `Pause` icon) next to Stop when timer is running
|
||||
- When on break:
|
||||
- Change pulsing dot color from red to amber
|
||||
- Elapsed time frozen at net work time
|
||||
- Show break time below: `Break: Xm XXs` (live-ticking)
|
||||
- Replace "Break" button with **"Resume"** button (green, `Play` icon)
|
||||
- **Disable** Stop and Cancel buttons (tooltip: "Resume before stopping")
|
||||
|
||||
### Duration Calculations
|
||||
- **Work time (displayed):** `now - startTime - totalBreakSeconds`
|
||||
- Where `totalBreakSeconds = (breakMinutes * 60) + (now - breakStart if on break)`
|
||||
- When on break: frozen at `(breakStart - startTime - breakMinutes * 60)`
|
||||
- **Break time (displayed):** `breakMinutes * 60 + (now - breakStart if on break)`
|
||||
|
||||
## Implementation
|
||||
|
||||
### 1. Database Schema (`backend/prisma/schema.prisma`)
|
||||
Add two fields to `OngoingTimer`:
|
||||
```prisma
|
||||
model OngoingTimer {
|
||||
// ... existing fields ...
|
||||
breakMinutes Int @default(0) @map("break_minutes")
|
||||
breakStart DateTime? @map("break_start") @db.Timestamptz()
|
||||
}
|
||||
```
|
||||
Run: `npx prisma migrate dev --name add_timer_break_fields`
|
||||
|
||||
### 2. Backend Service (`backend/src/services/timer.service.ts`)
|
||||
|
||||
**New method `startBreak(userId)`:**
|
||||
- Get ongoing timer, throw `NotFoundError` if none
|
||||
- Check `timer.breakStart` is null (not already on break), throw `BadRequestError` if on break
|
||||
- Update: `breakStart = new Date()`
|
||||
- Return updated timer
|
||||
|
||||
**New method `endBreak(userId)`:**
|
||||
- Get ongoing timer, throw `NotFoundError` if none
|
||||
- Check `timer.breakStart` is not null, throw `BadRequestError` if not on break
|
||||
- Calculate additional break minutes: `Math.floor((now - breakStart) / 60000)`
|
||||
- Update: `breakMinutes += additionalMinutes`, `breakStart = null`
|
||||
- Return updated timer
|
||||
|
||||
**Modify `stop(userId)`:**
|
||||
- Before creating time entry, check `timer.breakStart` is null — throw `BadRequestError("Cannot stop timer while on break")` if break is active
|
||||
- When creating `TimeEntry`, set `breakMinutes: timer.breakMinutes`
|
||||
|
||||
**Modify `cancel(userId)`:**
|
||||
- Check `timer.breakStart` is null — throw `BadRequestError("Cannot cancel timer while on break")` if break is active
|
||||
|
||||
### 3. Backend Routes (`backend/src/routes/timer.routes.ts`)
|
||||
Add two new routes (both require auth, no body validation):
|
||||
```
|
||||
POST /api/timer/break → timerService.startBreak(userId)
|
||||
POST /api/timer/resume → timerService.endBreak(userId)
|
||||
```
|
||||
|
||||
### 4. MCP Tools (`backend/src/routes/mcp.routes.ts`)
|
||||
Add two MCP tools: `pause_timer` and `resume_timer`.
|
||||
|
||||
### 5. Frontend Types (`frontend/src/types/index.ts`)
|
||||
Update `OngoingTimer` interface:
|
||||
```typescript
|
||||
export interface OngoingTimer {
|
||||
// ... existing fields ...
|
||||
breakMinutes: number;
|
||||
breakStart: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Frontend API (`frontend/src/api/timer.ts`)
|
||||
Add two methods:
|
||||
```typescript
|
||||
startBreak: async (): Promise<OngoingTimer> => { ... }
|
||||
endBreak: async (): Promise<OngoingTimer> => { ... }
|
||||
```
|
||||
|
||||
### 7. Frontend TimerContext (`frontend/src/contexts/TimerContext.tsx`)
|
||||
- Add `breakSeconds` state (live-updating, similar to `elapsedSeconds`)
|
||||
- Expose `isOnBreak` derived boolean (`ongoingTimer?.breakStart !== null`)
|
||||
- Update elapsed time calculation:
|
||||
- Running: `(now - startTime) - (breakMinutes * 60) - (now - breakStart if on break)`
|
||||
- On break: `(breakStart - startTime) - (breakMinutes * 60)` (frozen)
|
||||
- Break seconds: `(breakMinutes * 60) + (now - breakStart if on break)`
|
||||
- Add `startBreak()` and `endBreak()` callbacks
|
||||
- Expose `breakSeconds` and `isOnBreak` in context value
|
||||
|
||||
### 8. Frontend TimerWidget (`frontend/src/components/TimerWidget.tsx`)
|
||||
- Import `Pause` icon from lucide-react
|
||||
- Add Break/Resume button between project selector and Stop button
|
||||
- Show break time display when `breakSeconds > 0` or `isOnBreak`
|
||||
- Change dot color to amber when on break
|
||||
- Disable Stop/Cancel when on break with tooltip
|
||||
|
||||
## Files to Modify (in order)
|
||||
|
||||
| # | File | Change |
|
||||
|---|------|--------|
|
||||
| 1 | `backend/prisma/schema.prisma` | Add `breakMinutes`, `breakStart` to `OngoingTimer` |
|
||||
| 2 | `backend/src/services/timer.service.ts` | Add `startBreak()`, `endBreak()`, modify `stop()` and `cancel()` |
|
||||
| 3 | `backend/src/routes/timer.routes.ts` | Add `/break` and `/resume` routes |
|
||||
| 4 | `backend/src/routes/mcp.routes.ts` | Add `pause_timer` and `resume_timer` MCP tools |
|
||||
| 5 | `frontend/src/types/index.ts` | Add `breakMinutes`, `breakStart` to `OngoingTimer` |
|
||||
| 6 | `frontend/src/api/timer.ts` | Add `startBreak()`, `endBreak()` API methods |
|
||||
| 7 | `frontend/src/contexts/TimerContext.tsx` | Add break state, `breakSeconds`, `isOnBreak`, break methods |
|
||||
| 8 | `frontend/src/components/TimerWidget.tsx` | Add break UI (button, display, disabled states) |
|
||||
|
||||
## Edge Cases
|
||||
- Break start must be after timer start (always true since break is clicked after start)
|
||||
- Break duration naturally cannot exceed work duration (breakStart > startTime)
|
||||
- On stop: reject if break is active (user must resume first)
|
||||
- On cancel: reject if break is active (user must resume first)
|
||||
- Break minutes accumulate across multiple break/resume cycles
|
||||
- Timer refetch (every 60s) will sync break state from server
|
||||
|
||||
## Verification
|
||||
- Run `npm run lint` in both `frontend/` and `backend/`
|
||||
- Run `npm run build` in both `frontend/` and `backend/`
|
||||
- Manual testing: start timer → break → verify elapsed frozen, break ticking → resume → verify break added to total → stop → verify time entry has correct breakMinutes
|
||||
Reference in New Issue
Block a user