diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1f8b9c1 --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +DECODO_API_KEY= +INSFORGE_API_KEY= +INSFORGE_URL=https://YOUR_REF.YOUR_REGION.insforge.app + +# Optional - Customize Insforge configuration +# INSFORGE_MODEL=openai/gpt-4o-mini +# INSFORGE_RESULTS_TABLE=validated_saas_ideas + +# Optional - Customize Decodo scraping behavior +# DECODO_PROXY_POOL=residential +# DECODO_HEADLESS_MODE=true +# DECODO_TIMEOUT_MS=30000 +# INSFORGE_TIMEOUT_MS=60000 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9c7be43 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +on: + push: + pull_request: + +jobs: + lint-and-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + + - run: npm ci + + - run: npm run lint + + - run: npm run build + env: + NEXT_TELEMETRY_DISABLED: 1 diff --git a/.gitignore b/.gitignore index e8eb7fb..f3bc09a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ /build # misc +.vscode +.idea .DS_Store *.pem @@ -32,6 +34,7 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +!.env.example # vercel .vercel @@ -39,5 +42,3 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts - -.env.local diff --git a/.vscode/mcp.json b/.vscode/mcp.json deleted file mode 100644 index 5fcbc46..0000000 --- a/.vscode/mcp.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "servers": { - "mcp": { - "type": "stdio", - "command": "npx", - "args": ["-y", "@insforge/mcp@latest"], - "env": { - "API_KEY": "your_api_key_here", - "API_BASE_URL": "https://uk39hjmz.us-east.insforge.app" - } - } - }, - "inputs": [] -} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d3f6e25..b08e45b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,10 +4,10 @@ Thank you for your interest in contributing to Validly! This document provides g ## Getting Started -1. Fork the repository on GitHub +1. Fork [Nova-Designs-Creative/validly](https://github.com/Nova-Designs-Creative/validly) on GitHub 2. Clone your fork locally: ```bash - git clone https://github.com/yourusername/validly.git + git clone https://github.com//validly.git cd validly ``` 3. Install dependencies: diff --git a/README.md b/README.md index 22f27d1..5cda582 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ Validly is a Next.js application that scrapes weekly Reddit discussions from any - Node.js 20+ installed - A [Decodo](https://visit.decodo.com/oNza7b) API key (for Reddit scraping) -- An [Insforge](https://insforge.dev) API key (for AI analysis) +- An [Insforge](https://insforge.dev) project backend URL (`*.insforge.app`) and API key (for AI analysis) ## 🛠️ Installation 1. **Clone the repository** ```bash - git clone https://github.com/yourusername/validly.git + git clone https://github.com/Nova-Designs-Creative/validly.git cd validly ``` @@ -44,25 +44,13 @@ Validly is a Next.js application that scrapes weekly Reddit discussions from any ``` 3. **Set up environment variables** - - Create a `.env.local` file in the root directory: + ```bash - # Required - DECODO_API_KEY=your_decodo_api_key_here - INSFORGE_API_KEY=your_insforge_api_key_here - - # Optional - Customize Insforge configuration - INSFORGE_URL=https://api.insforge.dev - INSFORGE_MODEL=openai/gpt-4o-mini - INSFORGE_RESULTS_TABLE=validated_saas_ideas - - # Optional - Customize Decodo scraping behavior - DECODO_PROXY_POOL=residential - DECODO_HEADLESS_MODE=true - DECODO_TIMEOUT_MS=30000 - INSFORGE_TIMEOUT_MS=60000 + cp .env.example .env.local ``` + Fill in the required keys in `.env.local`. Optional variables and defaults are documented in [.env.example](.env.example). + 4. **Run the development server** ```bash npm run dev @@ -80,11 +68,11 @@ Validly is a Next.js application that scrapes weekly Reddit discussions from any 3. Navigate to your dashboard 4. Copy your API key -### Insforge API Key +### Insforge API key and backend URL 1. Visit [insforge.dev](https://insforge.dev) -2. Create an account -3. Go to your project settings -4. Generate and copy your API key +2. Create an account and open your project +3. Copy the backend/API base URL (format `https://..insforge.app`) into `INSFORGE_URL` +4. Generate and copy your API key into `INSFORGE_API_KEY` ## 📁 Project Structure @@ -103,7 +91,8 @@ validly/ │ ├── reddit.ts # Reddit scraping & parsing │ └── types.ts # TypeScript type definitions ├── public/ # Static assets -├── .env.local # Environment variables (create this) +├── .env.example # Environment variable template +├── .env.local # Local secrets (from .env.example) ├── next.config.ts # Next.js configuration ├── package.json # Dependencies └── tsconfig.json # TypeScript configuration @@ -115,38 +104,57 @@ validly/ Analyzes a subreddit for SaaS opportunities. -**Request Body:** +**Request body:** + ```json { "subreddit": "saas" } ``` -**Response:** +**Success response** (`200`): shape matches `AnalyzeIdeasResponse` in [lib/types.ts](lib/types.ts) — `subreddit`, `source` (scraped posts and comments), and `ideas` (AI-extracted SaaS ideas). + ```json { + "subreddit": "saas", + "source": { + "subreddit": "saas", + "scrapedAt": "2026-04-13T00:00:00.000Z", + "posts": [ + { + "title": "Example post title", + "comments": ["Comment excerpt", "Another excerpt"], + "permalink": "/r/saas/comments/abc123/example/", + "threadUrl": "https://www.reddit.com/r/saas/comments/abc123/example/" + } + ] + }, "ideas": [ { - "title": "AI-Powered Email Automation for SMBs", - "description": "...", - "target_customers": ["Small businesses", "Marketing agencies"], - "estimated_pricing": "$29-99/month", - "market_score": 8, - "urgency_score": 7, - "competitors": ["Mailchimp", "ActiveCampaign"], - "source_threads": [ - { - "title": "Struggling with email automation...", - "thread_url": "https://reddit.com/r/saas/..." - } - ] + "idea_name": "Example idea", + "problem": "...", + "demand_level": "High", + "existing_solutions": ["..."], + "similar_competitors": ["..."], + "user_complaints": ["..."], + "opportunity": "...", + "monetization_model": "...", + "pricing_hint": "...", + "revenue_potential": "...", + "go_to_market": "...", + "score": 8, + "verdict": "Strong", + "source_threads": [{ "title": "...", "thread_url": "https://reddit.com/..." }] } - ], - "posts": [...], - "metadata": { - "subreddit": "saas", - "analyzedAt": "2026-05-02T..." - } + ] +} +``` + +**Error response** (`400` for invalid body, `500` otherwise): + +```json +{ + "error": "Human-readable message" } ``` @@ -160,20 +168,6 @@ Analyzes a subreddit for SaaS opportunities. - **Validation:** Zod - **JSON Repair:** jsonrepair -## 🎨 Environment Variables Reference - -| Variable | Required | Default | Description | -|----------|----------|---------|-------------| -| `DECODO_API_KEY` | ✅ Yes | - | Your Decodo API key for Reddit scraping | -| `INSFORGE_API_KEY` | ✅ Yes | - | Your Insforge API key for AI analysis | -| `INSFORGE_URL` | ❌ No | `https://api.insforge.dev` | Insforge API base URL | -| `INSFORGE_MODEL` | ❌ No | `openai/gpt-4o-mini` | AI model to use | -| `INSFORGE_RESULTS_TABLE` | ❌ No | - | Optional database table name | -| `DECODO_PROXY_POOL` | ❌ No | `residential` | Proxy pool type for scraping | -| `DECODO_HEADLESS_MODE` | ❌ No | `true` | Headless browser mode | -| `DECODO_TIMEOUT_MS` | ❌ No | `30000` | Scraping timeout in milliseconds | -| `INSFORGE_TIMEOUT_MS` | ❌ No | `60000` | AI analysis timeout in milliseconds | - ## 📝 Available Scripts ```bash @@ -203,53 +197,10 @@ This project is open source and available under the [MIT License](LICENSE). - [Insforge](https://insforge.dev) for AI infrastructure - [Next.js](https://nextjs.org) team for the amazing framework ---- - -**Built with ❤️ using Next.js, TypeScript, and AI** - -`POST /api/analyze` - -Request body: - -```json -{ - "subreddit": "saas" -} -``` - -Response shape: - -```json -{ - "subreddit": "saas", - "source": { - "subreddit": "saas", - "scrapedAt": "2026-04-13T00:00:00.000Z", - "posts": [ - { - "title": "...", - "comments": ["...", "..."], - "permalink": "/r/saas/comments/..." - } - ] - }, - "ideas": [ - { - "idea_name": "...", - "problem": "...", - "demand_level": "High", - "existing_solutions": ["..."], - "user_complaints": ["..."], - "opportunity": "...", - "score": 8, - "verdict": "Strong" - } - ] -} -``` - ## Notes - The Decodo integration is intentionally resilient and tries multiple auth and payload conventions because Decodo account setups can differ. - Optional Insforge persistence is disabled unless `INSFORGE_RESULTS_TABLE` is set and the target table already exists. - The route validates both request input and AI output before returning data to the UI. + +**Built with ❤️ using Next.js, TypeScript, and AI** diff --git a/app/page.tsx b/app/page.tsx index 2af0fa6..eb0ca05 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; -import type { AnalyzeIdeasResponse, RedditPost, SaasIdea } from "@/lib/types"; +import type { AnalyzeIdeasResponse, SaasIdea } from "@/lib/types"; const EXAMPLE_SUBREDDITS = ["saas", "smallbusiness", "freelance", "marketing"]; const LOADING_PHASES = [ @@ -150,41 +150,6 @@ function IdeaCard({ idea }: { idea: SaasIdea }) { ); } -function ThreadCard({ post }: { post: RedditPost }) { - return ( -
-
-
-

- Source Thread -

-

{post.title}

-
- - Open Thread - -
- -
- {post.comments.length > 0 ? post.comments.map((comment) => ( -
- {comment} -
- )) : ( -

- No comments were extracted for this thread, but the title still contributed to the analysis. -

- )} -
-
- ); -} - export default function Home() { const [subreddit, setSubreddit] = useState("saas"); const [lastSubreddit, setLastSubreddit] = useState("saas"); @@ -251,7 +216,7 @@ export default function Home() { return (
-
+

@@ -267,7 +232,7 @@ export default function Home() {

-
+