feat: Tier 1 & 2 — Daily Note, Voice, Flashcard quota, Readwise, Calendar, Agent Gallery
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m7s
CI / Deploy production (on server) (push) Has been skipped

Tier 1:
- BASIC tier: chat (10/mo) + reformulate (10/mo) désormais accessibles
- Nouveaux quotas: ai_flashcard + voice_transcribe dans tous les tiers
- /api/notes/daily : note du jour auto-créée (find or create)
- Bouton Note du Jour dans la sidebar (CalendarDays)
- Voice-to-Text dans l'éditeur (Web Speech API, bouton Mic toolbar)
- Flashcard generation → quota ai_flashcard (au lieu de reformulate)

Tier 2:
- Intégration Readwise: GET/POST/DELETE /api/integrations/readwise
- Intégration Google Calendar: OAuth flow + today's events + meeting notes
- /api/integrations/calendar + /callback
- Page /settings/integrations avec cards Calendar + Readwise
- SettingsNav: onglet Intégrations
- AgentTemplates: catégories + 4 nouveaux templates (Digest/Recap/AutoTagger/Synthesis)

Schema:
- UserAISettings.integrationTokens Json? (migration 20260529160000)
- prisma generate + migrate deploy appliqués

Fix:
- SpeechRecognition types (triple-slash @types/dom-speech-recognition)
- Notebook.create: suppression champ 'description' inexistant

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Antigravity
2026-05-29 15:14:01 +00:00
parent 79fd6553b7
commit c415d93945
20 changed files with 1271 additions and 63 deletions

View File

@@ -49,7 +49,7 @@ export async function POST(request: NextRequest) {
}
try {
await checkEntitlementOrThrow(session.user.id, 'reformulate')
await checkEntitlementOrThrow(session.user.id, 'ai_flashcard')
} catch (err) {
if (err instanceof QuotaExceededError) {
const isTierLocked = err.currentQuota === 0
@@ -70,7 +70,7 @@ export async function POST(request: NextRequest) {
language: note.language || undefined,
})
incrementUsageAsync(session.user.id, 'reformulate')
incrementUsageAsync(session.user.id, 'ai_flashcard')
return NextResponse.json({ cards, noteId: note.id, style })
} catch (error) {