Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
cfff0cb
:sparkles: feat: Prompt guest users to log in when attempting to down…
danarocha-br Dec 7, 2025
42ac437
:sparkles: feat: Implement watermarks for exported images and OG imag…
danarocha-br Dec 7, 2025
f7e178b
:sparkles: feat: Implement Stripe integration for subscriptions and r…
danarocha-br Dec 7, 2025
3b9463c
:sparkles: feat: Implement public sharing with view limits and usage …
danarocha-br Dec 7, 2025
3a1abf2
:sparkles: feat: Introduce folder usage limits, integrate upgrade pro…
danarocha-br Dec 8, 2025
226b5d5
:sparkles: feat: Use Supabase service role client in Stripe webhook a…
danarocha-br Dec 8, 2025
21e9994
:sparkles: feat: Centralize SQL plan limit definitions and add a vali…
danarocha-br Dec 8, 2025
bcf7b65
:sparkles: feat: introduce video export limits with usage tracking, u…
danarocha-br Dec 8, 2025
eaa7ae5
:sparkles: feat: Implement video export usage limits and add decremen…
danarocha-br Dec 8, 2025
fe74ba0
:sparkles: feat: Add Stripe webhook audit logging, Sentry error repor…
danarocha-br Dec 8, 2025
98f6aa4
:sparkles: feat: Introduce usage tracking and sharing features with s…
danarocha-br Dec 8, 2025
d59c4ba
:wrench: refactor: Migrate usage counter updates from application act…
danarocha-br Dec 8, 2025
c85aa65
:sparkles: feat: Implement consistent error handling with new `Friend…
danarocha-br Dec 8, 2025
76cecf4
:sparkles: feat: Introduce Arcjet rate limiting to various API routes…
danarocha-br Dec 8, 2025
eee1439
:sparkles: feat: Implement Zod-based input validation for snippet and…
danarocha-br Dec 8, 2025
c73c90b
:sparkles: feat: introduce `withAuth` higher-order functions to centr…
danarocha-br Dec 8, 2025
2bbc745
:sparkles: feat: Add Stripe checkout success and canceled pages, upda…
danarocha-br Dec 8, 2025
36cfd59
:sparkles: feat: Implement 'over limit' tracking for user content wit…
danarocha-br Dec 8, 2025
4cd460d
:sparkles: feat: Introduce `@t3-oss/env-nextjs` for environment varia…
danarocha-br Dec 8, 2025
e970d82
:sparkles: feat: add CSRF protection to middleware and remove environ…
danarocha-br Dec 8, 2025
b527e37
:sparkles: feat: Implement user usage RPC with fallback and Sentry er…
danarocha-br Dec 8, 2025
76761fe
:sparkles: feat: add database migration for new foreign key and compo…
danarocha-br Dec 8, 2025
8267e94
:bug: refactor: Improve Stripe price ID mapping, use native disabled …
danarocha-br Dec 8, 2025
19bf608
:wrench: refactor: Implement collection-snippet many-to-many relation…
danarocha-br Dec 8, 2025
12e9945
:sparkles: feat: Enhance Next.js configuration with image optimizatio…
danarocha-br Dec 8, 2025
225cb94
:sparkles: feat: Refactor animation update logic to conditionally inc…
danarocha-br Dec 8, 2025
9acb3f2
:sparkles: feat: Update rate limiting to use publicLimiter across mul…
danarocha-br Dec 8, 2025
59fdf93
:sparkles: feat: Add Radix UI Checkbox component and integrate downgr…
danarocha-br Dec 8, 2025
05858cf
:sparkles: feat: Update user usage and plan queries to handle errors …
danarocha-br Dec 9, 2025
5dc4098
Update src/lib/arcjet/limiters.ts
danarocha-br Dec 9, 2025
64d44d9
:sparkles: feat: Implement new billing and subscription management sy…
danarocha-br Dec 9, 2025
078310b
Merge remote changes and resolve conflict in arcjet limiters
danarocha-br Dec 9, 2025
21ed37d
:sparkles: feat: Add 'use server' directive to withAuthAction utility…
danarocha-br Dec 9, 2025
86023f4
:sparkles: feat: Refactor animation creation and update logic to impr…
danarocha-br Dec 9, 2025
dfe5916
:sparkles: feat: Enhance snippet creation logic by adding robust limi…
danarocha-br Dec 9, 2025
c55f531
:sparkles: feat: Enhance error handling in checkout session creation …
danarocha-br Dec 9, 2025
e43dc9a
:sparkles: feat: Update CSRF handling in proxy logic to simplify orig…
danarocha-br Dec 9, 2025
a797d29
:sparkles: refactor: Update billing plan type to 'plan_type' for cons…
danarocha-br Dec 9, 2025
b0935d6
:bug: fix: Improve environment variable loading, add skip validation …
danarocha-br Dec 9, 2025
921c97e
:wrench: refactor: Enhance collection retrieval logic by ensuring id …
danarocha-br Dec 9, 2025
3eb56b6
:wrench: refactor: Remove Sentry route wrapping and context applicati…
danarocha-br Dec 9, 2025
52b3f1c
:sparkles: feat: Update free plan limits, refine usage tracking, and …
danarocha-br Dec 9, 2025
6c6cc07
:wrench: refactor: Change runtime environment for URL shortening API …
danarocha-br Dec 9, 2025
aa60664
:wrench: chore: Remove rate limiting from the OG image API.
danarocha-br Dec 10, 2025
57e6255
:sparkles: chore: Adjust friendly error page to fill screen height an…
danarocha-br Dec 10, 2025
42262ad
:wrench: refactor: Update FriendlyError component layout for better c…
danarocha-br Dec 10, 2025
0786dc9
:sparkles: feat: allow same-origin requests and Vercel preview URLs i…
danarocha-br Dec 11, 2025
740ecdc
:bug: refactor: Move checkout success UI, toast, and redirect logic t…
danarocha-br Dec 11, 2025
1170be8
:sparkles: feat: Introduce `subscription-sync` service to centralize …
danarocha-br Dec 11, 2025
4377f08
:bug: refactor: Split subscription profile update into two parts to a…
danarocha-br Dec 11, 2025
f08e5f7
:sparkles: feat: Add `update_user_plan` RPC function and integrate it…
danarocha-br Dec 11, 2025
93de416
:sparkles: feat: Add `reconcile_over_limit_content` function, refine …
danarocha-br Dec 11, 2025
5079ae0
:sparkles: feat: Enhance animation and snippet creation with improved…
danarocha-br Dec 11, 2025
efc72a5
:sparkles: feat: Implement usage limits cache management in snippet d…
danarocha-br Dec 11, 2025
7d31894
:sparkles: feat: Remove debug log file, enhance folder creation check…
danarocha-br Dec 11, 2025
a67f64c
:sparkles: feat: Remove debug log file, enhance animation and collect…
danarocha-br Dec 12, 2025
b640fe8
:sparkles: feat: Enhance animation collection deletion and movement l…
danarocha-br Dec 12, 2025
b0cd292
:sparkles: feat: Refactor collection deletion logic to include snippe…
danarocha-br Dec 12, 2025
f0acfe7
:sparkles: feat: Add ConfirmDeleteDialog component and integrate it i…
danarocha-br Dec 12, 2025
3f33c36
:sparkles: feat: Enhance usage limits computation with agent logging …
danarocha-br Dec 12, 2025
8f39738
:bug: fix: Update validation error message for code input, enhance us…
danarocha-br Dec 12, 2025
3b021df
:sparkles: feat: Implement subscription synchronization functionality…
danarocha-br Dec 12, 2025
9ba6573
feat: Implement comprehensive billing dialog with payment method and …
danarocha-br Dec 12, 2025
576628e
:sparkles: feat: Implement a new downgrade feature with dedicated UI …
danarocha-br Dec 12, 2025
973b8ba
:bug: fix: Prevent duplicate subscriptions and enhance invoice displa…
danarocha-br Dec 12, 2025
f3e132b
:lipstick: chore: make settings panel more accessible
danarocha-br Dec 12, 2025
4c47b1a
:sparkles: feat: Implement Stripe customer portal return handling and…
danarocha-br Dec 12, 2025
8489bf7
:sparkles: feat: Update plan terminology from 'started' to 'starter' …
danarocha-br Dec 16, 2025
0288bd3
🗑️ chore: Remove verbose console logs and refine subscription period …
danarocha-br Dec 16, 2025
8cc6c56
:sparkles: feat: Add email preview and development scripts, enhance p…
danarocha-br Dec 16, 2025
e6232ff
:sparkles: feat: Add SQL function to gracefully handle user deletion …
danarocha-br Dec 16, 2025
e97769e
:bug: fix: Enhance animation persistence by skipping auto-save for em…
danarocha-br Dec 16, 2025
4418388
:bug: fix: Enhance webhook handling and subscription management by ve…
danarocha-br Dec 16, 2025
90e97d3
:bug: fix: Clean up account deletion process by removing unnecessary …
danarocha-br Dec 16, 2025
b373f1c
:sparkles: feat: Integrate comprehensive tracking for user actions in…
danarocha-br Dec 17, 2025
65d4e77
:wrench: chore: Update pnpm version to 10.26.0 in plan-validation wor…
danarocha-br Dec 17, 2025
4221eb5
:bug: fix: Enhance user snippet saving process by adding usage data r…
danarocha-br Dec 17, 2025
b943e68
:bug: fix: Improve user snippet saving by implementing session valida…
danarocha-br Dec 17, 2025
dd6f3f6
:art: style: Update letter-spacing for code elements to zero in CSS a…
danarocha-br Dec 17, 2025
b4bb900
:sparkles: feat: Enhance error handling in animation actions with a s…
danarocha-br Dec 17, 2025
2f564ea
:sparkles: feat: Introduce JSON type definitions in Liveblocks config…
danarocha-br Dec 17, 2025
3eb5530
:sparkles: feat: Add Content Security Policy and X-Frame-Options head…
danarocha-br Dec 17, 2025
5f2543d
:sparkles: feat: Update plan validation workflow to trigger on specif…
danarocha-br Dec 17, 2025
7172249
:sparkles: feat: Update Keepalive workflow to run on Mondays at 00:00…
danarocha-br Dec 17, 2025
e209e67
:sparkles: feat: Update Notion URL handling in generatePlatformUrl fu…
danarocha-br Dec 17, 2025
0da4690
:sparkles: feat: Refactor plan validation workflow to trigger on spec…
danarocha-br Dec 17, 2025
a0ddb08
:bug: fix: Refactor OG image generation to improve error handling and…
danarocha-br Dec 17, 2025
b643704
:sparkles: feat: Enhance animation embed functionality by adding auto…
danarocha-br Dec 17, 2025
a5263d7
:sparkles: feat: Enhance OG image generation by implementing syntax h…
danarocha-br Dec 17, 2025
8f8ca44
:sparkles: feat: Integrate watermark visibility preferences across an…
danarocha-br Dec 17, 2025
b4ee885
:sparkles: feat: Optimize bundle size for Edge Runtime by temporarily…
danarocha-br Dec 17, 2025
b23ed4e
:sparkles: feat: Enhance README with new features for code animations…
danarocha-br Dec 17, 2025
275d047
:sparkles: feat: Refactor watermark preference management by removing…
danarocha-br Dec 17, 2025
5579aa9
:bug: fix: Integrate AuthProvider into Providers component for enhanc…
danarocha-br Dec 17, 2025
79e82ba
:sparkles: feat: Enhance checkout success flow by invalidating billin…
danarocha-br Dec 17, 2025
f8c2cd2
:sparkles: feat: Update animation and snippet creation actions to use…
danarocha-br Dec 17, 2025
7ba885f
:fire: refactor: Remove the "Refresh subscription status" button from…
danarocha-br Dec 17, 2025
053de5c
:fire: refactor: Remove watermark visibility management and related e…
danarocha-br Dec 17, 2025
1736a48
:sparkles: feat: Add middleware for CORS handling and Next.js 16 comp…
danarocha-br Dec 17, 2025
124f3e7
:fire: refactor: Remove middleware file for proxy re-export, streamli…
danarocha-br Dec 17, 2025
4f52b3f
:sparkles: feat: Introduce payment method and invoices query keys for…
danarocha-br Dec 17, 2025
3e80aca
:sparkles: feat: Update snippet creation logic to handle null max lim…
danarocha-br Dec 18, 2025
674da0d
:sparkles: feat: Add an empty line at the end of dtos.ts for improved…
danarocha-br Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 44 additions & 23 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
NODE_ENV=development

# GENERAL
NEXT_PUBLIC_VERCEL_ENV=development
NEXT_PUBLIC_VERCEL_URL=localhost:3000

NEXT_PUBLIC_SENTRY_TUNNEL=/monitoring
SENTRY_DSN=

#SUPABASE
# Required: core platform
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=

#CANNY
CANNY_API_KEY=

NEXT_PUBLIC_HOTJAR_SITE_ID=

#LIVEBLOCKS
SUPABASE_SERVICE_ROLE_KEY=
LIVEBLOCKS_SECRET_KEY=
LIVEBLOCKS_PUCLIC_API_KEY=

KEEPALIVE_ENDPOINT=
KEEPALIVE_API_KEY=

#ANALYTICS
# Required: app + billing
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_VERCEL_ENV=development
NEXT_PUBLIC_VERCEL_URL=localhost:3000
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_STARTER_MONTHLY_PRICE_ID=price_...
NEXT_PUBLIC_STRIPE_STARTER_YEARLY_PRICE_ID=price_...
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PRICE_ID=price_...
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PRICE_ID=price_...

# Optional: observability
NEXT_PUBLIC_SENTRY_TUNNEL=/monitoring
SENTRY_DSN=
SENTRY_ENVIRONMENT=
SENTRY_TRACES_SAMPLE_RATE=
SENTRY_PROFILES_SAMPLE_RATE=
SENTRY_TRACE_PROPAGATION_TARGETS=
SENTRY_RELEASE=
SENTRY_REPLAYS_SESSION_SAMPLE_RATE=
SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=

# Optional: analytics + marketing
NEXT_PUBLIC_POSTHOG_KEY=
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
NEXT_PUBLIC_POSTHOG_ENABLE_LOCAL=false
POSTHOG_API_KEY=
NEXT_PUBLIC_HOTJAR_SITE_ID=
NEXT_PUBLIC_SITE_URL=
CANNY_API_KEY=

# Optional: feature flags + experiments
NEXT_PUBLIC_EXPORT_EXPERIMENT=control
NEXT_PUBLIC_TRANSITION_EXPERIMENT=control

#SECURITY
ARCJET_KEY=
# Optional: collaboration / security
ARCJET_KEY=
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_API_KEY=
CORS_ALLOWED_ORIGIN=
NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA=
VERCEL_GIT_COMMIT_SHA=

# Optional: maintenance
KEEPALIVE_ENDPOINT=
KEEPALIVE_API_KEY=
SKIP_ENV_VALIDATION=false
38 changes: 38 additions & 0 deletions .github/workflows/cron-check-usage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Check Usage Limits

on:
schedule:
# Runs daily at midnight UTC
- cron: '0 0 * * *'
# Allow manual triggering from the Actions tab
workflow_dispatch:

jobs:
check-usage:
runs-on: ubuntu-latest

steps:
- name: Invoke Usage Check API
env:
APP_URL: ${{ secrets.APP_URL || 'https://jollycode.dev' }}
CRON_SECRET: ${{ secrets.CRON_SECRET }}
run: |
if [ -z "$CRON_SECRET" ]; then
echo "Error: CRON_SECRET secret is not set in GitHub Secrets"
exit 1
fi

response=$(curl -s -w "\n%{http_code}" -X GET \
-H "Authorization: Bearer ${CRON_SECRET}" \
"${APP_URL}/api/cron/check-usage")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

if [ "$http_code" -eq 200 ]; then
echo "✅ Usage check completed successfully"
echo "$body" | jq '.' || echo "$body"
else
echo "❌ Usage check failed with HTTP $http_code"
echo "$body"
exit 1
fi
28 changes: 24 additions & 4 deletions .github/workflows/keepalive.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: Keepalive

on:
schedule:
# Runs every Monday at midnight UTC
- cron: '0 0 * * 0'
# Runs every Monday at 00:00 UTC (day 1 = Monday)
- cron: '0 0 * * 1'
# Allow manual triggering from the Actions tab
workflow_dispatch:

Expand All @@ -13,6 +13,26 @@ jobs:

steps:
- name: Ping Keepalive Endpoint
env:
KEEPALIVE_URL: ${{ secrets.KEEPALIVE_ENDPOINT }}
run: |
curl -X GET "${{ secrets.KEEPALIVE_ENDPOINT}}" \
-H "Authorization: Bearer ${{ secrets.KEEPALIVE_API_KEY }}"
if [ -z "$KEEPALIVE_URL" ]; then
echo "::error::KEEPALIVE_ENDPOINT secret is not set"
echo "Please set it in repository settings to your production URL"
echo "Example: https://your-domain.com/api/keepalive"
exit 1
fi

response=$(curl -s -w "\n%{http_code}" "$KEEPALIVE_URL")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

echo "Response body: $body"
echo "HTTP Status: $http_code"

if [ "$http_code" -ne 200 ]; then
echo "::error::Keepalive ping failed with status $http_code"
exit 1
fi

echo "✅ Keepalive ping successful!"
Comment on lines +26 to +38
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add curl error handling to prevent false success.

The script doesn't handle curl command failures (network errors, DNS failures, timeouts, connection refused, etc.). If curl fails, the script continues with potentially empty or unexpected variables, leading to unclear error messages or false success.

Apply this diff to add robust error handling:

-          response=$(curl -s -w "\n%{http_code}" "$KEEPALIVE_URL")
+          response=$(curl -s -S -f -w "\n%{http_code}" "$KEEPALIVE_URL" 2>&1) || {
+            echo "::error::Failed to connect to keepalive endpoint"
+            exit 1
+          }
           http_code=$(echo "$response" | tail -n1)
           body=$(echo "$response" | sed '$d')
           
           echo "Response body: $body"
           echo "HTTP Status: $http_code"

Additional considerations:

  1. Security: Line 30 logs the response body, which could expose sensitive information. Consider whether this is necessary or if a truncated/sanitized version would suffice.
  2. Robustness: Add a timeout flag (e.g., --max-time 30) to prevent the workflow from hanging indefinitely.

Alternative implementation with timeout:

-          response=$(curl -s -w "\n%{http_code}" "$KEEPALIVE_URL")
+          response=$(curl -s -S -f --max-time 30 -w "\n%{http_code}" "$KEEPALIVE_URL" 2>&1) || {
+            curl_exit_code=$?
+            echo "::error::Failed to connect to keepalive endpoint (exit code: $curl_exit_code)"
+            exit 1
+          }
🤖 Prompt for AI Agents
.github/workflows/keepalive.yml around lines 26 to 38: the curl invocation
doesn't check for curl failures or timeouts and prints the full response body,
which can yield false success or leak sensitive data; update the step so you run
curl with a timeout flag (e.g., --max-time 30) and capture its exit status, only
parse http_code/body if curl succeeded, on curl failure log an explicit error
with curl's exit code and exit 1, and avoid echoing the full response body
(either remove the body log or print a truncated/sanitized preview).

39 changes: 39 additions & 0 deletions .github/workflows/plan-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Plan Limits

on:
pull_request:
paths:
- 'src/lib/config/plans.ts'
- 'supabase/migrations/**'
- '.github/workflows/plan-validation.yml'
push:
branches:
- main
paths:
- 'src/lib/config/plans.ts'
- 'supabase/migrations/**'
- '.github/workflows/plan-validation.yml'

jobs:
validate-plan-limits:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
# Version is automatically read from package.json packageManager field
uses: pnpm/action-setup@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Validate plan limits
run: pnpm run validate:plans
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.cursor/debug.log

# local env files
.env*.local
Expand Down
38 changes: 33 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,39 @@
- PRs should describe intent, note any env vars touched (e.g., `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`, Sentry/PostHog keys), and link related issues. Include screenshots or short clips for UI changes and mention manual checks run.

## Security & Configuration Tips
- Store secrets in `.env.local`; never commit keys. Required keys include Supabase (`NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`) and Sentry/PostHog credentials where applicable.
- Store secrets in `.env.local`; never commit keys. Required keys include Supabase (`NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`), Stripe (`STRIPE_SECRET_KEY`, `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`, `STRIPE_WEBHOOK_SECRET`, price IDs), and Sentry/PostHog credentials where applicable.
- When developing analytics/Sentry changes, guard them behind environment checks to keep local runs noise-free.
- Stripe webhook endpoint: `/api/webhooks/stripe` - must be configured in Stripe Dashboard with events: `customer.subscription.created`, `customer.subscription.updated`, `customer.subscription.deleted`, `checkout.session.completed`.

## Usage Limits & Plans
- Free plan caps: 10 snippets, 10 animations, 5 slides per animation. Pro plan removes limits.
- Usage counts live in `profiles` and `usage_limits` with helper RPCs (`check_*_limit`, `increment_*`, `decrement_*`).
- Use `src/lib/services/usage-limits.ts` + `src/features/user/queries.ts` for limit checks and usage fetch/invalidation.
- Surface upgrade prompts via `UpgradeDialog` and show current usage with `UsageStatsWidget`.

### Plan Tiers

- **Free**: 0 saved snippets/animations, 3 slides per animation, 50 public shares
- **Started** ($5/mo or $3/mo yearly): 50 snippets, 50 animations, 10 slides per animation, 10 folders, 50 video exports, 1,000 public shares
- **Pro** ($9/mo or $7/mo yearly): Unlimited everything + watermark removal + priority support

### Implementation Details

- Plan configuration lives in `src/lib/config/plans.ts` with helper functions (`getPlanConfig`, `isLimitReached`, `getUsagePercentage`, etc.)
- Database schema in migration `supabase/migrations/20251207103258_add_usage_limits_and_plans.sql`:
- `profiles` table has plan columns: `plan` (enum), `plan_updated_at`, usage counters, and Stripe fields
- PostgreSQL RPC functions handle atomic limit checks and counter updates
- Usage tracking service: `src/lib/services/usage-limits.ts` provides `checkSnippetLimit`, `checkAnimationLimit`, `incrementUsageCount`, `decrementUsageCount`, `getUserUsage`
- Server actions enforce limits: `src/actions/snippets/create-snippet.ts` and `src/actions/animations/create-animation.ts` check RPCs before saving
- React Query hooks: `src/features/user/queries.ts` exports `useUserUsage()` and `useUserPlan()` for client-side usage display
- UI components:
- `src/components/usage-stats-widget` shows current usage with progress bars and upgrade CTA
- `src/components/ui/upgrade-dialog` displays plan comparison and pricing for upgrades
- Animation store (`src/app/store/animation-store.ts`) enforces slide limits via `addSlide({ maxSlides, onLimit })` parameter

### Stripe Integration

- Service layer: `src/lib/services/stripe.ts` handles customer management, checkout sessions, subscriptions, and webhooks
- Client-side: `src/lib/stripe-client.ts` loads Stripe.js; `src/actions/stripe/checkout.ts` provides `createCheckoutSession()` and `createPortalSession()` server actions
- API endpoints:
- `/api/checkout` - Creates Stripe checkout session for plan upgrades
- `/api/webhooks/stripe` - Handles subscription lifecycle events and updates user plans
- `/api/customer-portal` - Creates Stripe customer portal session for subscription management
- Webhooks automatically update `profiles` table when subscriptions are created, updated, or canceled
- Price IDs must be configured in environment variables for both monthly and yearly billing for Started and Pro plans
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ Welcome to the Github repo for JollyCode. An open-source aesthetically appealing

We support a wide array of programming languages, including Python, JavaScript, Java, C++, C#, Ruby, PHP, and more. No matter your preferred development language, we've got you covered.

### 🎬 Code Animations

Create stunning multi-slide code animations with smooth transitions. Perfect for tutorials, demos, and showcasing code evolution. Export as GIF, MP4 or live embeds.

### 🎨 Share Code Imagery

Fancy showing off your beautiful code? You can share captivating images of your code right from JollyCode.
Share captivating images of your code with beautiful syntax-highlighted Open Graph previews for Twitter, LinkedIn, and other social platforms. Your shared links automatically generate professional preview cards.

### 🌍 Short shared URL

Expand All @@ -22,15 +26,13 @@ Once you share your URL, it gets shortened for easy sharing via services like Tw

On the shared link, visualize the users interacting with your code snippet.

### 💾 Code Snippets

Save your code snippets for future reference directly in the tool. Group your saved snippets into categories for easy retrieval.
### 💾 Code Snippets & Collections

- **Saving Snippets**: Use the 'Save Snippet' button after you've added your code. Give your snippet a meaningful name so you can easily find it later.
Save your code snippets and animations for future reference. Organize them into collections (folders) for easy retrieval and management.

- **Organizing Snippets**: Group your snippets into categories or use tags to organize them. This organization method makes it easy to find a relevant piece of code.

- **Using Snippets**: Click on any snippet in 'My Snippets' to load it into the code editor. You can then modify it as per your current requirements.
- **Saving**: Save snippets and animations with meaningful names for quick access.
- **Organizing**: Group your content into collections to keep everything organized.
- **Using**: Click on any saved item to load it into the editor and continue working.

## 🚀 Built With

Expand All @@ -39,6 +41,10 @@ Save your code snippets for future reference directly in the tool. Group your sa
- Supabase
- TailwindCSS

## Environment Variables

We validate configuration with `@t3-oss/env-nextjs`; `pnpm env:check` runs automatically before `pnpm dev`, `pnpm build`, and `pnpm start`. Copy `.env.example` to `.env.local` and fill in the required values.

## Roadmap

For any additional feature request 👉: [Check it out](https://jollycode.canny.io/feature-requests)
Expand Down
74 changes: 74 additions & 0 deletions emails/account-deleted-email.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from "react";
import {
Body,
Container,
Head,
Heading,
Html,
Preview,
Section,
Text,
Tailwind,
} from "@react-email/components";
import { Logo } from "../src/components/ui/logo";

interface AccountDeletedEmailProps {
name?: string;
}

export default function AccountDeletedEmail({ name }: AccountDeletedEmailProps) {
return (
<Html>
<Head />
<Preview>Your Jolly Code account has been deleted</Preview>
<Tailwind>
<Body className="bg-white my-auto mx-auto font-sans">
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
<div className="flex justify-center">
<Logo variant="short" className="mx-auto scale-75 -mb-5" />
</div>
<Heading className="text-black text-xl font-normal text-center p-0 my-[30px] mx-0">
Your account has been deleted
</Heading>
<Text className="text-black text-[14px] leading-[24px]">
Hey {name || "there"},
</Text>
<Text className="text-black text-[14px] leading-[24px]">
This email confirms that your Jolly Code account and all associated data have been permanently deleted from our systems.
</Text>
<Text className="text-black text-[14px] leading-[24px]">
<strong>What was deleted:</strong>
</Text>
<Text className="text-black text-[14px] leading-[24px] ml-4">
• Your profile and account information<br />
• All your code snippets and animations<br />
• All your collections and folders<br />
• All shared links and associated data<br />
• Your subscription information (if applicable)
</Text>
<Text className="text-black text-[14px] leading-[24px]">
If you had an active subscription, it has been canceled and no further charges will be made.
</Text>
<Text className="text-black text-[14px] leading-[24px]">
If you didn't request this deletion or have any questions, please contact us immediately at{" "}
<a href="mailto:support@jollycode.dev" className="text-blue-600 underline">
support@jollycode.dev
</a>
.
</Text>
<Text className="text-black text-[14px] leading-[24px] mt-6">
We're sorry to see you go. If you change your mind, you can always create a new account in the future.
</Text>
<Text className="text-black text-[14px] leading-[24px] mt-6">
Best regards,
</Text>
<Text className="text-black text-[14px] leading-[24px]">
The Jolly Code Team
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
}

Loading