Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 9 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
---
name: Bug Report 🐛
about: Create a report to help us improve and fix bugs in Frontend Junction.
title: "[BUG] "
title: '[BUG] '
labels: bug, triage
assignees: ""
assignees: ''
---

## Description

<!-- A clear and concise description of what the bug is. -->

## Steps to Reproduce

<!-- Steps to reproduce the behavior: -->

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

## Expected Behavior

<!-- A clear and concise description of what you expected to happen. -->

## Screenshots / Screen Recordings

<!-- If applicable, add screenshots or recordings to help explain your problem. -->

## Environment Details

- **Browser**: [e.g. Chrome, Safari, Firefox]
- **OS**: [e.g. macOS, Windows, iOS, Android]
- **Device (if mobile)**: [e.g. iPhone 15, Pixel 8]

## Additional Context

<!-- Add any other context about the problem here (e.g., console logs, stack traces). -->
8 changes: 6 additions & 2 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
---
name: Feature Request ✨
about: Suggest a new idea or enhancement for Frontend Junction.
title: "[FEATURE] "
title: '[FEATURE] '
labels: enhancement, triage
assignees: ""
assignees: ''
---

## Is your feature request related to a problem?

<!-- A clear and concise description of what the problem is. E.g. I'm always frustrated when [...] -->

## Proposed Solution

<!-- A clear and concise description of what you want to happen. -->

## Alternative Solutions Considered

<!-- A clear and concise description of any alternative solutions or features you've considered. -->

## Additional Context

<!-- Add any other context, mockups, or screenshots about the feature request here. -->
5 changes: 5 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
## Description

<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. -->

Fixes # (issue)

## Type of Change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update (non-breaking change to docs/README)
- [ ] Code style / formatting / refactoring (non-breaking change)

## How Has This Been Tested?

<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. -->

- [ ] Local dev server build and runtime test (`npm run dev`)
Expand All @@ -19,9 +22,11 @@ Fixes # (issue)
- [ ] TypeScript type checks passed (`npm run check-types`)

## Screenshots / GIFs (if applicable)

<!-- Add screenshots or screen recordings showing the UI changes on both Desktop and Mobile viewports. -->

## Checklist

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ npm run dev
5. Submit the PR against `main`

Our CI pipeline runs automatically:

- ESLint + TypeScript type checking
- Security audit
- Production build
Expand Down
64 changes: 32 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,18 @@ Frontend developers preparing for interviews often rely on scattered LinkedIn po

## Tech Stack

| Layer | Technology |
|-------|-----------|
| **Framework** | Next.js 15 (App Router, Server Actions, ISR) |
| **Language** | TypeScript |
| **Database** | Supabase (PostgreSQL + Auth + Storage) |
| **Styling** | Tailwind CSS + Radix UI primitives |
| **Animations** | Framer Motion |
| **Content** | MDX via Velite |
| **AI** | Google Gemini (content processing pipeline) |
| **CI/CD** | GitHub Actions (lint, type check, security audit, bundle size, Lighthouse) |
| **Auth** | Supabase SSR Auth with middleware |
| **Deployment** | Vercel |
| Layer | Technology |
| -------------- | -------------------------------------------------------------------------- |
| **Framework** | Next.js 15 (App Router, Server Actions, ISR) |
| **Language** | TypeScript |
| **Database** | Supabase (PostgreSQL + Auth + Storage) |
| **Styling** | Tailwind CSS + Radix UI primitives |
| **Animations** | Framer Motion |
| **Content** | MDX via Velite |
| **AI** | Google Gemini (content processing pipeline) |
| **CI/CD** | GitHub Actions (lint, type check, security audit, bundle size, Lighthouse) |
| **Auth** | Supabase SSR Auth with middleware |
| **Deployment** | Vercel |

## Getting Started

Expand Down Expand Up @@ -104,19 +104,19 @@ Admin role is read from Supabase `app_metadata` — there are no hardcoded admin

### Environment Variables

