feat(credits): add sync billing — monthly credit subscription for cloud sync

Cloud Sync is now a paid feature: 30 credits/month (90/quarter, 360/year).
Users start in local-only mode and opt-in via Settings > Cloud Sync.
1 Credit = 1 Cent, so sync costs ~0.30€/month.

When credits run out, sync is paused (not deleted) and an in-app banner
prompts the user to top up. Local data is always preserved.

Backend (mana-credits):
- New sync_subscriptions table in credits schema
- SyncBillingService with activate/deactivate/chargeRecurring
- User-facing routes: GET/POST /api/v1/sync/{status,activate,deactivate,change-interval}
- Internal routes for server-side checks and cron triggers

Frontend (mana web):
- Sync API client + reactive sync-billing store
- syncEnabled parameter gates createUnifiedSync() — sync only starts when active
- Settings sync page with interval selection and activate/deactivate
- Pause banner in app layout when credits insufficient

Also: removed CALDAV_SYNC/GOOGLE_SYNC operations (not needed),
updated CLOUD_SYNC cost from 5 to 30 credits/month.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-10 22:21:58 +02:00
parent f9b6720d15
commit 5c2ea614cd
16 changed files with 1082 additions and 29 deletions

View file

@ -62,9 +62,7 @@ export enum CreditOperationType {
// Premium Features (Standard Credits: 0.5-5)
// -------------------------------------------------------------------------
// Sync features
CALDAV_SYNC = 'caldav_sync',
GOOGLE_SYNC = 'google_sync',
// Sync
CLOUD_SYNC = 'cloud_sync',
// Import/Export
@ -113,9 +111,7 @@ export const CREDIT_COSTS: Record<CreditOperationType, number> = {
[CreditOperationType.AI_ENRICHMENT]: 2,
// Premium Features
[CreditOperationType.CALDAV_SYNC]: 0.5,
[CreditOperationType.GOOGLE_SYNC]: 0.5,
[CreditOperationType.CLOUD_SYNC]: 5, // Monthly
[CreditOperationType.CLOUD_SYNC]: 30, // Monthly (or 90/quarterly, 360/yearly)
[CreditOperationType.BULK_IMPORT]: 0.2, // Per 10 items
[CreditOperationType.PDF_EXPORT]: 1,
@ -132,7 +128,6 @@ export const CREDIT_COSTS: Record<CreditOperationType, number> = {
*/
export enum CreditCategory {
AI = 'ai',
PRODUCTIVITY = 'productivity',
PREMIUM = 'premium',
}
@ -293,23 +288,11 @@ export const OPERATION_METADATA: Record<CreditOperationType, OperationMetadata>
},
// Premium - Sync
[CreditOperationType.CALDAV_SYNC]: {
name: 'CalDAV Sync',
description: 'Sync with CalDAV server',
category: CreditCategory.PREMIUM,
app: 'calendar',
},
[CreditOperationType.GOOGLE_SYNC]: {
name: 'Google Sync',
description: 'Sync with Google services',
category: CreditCategory.PREMIUM,
app: 'contacts',
},
[CreditOperationType.CLOUD_SYNC]: {
name: 'Cloud Sync (Monthly)',
description: 'Enable cloud synchronization',
name: 'Cloud Sync',
description: 'Cloud-Synchronisation über alle Geräte (30 Credits/Monat)',
category: CreditCategory.PREMIUM,
app: 'skilltree',
app: 'general',
},
// Premium - Import/Export