docs: add comprehensive Stripe billing guide
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 4s

Covers architecture, configuration steps, user flows, API routes,
webhooks, pricing, testing with Stripe CLI, production checklist,
and troubleshooting.
This commit is contained in:
Antigravity
2026-05-16 21:10:26 +00:00
parent aa12d2226f
commit bb75b2e763
36 changed files with 2099 additions and 735 deletions

View File

@@ -185,7 +185,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
handleNoteCreated(newNote)
setEditingNote({ note: newNote, readOnly: false })
} catch {
toast.error(t('notes.createFailed') || 'Failed to create note')
toast.error(t('notes.createFailed'))
}
})
}
@@ -429,10 +429,10 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
}, [sortedNotes])
const sortLabels: Record<SortOrder, string> = {
newest: t('sidebar.sortNewest') || 'Plus récentes',
oldest: t('sidebar.sortOldest') || 'Plus anciennes',
alpha: t('sidebar.sortAlpha') || 'A → Z',
manual: t('sidebar.sortManual') || 'Libre',
newest: t('sidebar.sortNewest'),
oldest: t('sidebar.sortOldest'),
alpha: t('sidebar.sortAlpha'),
manual: t('sidebar.sortManual'),
}
@@ -495,9 +495,9 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
{currentNotebook
? currentNotebook.name
: searchParams.get('shared') === '1'
? (t('sidebar.sharedWithMe') || 'Partagées avec moi')
? t('sidebar.sharedWithMe')
: searchParams.get('reminders') === '1'
? (t('sidebar.reminders') || 'Rappels')
? t('sidebar.reminders')
: t('notes.title')}
</h1>
</div>
@@ -511,7 +511,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
>
<Plus size={16} />
<span>{t('notes.newNote') || 'Add Note'}</span>
<span>{t('notes.newNote')}</span>
</button>
{currentNotebook && (
@@ -520,7 +520,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
>
<FolderOpen size={16} />
<span>{t('notebook.createSubNotebook') || 'Nouveau sous-carnet'}</span>
<span>{t('notebook.createSubNotebook')}</span>
</button>
)}
@@ -558,7 +558,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
router.push(`/home?${params.toString()}`)
}
}}
placeholder={t('search.placeholder') || 'Rechercher...'}
placeholder={t('search.placeholder')}
className="w-48 bg-transparent border-b border-foreground/20 focus:border-foreground outline-none text-[13px] text-foreground placeholder:text-muted-foreground/50 py-0.5 transition-colors"
/>
{inlineSearchQuery && (
@@ -585,7 +585,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
>
<Search size={16} />
<span>{t('notes.search') || 'Search'}</span>
<span>{t('notes.search')}</span>
</button>
)}
@@ -595,7 +595,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
>
<Sparkles size={16} />
<span>{t('notes.reorganize') || 'Réorganiser les notes'}</span>
<span>{t('notes.reorganize')}</span>
</button>
)}
@@ -622,7 +622,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
title={initialSettings.aiAssistantEnabled ? t('notebook.summary') : t('notebook.assistantRequiredForSummarize')}
>
<FileText size={16} />
<span>{t('notebook.summary') || 'Summarize'}</span>
<span>{t('notebook.summary')}</span>
</button>
)}
<button
@@ -640,7 +640,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
<div className="flex items-center justify-between">
<div className="flex items-center gap-3 text-[10px] font-bold uppercase tracking-[0.2em] text-muted-foreground">
<TagIcon size={12} />
<span>{t('labels.filterByTags') || 'Filter by Tags'}</span>
<span>{t('labels.filterByTags')}</span>
{selectedTagIds.length > 0 && (
<span className="bg-brand-accent/10 text-brand-accent px-2 py-0.5 rounded-full text-[9px] lowercase tracking-normal">
{selectedTagIds.length} active
@@ -650,7 +650,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
{availableTags.length > 10 && (
<input
type="text"
placeholder={t('labels.searchTags') || 'Search tags...'}
placeholder={t('labels.searchTags')}
className="bg-transparent border-b border-foreground/10 text-[10px] outline-none focus:border-brand-accent/40 py-1 px-2 w-32 transition-all focus:w-48 placeholder:text-muted-foreground/40"
value={tagSearchQuery}
onChange={e => setTagSearchQuery(e.target.value)}
@@ -696,7 +696,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
className="px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider text-muted-foreground/60 hover:text-foreground transition-colors border border-dashed border-border rounded-full"
>
{isTagsExpanded
? (t('labels.showLess') || 'Show less')
? t('labels.showLess')
: `+ ${availableTags.length - 10} more`}
</button>
)}
@@ -706,7 +706,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
onClick={() => setSelectedTagIds([])}
className="px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider text-red-500 hover:underline ms-auto"
>
{t('labels.clearAll') || 'Clear all'}
{t('labels.clearAll')}
</button>
)}
</div>
@@ -745,14 +745,14 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
{notes.length === 0 && (
<div className="h-64 flex flex-col items-center justify-center text-center space-y-4">
<p className="font-memento-serif text-xl italic text-muted-foreground">
{t('notes.emptyState') || 'This notebook is waiting for its first vision.'}
{t('notes.emptyState')}
</p>
<button
onClick={handleAddNote}
disabled={isCreating}
className="px-6 py-2 border border-foreground text-[13px] uppercase tracking-[0.2em] hover:bg-foreground hover:text-background transition-all"
>
{t('notes.createFirst') || 'Begin Drawing'}
{t('notes.createFirst')}
</button>
</div>
)}