| Variable | Description |
|----------|-------------|
| `NEXT_PUBLIC_SUPABASE_URL` | Your Supabase project URL |
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase anonymous/public key |
| `SUPABASE_SERVICE_ROLE_KEY` | Server-only Supabase key for admin routes, data pipelines, and sitemap generation |
| `GEMINI_API_KEY` | Server-only Google Gemini API key for the content pipeline |
| `CRON_SECRET` | Server-only bearer token that authorizes the protected pipeline and seed API routes |
| `GOOGLE_SITE_VERIFICATION` | Optional Google Search Console verification token exposed in the page metadata |
| `NEXT_GOOGLE_ANALYTICS` | Optional Google Analytics measurement ID used to load the site tag |
| `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | Optional public Cloudflare Turnstile site key used by bot-protected forms |
| `TURNSTILE_SECRET_KEY` | Optional server-only Cloudflare Turnstile secret used to verify bot-protected form submissions |
| `NEXT_PUBLIC_IS_DEV` | Optional non-production flag that relaxes cron protection for local pipeline testing |
| `NEXT_PUBLIC_LOGO_DEV_KEY` | Optional public Logo.dev token for company logos; the app falls back to a bundled demo key when unset |
| Variable | Description |
| -------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_SUPABASE_URL` | Your Supabase project URL |
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase anonymous/public key |
| `SUPABASE_SERVICE_ROLE_KEY` | Server-only Supabase key for admin routes, data pipelines, and sitemap generation |
| `GEMINI_API_KEY` | Server-only Google Gemini API key for the content pipeline |
| `CRON_SECRET` | Server-only bearer token that authorizes the protected pipeline and seed API routes |
| `GOOGLE_SITE_VERIFICATION` | Optional Google Search Console verification token exposed in the page metadata |
| `NEXT_GOOGLE_ANALYTICS` | Optional Google Analytics measurement ID used to load the site tag |
| `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | Optional public Cloudflare Turnstile site key used by bot-protected forms |
| `TURNSTILE_SECRET_KEY` | Optional server-only Cloudflare Turnstile secret used to verify bot-protected form submissions |
| `NEXT_PUBLIC_IS_DEV` | Optional non-production flag that relaxes cron protection for local pipeline testing |
| `NEXT_PUBLIC_LOGO_DEV_KEY` | Optional public Logo.dev token for company logos; the app falls back to a bundled demo key when unset |

### Scripts

Expand Down Expand Up @@ -173,13 +173,13 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.

## Stats

| Metric | Count |
|--------|-------|
| Interview Experiences | 106+ |
| Blog Posts | 23 |
| Companies Covered | 103 |
| Pull Requests | 91+ |
| Commits | 127+ |
| Metric | Count |
| --------------------- | ----- |
| Interview Experiences | 106+ |
| Blog Posts | 23 |
| Companies Covered | 103 |
| Pull Requests | 91+ |
| Commits | 127+ |

## License

Expand Down
5 changes: 4 additions & 1 deletion app/api/admin/stats/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ export async function GET() {
});
} catch (error: any) {
if (error instanceof AuthError) {
return NextResponse.json({ error: error.message }, { status: error.status });
return NextResponse.json(
{ error: error.message },
{ status: error.status }
);
}
console.error('[AdminStatsAPI] Error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
Expand Down
6 changes: 2 additions & 4 deletions app/api/interview/view/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const cookieStore = await cookies();
const [{ id }, cookieStore] = await Promise.all([params, cookies()]);
const supabase = createServerClient(
supabaseUrl,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
Expand Down Expand Up @@ -45,8 +44,7 @@ export async function POST(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const cookieStore = await cookies();
const [{ id }, cookieStore] = await Promise.all([params, cookies()]);
const supabase = createServerClient(
supabaseUrl,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
Expand Down
6 changes: 3 additions & 3 deletions app/api/og/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export async function GET(req: NextRequest) {
viewBox='0 0 24 24'
fill='none'
stroke='currentColor'
stroke-width='2'
stroke-linecap='round'
stroke-linejoin='round'
strokeWidth='2'
strokeLinecap='round'
strokeLinejoin='round'
>
<path d='M4 11a9 9 0 0 1 9 9' />
<path d='M4 4a16 16 0 0 1 16 16' />
Expand Down
9 changes: 8 additions & 1 deletion app/api/pipeline/process/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ async function fetchMediumContent(url: string) {
}

export async function GET(request: Request) {
return POST(request);
}

export async function POST(request: Request) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Changing this handler to POST breaks existing GET-based integrations (common for cron/scheduler triggers), causing those callers to receive method errors and stop processing. Keep backward compatibility by retaining a GET handler (or adding one that delegates to POST) if existing jobs still call this endpoint via GET. [api mismatch]

Severity Level: Major ⚠️
- ❌ GET requests to /api/pipeline/process no longer work.
- ⚠️ Existing GET-based cron jobs stop triggering pipeline.
Steps of Reproduction ✅
1. Run the Next.js app with the current PR code; verify in
`app/api/pipeline/process/route.ts` that only a POST handler exists (lines 39–225) and
there is no exported GET function (confirmed via BulkRead of this file).

2. Send an HTTP GET request to the `/api/pipeline/process` endpoint with a valid key query
parameter (App Router maps `app/api/pipeline/process/route.ts` to `/api/pipeline/process`
and the security check at lines 40–47 expects `key` in the URL).

3. Next.js attempts to dispatch the GET request but, because no `export async function
GET` exists in `app/api/pipeline/process/route.ts`, the framework responds with a
405-style method error and the processing logic at lines 58–221 is never executed.

4. Any existing external cron or scheduler configuration that previously triggered this
endpoint using GET (typical for HTTP cron jobs on function URLs) will now consistently
receive method errors instead of running the pipeline, effectively stopping scheduled
processing until those jobs are updated to use POST.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** app/api/pipeline/process/route.ts
**Line:** 39:39
**Comment:**
	*Api Mismatch: Changing this handler to POST breaks existing GET-based integrations (common for cron/scheduler triggers), causing those callers to receive method errors and stop processing. Keep backward compatibility by retaining a GET handler (or adding one that delegates to POST) if existing jobs still call this endpoint via GET.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines 39 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep this write path POST-only.

Line 40 makes a GET request execute the full processing pipeline and write back to the database. That breaks HTTP safety and makes accidental crawls, previews, or prefetches capable of triggering mutations.

Proposed fix
 export async function GET(request: Request) {
-  return POST(request);
+  return NextResponse.json({ error: 'Method not allowed' }, { status: 405 });
 }
📝 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.

Suggested change
export async function GET(request: Request) {
return POST(request);
}
export async function POST(request: Request) {
export async function GET(request: Request) {
return NextResponse.json({ error: 'Method not allowed' }, { status: 405 });
}
export async function POST(request: Request) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/api/pipeline/process/route.ts` around lines 39 - 43, The GET handler in
GET should not delegate to POST because it causes the full processing pipeline
to run and mutate state on safe requests. Remove the GET-to-POST passthrough in
this route and keep the write path exposed only through POST, leaving GET
unimplemented or returning a method-not-allowed response so accidental crawls or
prefetches cannot trigger processing.

