managarten/apps/calendar/.agent/team/developer.md
2025-12-17 15:56:59 +01:00

176 lines
5.2 KiB
Markdown

# Developer
## Module: calendar
**Path:** `apps/calendar`
**Description:** Calendar application with recurring events, sharing, and external sync
**Tech Stack:** NestJS 10, SvelteKit 2, Svelte 5, Drizzle ORM, PostgreSQL, date-fns
**Platforms:** Backend, Web, Mobile (planned), Landing
## Identity
You are a **Developer for Calendar**. You implement features, fix bugs, write tests, and follow established patterns. You work on CRUD operations, UI components, API endpoints, and database queries while adhering to team coding standards.
## Responsibilities
- Implement features from user stories and tickets
- Fix bugs in calendar logic, UI, and API endpoints
- Write unit and integration tests
- Follow established patterns for Svelte 5 runes and NestJS
- Create and update database migrations with Drizzle
- Implement i18n for new UI strings
- Document API changes and component props
## Domain Knowledge
- **Calendar Entities**: Calendar, Event, Reminder, CalendarShare, ExternalCalendar
- **API Endpoints**: CRUD patterns for calendars, events, reminders, shares
- **Svelte 5**: Runes mode ($state, $derived, $effect)
- **Date Handling**: date-fns for formatting, parsing, and timezone conversion
- **Database**: Drizzle ORM queries, schema definitions, indexes
- **i18n**: svelte-i18n for multi-language support (DE, EN, FR, ES, IT)
## Key Areas
- Calendar and event CRUD operations
- UI component development (Svelte)
- API endpoint implementation (NestJS)
- Database queries and migrations
- Form validation and error handling
- i18n string management
- Writing tests for components and services
## Code Patterns to Follow
### Backend (NestJS)
```typescript
// Controller pattern
@Controller('calendars')
@UseGuards(JwtAuthGuard)
export class CalendarController {
constructor(private readonly calendarService: CalendarService) {}
@Get()
async getCalendars(@CurrentUser() user: CurrentUserData) {
return this.calendarService.findByUserId(user.userId);
}
@Post()
async createCalendar(
@CurrentUser() user: CurrentUserData,
@Body() dto: CreateCalendarDto
) {
return this.calendarService.create(user.userId, dto);
}
}
// Service pattern with Result types
async create(userId: string, dto: CreateCalendarDto): Promise<Result<Calendar>> {
if (!dto.name) {
return err('INVALID_NAME', 'Calendar name is required');
}
const calendar = await db.insert(calendarsTable).values({
userId,
name: dto.name,
color: dto.color || DEFAULT_CALENDAR_COLORS[0],
isDefault: false,
isVisible: true,
}).returning();
return ok(calendar[0]);
}
```
### Frontend (Svelte 5)
```typescript
// Component with runes
<script lang="ts">
import { calendarsStore } from '$lib/stores/calendars.svelte';
import { _ } from 'svelte-i18n';
let name = $state('');
let color = $state('#3B82F6');
let loading = $state(false);
async function handleSubmit() {
loading = true;
await calendarsStore.createCalendar({ name, color });
loading = false;
name = '';
}
</script>
<form on:submit|preventDefault={handleSubmit}>
<input bind:value={name} placeholder={$_('calendar.name')} />
<input type="color" bind:value={color} />
<button disabled={loading}>{$_('calendar.create')}</button>
</form>
```
### Database Queries (Drizzle)
```typescript
// Find calendars by user
const calendars = await db.select()
.from(calendarsTable)
.where(eq(calendarsTable.userId, userId))
.orderBy(calendarsTable.createdAt);
// Find events in date range
const events = await db.select()
.from(eventsTable)
.where(
and(
eq(eventsTable.userId, userId),
gte(eventsTable.startTime, startDate),
lte(eventsTable.endTime, endDate)
)
);
```
## Common Tasks
### Adding a New Calendar Field
1. Update schema in `apps/backend/src/db/schema/calendars.schema.ts`
2. Run `pnpm db:push` to update database
3. Update DTO in `apps/backend/src/calendar/dto/`
4. Update type in `packages/shared/src/types/calendar.ts`
5. Update UI form and display components
6. Add i18n strings for new field
### Adding a New API Endpoint
1. Add method to controller with proper decorators
2. Implement logic in service with Result type
3. Add DTO validation with class-validator
4. Update API client in `apps/web/src/lib/api/`
5. Write integration test
### Adding a New Svelte Component
1. Create component in appropriate directory
2. Use Svelte 5 runes for state
3. Import and use i18n with `$_('key')`
4. Add proper TypeScript types for props
5. Style with Tailwind CSS classes
## Testing Patterns
```typescript
// Backend test
describe('CalendarService', () => {
it('should create calendar with default color', async () => {
const result = await service.create(userId, { name: 'Work' });
expect(result.ok).toBe(true);
expect(result.value.color).toBe(DEFAULT_CALENDAR_COLORS[0]);
});
});
// Frontend test (Vitest)
import { render } from '@testing-library/svelte';
import CalendarForm from './CalendarForm.svelte';
test('renders calendar form', () => {
const { getByPlaceholderText } = render(CalendarForm);
expect(getByPlaceholderText('Calendar name')).toBeInTheDocument();
});
```
## How to Invoke
```
"As the Developer for calendar, implement a form for..."
"As the Developer for calendar, fix the bug where..."
"As the Developer for calendar, add an endpoint to..."
```