-
Notifications
You must be signed in to change notification settings - Fork 136
feat: implement newsletter page for pro users #178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@Sandesh-Upadhyay is attempting to deploy a commit to the AJEET PRATAP SINGH's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughAdds comprehensive newsletter feature: docs and guides, newsletter data/types and components, list/detail pages with pro-user gating and test-mode bypass, middleware/auth config updates, Razorpay lazy-init via Proxy, startup/logging changes, and a Windows start-dev script. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant NewslettersPage as Newsletters Page
participant Session as NextAuth Session
participant Subscription as useSubscription
participant Data as Newsletter Data Store
User->>NewslettersPage: GET /newsletters
NewslettersPage->>Session: request session
alt Test mode enabled (NEXT_PUBLIC_ENABLE_TEST_MODE)
Session-->>NewslettersPage: (bypass) proceed
NewslettersPage->>Data: getNewslettersByDate()
Data-->>NewslettersPage: grouped newsletters
NewslettersPage-->>User: render list
else Normal mode
Session-->>NewslettersPage: session present?
alt not authenticated
NewslettersPage-->>User: redirect /login
else authenticated
NewslettersPage->>Subscription: check pro status
alt not pro
NewslettersPage-->>User: redirect /pricing
else pro
NewslettersPage->>Data: getNewslettersByDate()
Data-->>NewslettersPage: grouped newsletters
NewslettersPage-->>User: render list
end
end
end
sequenceDiagram
participant Client as Module Consumer
participant Proxy as rz_instance Proxy
participant Init as getRazorpayInstance()
participant Razorpay as Razorpay Instance
Client->>Proxy: access rz_instance.method()
Proxy->>Init: ensure instance
alt first access
Init->>Init: validate env vars
Init->>Razorpay: new Razorpay(...)
Razorpay-->>Init: instance
Init-->>Proxy: return bound methods
else cached
Init-->>Proxy: return cached bound methods
end
Proxy-->>Client: invoke method
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Areas to focus review on:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (6)
apps/api/src/prisma.ts (2)
108-122: Consider using the existingwithTimeouthelper for database connection.The
connectDBfunction doesn't use thewithTimeouthelper defined at lines 94-106, which could result in indefinite hanging if the database is unresponsive. Additionally, in production mode, immediately exiting the process may prevent graceful shutdown of existing connections or in-flight requests.Apply this diff to add timeout protection:
async function connectDB() { try { - await prisma.$connect(); + await withTimeout(prisma.$connect(), 5000); console.log("✅ Database connected successfully"); } catch (err: any) { console.error("❌ Database connection failed:", err.message || err);
112-112: Useunknowninstead ofanyfor better type safety.The catch clause uses
any, which bypasses TypeScript's type checking. Usingunknownforces explicit type checking before accessing properties.Apply this diff:
- } catch (err: any) { + } catch (err: unknown) { - console.error("❌ Database connection failed:", err.message || err); + console.error("❌ Database connection failed:", err instanceof Error ? err.message : String(err));apps/web/PR_DESCRIPTION.md (1)
36-51: Add language identifier to the code fence for better rendering.The code block at line 36 should specify a language identifier to enable proper syntax highlighting in markdown renderers.
Apply this diff:
-``` +```plaintext src/RUN_AND_PUSH_GUIDE.md (1)
134-142: Consider whether this commit message is appropriately scoped.The example commit message lists multiple distinct features (listing page, detail page, authentication, documentation) in a single commit. For better git history and easier rollbacks, consider demonstrating atomic commits where each addresses one logical change.
Example structure:
# First commit - core implementation git commit -m "feat: add newsletter pages with rich content support" # Second commit - authentication git commit -m "feat: add pro-user authentication for newsletter pages" # Third commit - documentation git commit -m "docs: add newsletter documentation and examples"apps/web/src/app/(main)/newsletters/page.tsx (1)
15-15: Memoize the newsletter grouping calculation.The
getNewslettersByDate()call runs on every render, recalculating the grouping and sorting each time. This is inefficient and can be optimized.Apply this diff to memoize the calculation:
+import { useEffect, useMemo } from "react"; -import { useEffect } from "react";const { isPaidUser, isLoading: isSubscriptionLoading } = useSubscription(); - const { grouped, sortedKeys } = getNewslettersByDate(); + const { grouped, sortedKeys } = useMemo(() => getNewslettersByDate(), []);apps/web/src/lib/auth/config.ts (1)
31-38: Consider improving the dummy provider documentation.The fallback dummy provider is a creative solution for test mode, but the comment could be more explicit about when and why this is used (i.e., for
NEXT_PUBLIC_ENABLE_TEST_MODE).Apply this diff to improve the comment:
- providers: providers.length > 0 ? providers : [ - // fallback: create a dummy provider to prevent NextAuth errors - // this won't work for actual auth but allows the server to start + providers: providers.length > 0 ? providers : [ + // Fallback dummy provider for test mode (NEXT_PUBLIC_ENABLE_TEST_MODE=true) + // This prevents NextAuth initialization errors when no real OAuth providers are configured + // Authentication will be bypassed in pages that check for test mode GoogleProvider({ clientId: "dummy", clientSecret: "dummy", }), ],
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
NEXT_STEPS.md(1 hunks)QUICK_START.md(1 hunks)RUN_AND_PUSH_GUIDE.md(1 hunks)SETUP_INSTRUCTIONS.md(1 hunks)TESTING_MODE.md(1 hunks)TROUBLESHOOTING.md(1 hunks)apps/api/src/clients/razorpay.ts(1 hunks)apps/api/src/index.ts(3 hunks)apps/api/src/prisma.ts(1 hunks)apps/web/NEWSLETTER_DOCUMENTATION.md(1 hunks)apps/web/PR_DESCRIPTION.md(1 hunks)apps/web/src/app/(main)/newsletters/[id]/page.tsx(1 hunks)apps/web/src/app/(main)/newsletters/page.tsx(1 hunks)apps/web/src/components/dashboard/Sidebar.tsx(2 hunks)apps/web/src/components/newsletters/NewsletterCard.tsx(1 hunks)apps/web/src/components/newsletters/NewsletterContent.tsx(1 hunks)apps/web/src/components/newsletters/NewsletterHeader.tsx(1 hunks)apps/web/src/data/newsletters.ts(1 hunks)apps/web/src/lib/auth/config.ts(2 hunks)apps/web/src/middleware.ts(2 hunks)start-dev.bat(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
apps/web/src/components/newsletters/NewsletterHeader.tsx (1)
apps/web/src/components/blogs/BlogHeader.tsx (1)
BlogHeader(5-24)
apps/web/src/components/newsletters/NewsletterContent.tsx (1)
apps/web/src/data/newsletters.ts (1)
NewsletterContent(4-10)
apps/web/src/app/(main)/newsletters/page.tsx (4)
apps/web/src/hooks/useSubscription.ts (1)
useSubscription(11-75)apps/web/src/data/newsletters.ts (2)
getNewslettersByDate(260-292)newsletters(19-257)apps/web/src/components/newsletters/NewsletterHeader.tsx (1)
NewsletterHeader(5-32)apps/web/src/components/newsletters/NewsletterCard.tsx (1)
NewsletterCard(10-43)
apps/web/src/data/newsletters.ts (1)
apps/web/src/components/newsletters/NewsletterContent.tsx (1)
NewsletterContent(9-110)
apps/web/src/app/(main)/newsletters/[id]/page.tsx (4)
apps/web/src/hooks/useSubscription.ts (1)
useSubscription(11-75)apps/web/src/data/newsletters.ts (2)
getNewsletterById(295-297)NewsletterContent(4-10)apps/web/src/components/newsletters/NewsletterHeader.tsx (1)
NewsletterHeader(5-32)apps/web/src/components/newsletters/NewsletterContent.tsx (1)
NewsletterContent(9-110)
apps/web/src/components/newsletters/NewsletterCard.tsx (1)
apps/web/src/data/newsletters.ts (1)
Newsletter(12-17)
🪛 Biome (2.1.2)
apps/web/src/components/newsletters/NewsletterContent.tsx
[error] 61-61: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🪛 Gitleaks (8.29.0)
QUICK_START.md
[high] 11-11: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 27-27: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 LanguageTool
TROUBLESHOOTING.md
[style] ~5-~5: Consider an alternative verb to strengthen your wording.
Context: ...g guide ## prisma client error if you see this error: ``` Error: @prisma/client d...
(IF_YOU_HAVE_THIS_PROBLEM)
SETUP_INSTRUCTIONS.md
[uncategorized] ~53-~53: The name of this company should be capitalized.
Context: ...tter page, you can use dummy values for google oauth (the page will still load) - gene...
(GOOGLE_PRODUCTS)
QUICK_START.md
[style] ~58-~58: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...ing without full authentication if you want to see the newsletter page ui without sett...
(REP_WANT_TO_VB)
🪛 markdownlint-cli2 (0.18.1)
RUN_AND_PUSH_GUIDE.md
148-148: Bare URL used
(MD034, no-bare-urls)
170-170: Bare URL used
(MD034, no-bare-urls)
NEXT_STEPS.md
14-14: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
117-117: Bare URL used
(MD034, no-bare-urls)
132-132: Bare URL used
(MD034, no-bare-urls)
apps/web/PR_DESCRIPTION.md
36-36: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (9)
apps/api/src/index.ts (2)
20-20: LGTM! Helpful startup logging.The startup log provides clear feedback during server initialization and aligns well with the enhanced logging at lines 280-281.
253-256: Database connection error handling is already in place.The endpoints that use
prismaModule.prismaare wrapped in outer try-catch blocks that gracefully handle connection failures by returning 500 responses:
/join-community(line 100): Outer try-catch at lines 101 and 148 catches any errors from the prisma query at line 121/webhook/razorpay(line 155): Outer try-catch at lines 156 and 250+ catches errors from payment service callsConnection failures will be caught and return
{ error: "Internal server error" }rather than crashing. The existing error handling adequately addresses the concern.Likely an incorrect or invalid review comment.
SETUP_INSTRUCTIONS.md (1)
1-124: LGTM! Clear and comprehensive setup documentation.The setup instructions are well-structured, cover all necessary steps, and appropriately note that the newsletter UI can be tested without full database setup. The troubleshooting section addresses common issues effectively.
apps/web/PR_DESCRIPTION.md (1)
1-101: LGTM! Comprehensive PR documentation.The PR description thoroughly documents the newsletter feature implementation, including architecture, features, file structure, and testing instructions. This will help reviewers understand the scope and design decisions.
TROUBLESHOOTING.md (1)
1-47: LGTM! Clear and actionable troubleshooting guide.The troubleshooting guide covers common setup issues with specific solutions. The note that newsletter UI testing doesn't require a database is particularly helpful for developers who want to quickly test the frontend.
apps/web/NEWSLETTER_DOCUMENTATION.md (1)
1-192: LGTM! Excellent content management documentation.This documentation provides clear, comprehensive instructions for adding newsletters with well-structured examples and type definitions. The content guidelines and testing checklist ensure consistent quality across newsletters.
RUN_AND_PUSH_GUIDE.md (1)
1-222: LGTM! Comprehensive workflow guide.This guide provides clear, detailed instructions for both running the application locally and contributing changes via pull requests. The quick commands summary and troubleshooting section are particularly helpful.
start-dev.bat (1)
4-8: Path navigation is correct and verified.The script output confirms both
apps/api/andapps/web/exist in the repository. The relative pathcd ..\apifromapps\webcorrectly navigates toapps\api. The directory structure matches the batch script's assumptions.apps/web/src/app/(main)/newsletters/[id]/page.tsx (1)
23-66: Auth guard flow is dialed in. Clear separation between test mode, loading, and redirect paths keeps the detail view from flashing sensitive content. Nicely done.
| case "link": | ||
| return ( | ||
| <a | ||
| key={idx} | ||
| href={item.href} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="text-[#9455f4] hover:text-white underline transition-colors" | ||
| > | ||
| {item.content} | ||
| </a> | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate link href to prevent XSS.
The href attribute is used directly from item.href without validation. Malicious content could include javascript: or data: URLs, leading to XSS vulnerabilities.
Apply this diff to add href validation:
case "link":
+ // Only allow http/https URLs
+ const isValidHref = item.href && /^https?:\/\//i.test(item.href);
return (
<a
key={idx}
- href={item.href}
+ href={isValidHref ? item.href : "#"}
target="_blank"
rel="noopener noreferrer"
className="text-[#9455f4] hover:text-white underline transition-colors"
>
{item.content}
</a>
);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case "link": | |
| return ( | |
| <a | |
| key={idx} | |
| href={item.href} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-[#9455f4] hover:text-white underline transition-colors" | |
| > | |
| {item.content} | |
| </a> | |
| ); | |
| case "link": | |
| // Only allow http/https URLs | |
| const isValidHref = item.href && /^https?:\/\//i.test(item.href); | |
| return ( | |
| <a | |
| key={idx} | |
| href={isValidHref ? item.href : "#"} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-[#9455f4] hover:text-white underline transition-colors" | |
| > | |
| {item.content} | |
| </a> | |
| ); |
🤖 Prompt for AI Agents
In apps/web/src/components/newsletters/NewsletterContent.tsx around lines 33 to
44, the link branch uses item.href directly which allows dangerous schemes like
javascript: or data:; update the rendering to validate and sanitize href before
use: only allow safe values (absolute http/https, mailto:, tel:) or safe
relative URLs (starting with '/'), and otherwise do not render the anchor (or
render a non-navigating fallback like plain text or href="#" with no-op) —
implement a small helper that returns a validatedHref or null (rejecting unsafe
schemes such as javascript:, data:, vbscript:), and use that validatedHref in
the href prop (skip rendering if null) so XSS via href is prevented.
| <img | ||
| src={item.content} | ||
| alt={item.alt || ""} | ||
| className="rounded-lg w-full h-auto" | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate image src to prevent potential security issues.
The src attribute uses item.content directly without validation. While modern browsers don't execute javascript: in img src, data: URLs or other unexpected content could still pose security or display issues.
Apply this diff to add src validation:
+ // Only allow http/https image URLs
+ const isValidSrc = /^https?:\/\//i.test(item.content);
+ if (!isValidSrc) {
+ return null;
+ }
<img
src={item.content}
alt={item.alt || ""}
className="rounded-lg w-full h-auto"
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <img | |
| src={item.content} | |
| alt={item.alt || ""} | |
| className="rounded-lg w-full h-auto" | |
| /> | |
| {isValidImageSrc(item.content) ? ( | |
| <img | |
| src={item.content} | |
| alt={item.alt || ""} | |
| className="rounded-lg w-full h-auto" | |
| /> | |
| ) : null} |
| pages: { | ||
| signIn: "/login", | ||
| }, | ||
| secret: process.env.NEXTAUTH_SECRET || "development-secret-change-in-production", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strengthen the secret configuration.
The fallback secret "development-secret-change-in-production" is insecure even for development. If NEXTAUTH_SECRET is not set, session tokens and CSRF protection will be weak, potentially allowing session hijacking.
Consider one of these approaches:
Option 1: Require NEXTAUTH_SECRET (recommended)
- secret: process.env.NEXTAUTH_SECRET || "development-secret-change-in-production",
+ secret: process.env.NEXTAUTH_SECRET!,Then document in README that NEXTAUTH_SECRET is required.
Option 2: Generate a random secret for development
- secret: process.env.NEXTAUTH_SECRET || "development-secret-change-in-production",
+ secret: process.env.NEXTAUTH_SECRET || (
+ process.env.NODE_ENV === "development"
+ ? require("crypto").randomBytes(32).toString("hex")
+ : (() => { throw new Error("NEXTAUTH_SECRET is required in production") })()
+ ),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| secret: process.env.NEXTAUTH_SECRET || "development-secret-change-in-production", | |
| secret: process.env.NEXTAUTH_SECRET!, |
🤖 Prompt for AI Agents
In apps/web/src/lib/auth/config.ts around line 88, the code falls back to an
insecure hardcoded secret; replace this by requiring NEXTAUTH_SECRET in
production (throw or assert if NODE_ENV === 'production' and env var missing)
and for local/dev either generate and persist a strong random secret at startup
or derive one safely (e.g., crypto.randomBytes) while documenting the
requirement in README; update the config to pull from
process.env.NEXTAUTH_SECRET only and implement the environment check/throw or
dev-generation logic accordingly.
| if (!process.env.NEXTAUTH_SECRET || process.env.NEXT_PUBLIC_ENABLE_TEST_MODE === "true") { | ||
| return NextResponse.next(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not fail open when NEXTAUTH_SECRET is missing
Line 6 turns off authentication whenever the secret isn’t set. In production a misconfigured secret becomes a full bypass for every protected path, leaking /dashboard and /newsletters to the public. We must fail closed: only allow the bypass for explicit test mode, and keep throwing/blocking when the secret is absent.
Apply this diff to enforce that behavior:
- // skip auth check if NEXTAUTH_SECRET is not configured or test mode is enabled
- if (!process.env.NEXTAUTH_SECRET || process.env.NEXT_PUBLIC_ENABLE_TEST_MODE === "true") {
- return NextResponse.next();
- }
+ const isTestMode = process.env.NEXT_PUBLIC_ENABLE_TEST_MODE === "true";
+ if (isTestMode) {
+ return NextResponse.next();
+ }
+
+ const secret = process.env.NEXTAUTH_SECRET;
+ if (!secret) {
+ return new NextResponse(
+ "NEXTAUTH_SECRET is not configured. Authentication checks cannot proceed.",
+ { status: 500 }
+ );
+ }Then pass secret into getToken as before.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!process.env.NEXTAUTH_SECRET || process.env.NEXT_PUBLIC_ENABLE_TEST_MODE === "true") { | |
| return NextResponse.next(); | |
| } | |
| const isTestMode = process.env.NEXT_PUBLIC_ENABLE_TEST_MODE === "true"; | |
| if (isTestMode) { | |
| return NextResponse.next(); | |
| } | |
| const secret = process.env.NEXTAUTH_SECRET; | |
| if (!secret) { | |
| return new NextResponse( | |
| "NEXTAUTH_SECRET is not configured. Authentication checks cannot proceed.", | |
| { status: 500 } | |
| ); | |
| } |
🤖 Prompt for AI Agents
In apps/web/src/middleware.ts around lines 6 to 8, the current code bypasses
auth whenever NEXTAUTH_SECRET is missing which fails open; change the logic so
you only bypass when NEXT_PUBLIC_ENABLE_TEST_MODE === "true", and otherwise fail
closed by throwing or returning an error/redirect if NEXTAUTH_SECRET is absent.
Concretely: first check if test mode is enabled and return NextResponse.next()
only in that case; then if NEXTAUTH_SECRET is undefined throw a clear error (or
return a blocking response) instead of proceeding; finally, when calling
getToken pass { req, secret: process.env.NEXTAUTH_SECRET } as before.
| JWT_SECRET="3bb3238092da53f8ba9d1e02e15efe8ec84341252a11eff1b28ff742c292224e" | ||
| PORT=8080 | ||
| CORS_ORIGINS=http://localhost:3000 | ||
| NODE_ENV=development | ||
| ``` | ||
|
|
||
| **update:** replace `USER` and `PASSWORD` with your postgresql credentials, or use a dummy value if you don't have postgresql yet. | ||
|
|
||
| ### frontend (`apps/web/.env.local`) | ||
|
|
||
| create the file `apps/web/.env.local` with this content: | ||
|
|
||
| ```env | ||
| NEXT_PUBLIC_API_URL="http://localhost:8080" | ||
| GOOGLE_CLIENT_ID="dummy-client-id" | ||
| GOOGLE_CLIENT_SECRET="dummy-secret" | ||
| NEXTAUTH_SECRET="3bb3238092da53f8ba9d1e02e15efe8ec84341252a11eff1b28ff742c292224e" | ||
| NEXTAUTH_URL="http://localhost:3000" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace hard-coded secrets with placeholders
The guide currently publishes concrete JWT_SECRET / NEXTAUTH_SECRET values. Even if they’re meant to be dummy, committing fixed secrets encourages copy‑pasting them into real deployments and trips secret scanners. Please switch to clearly marked placeholders and ask readers to supply their own values.
Use a diff like this:
-JWT_SECRET="3bb3238092da53f8ba9d1e02e15efe8ec84341252a11eff1b28ff742c292224e"
+JWT_SECRET="<set-your-own-jwt-secret>"
...
-NEXTAUTH_SECRET="3bb3238092da53f8ba9d1e02e15efe8ec84341252a11eff1b28ff742c292224e"
+NEXTAUTH_SECRET="<set-your-own-nextauth-secret>"Optionally add a note explaining how to generate secure secrets.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| JWT_SECRET="3bb3238092da53f8ba9d1e02e15efe8ec84341252a11eff1b28ff742c292224e" | |
| PORT=8080 | |
| CORS_ORIGINS=http://localhost:3000 | |
| NODE_ENV=development | |
| ``` | |
| **update:** replace `USER` and `PASSWORD` with your postgresql credentials, or use a dummy value if you don't have postgresql yet. | |
| ### frontend (`apps/web/.env.local`) | |
| create the file `apps/web/.env.local` with this content: | |
| ```env | |
| NEXT_PUBLIC_API_URL="http://localhost:8080" | |
| GOOGLE_CLIENT_ID="dummy-client-id" | |
| GOOGLE_CLIENT_SECRET="dummy-secret" | |
| NEXTAUTH_SECRET="3bb3238092da53f8ba9d1e02e15efe8ec84341252a11eff1b28ff742c292224e" | |
| NEXTAUTH_URL="http://localhost:3000" | |
| JWT_SECRET="<set-your-own-jwt-secret>" | |
| PORT=8080 | |
| CORS_ORIGINS=http://localhost:3000 | |
| NODE_ENV=development |
🧰 Tools
🪛 Gitleaks (8.29.0)
[high] 11-11: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 27-27: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🤖 Prompt for AI Agents
In QUICK_START.md around lines 11 to 28, replace the hard-coded JWT_SECRET and
NEXTAUTH_SECRET values in the environment examples with clearly marked
placeholders (e.g. JWT_SECRET="<YOUR_JWT_SECRET>" and
NEXTAUTH_SECRET="<YOUR_NEXTAUTH_SECRET>") and remove any concrete secret strings
from the file; update the frontend env example similarly (NEXTAUTH_SECRET
placeholder) and add a one-line note telling users how to generate secure
secrets (for example using openssl rand -hex 32 or a secrets manager) so readers
supply their own values rather than copying committed secrets.
this pr implements a newsletter page for pro users on opensox.ai. the newsletter page displays newsletters as blog posts with rich content support, organized by date (month and year).
core features:
pro user protection:
sample data:
documentation:
technical implementation:
files added:
files modified:
implements bounty requirements for newsletter page feature.
Summary by CodeRabbit
New Features
Documentation
Bug Fixes
Chores