// Security Check
const { searchParams } = new URL(request.url);
const key = searchParams.get('key');
Expand Down Expand Up @@ -66,7 +70,7 @@ export async function GET(request: Request) {
);
}

const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });
const results = { scraped: 0, user: 0, legacy: 0, errors: [] as string[] };
const BATCH_SIZE = 200;

Expand All @@ -87,6 +91,7 @@ export async function GET(request: Request) {
}

if (scrapedData && scrapedData.length > 0) {
// Sequential processing: AI model calls must be serialized to avoid rate limits
for (const item of scrapedData) {
try {
let content = item.metadata?.content || item.summary || '';
Expand Down Expand Up @@ -141,6 +146,7 @@ export async function GET(request: Request) {
.limit(BATCH_SIZE);

if (userData && userData.length > 0) {
// Sequential processing: each item requires AI model call, processed one at a time to avoid rate limits
for (const item of userData) {
try {
const content = item.description || '';
Expand Down Expand Up @@ -186,6 +192,7 @@ export async function GET(request: Request) {
}

if (legacyData && legacyData.length > 0) {
// Sequential processing: each item requires AI model call, processed one at a time to avoid rate limits
for (const item of legacyData) {
try {
const content = item.detail_experience || item.summary || '';
Expand Down
Loading
Loading