|
| 1 | +# CodePulse — Development Guide |
| 2 | + |
| 3 | +Developer learning retention platform using spaced repetition (SM-2), TF-IDF search, K-means clustering, and Levenshtein duplicate detection. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Stack |
| 8 | + |
| 9 | +| Layer | Technology | |
| 10 | +|-------|-----------| |
| 11 | +| Frontend | Next.js 16, TypeScript, Tailwind CSS v4, Shadcn/UI | |
| 12 | +| Auth | Clerk (Google OAuth) | |
| 13 | +| Database | Supabase (PostgreSQL) | |
| 14 | +| Algorithm API | FastAPI (Python 3.12) | |
| 15 | +| Package manager | pnpm (workspace monorepo) | |
| 16 | +| Deployment | Vercel (frontend) · Railway (API) | |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Prerequisites |
| 21 | + |
| 22 | +- Node.js 20+ |
| 23 | +- Python 3.12+ |
| 24 | +- pnpm — `npm install -g pnpm` |
| 25 | +- Supabase CLI — `brew install supabase/tap/supabase` |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## Running Locally |
| 30 | + |
| 31 | +### 1. Clone and install |
| 32 | + |
| 33 | +```bash |
| 34 | +git clone git@github.com:prithaxdev/CodePulse.git |
| 35 | +cd CodePulse |
| 36 | +pnpm install |
| 37 | +``` |
| 38 | + |
| 39 | +### 2. Set up environment variables |
| 40 | + |
| 41 | +Create `apps/web/.env.local`: |
| 42 | + |
| 43 | +```bash |
| 44 | +# Supabase — get from supabase.com → your project → Settings → API |
| 45 | +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co |
| 46 | +NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key |
| 47 | +SUPABASE_SERVICE_ROLE_KEY=your_service_role_key |
| 48 | + |
| 49 | +# Clerk — get from clerk.com → your app → API Keys |
| 50 | +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... |
| 51 | +CLERK_SECRET_KEY=sk_test_... |
| 52 | +NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in |
| 53 | +NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up |
| 54 | +NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard |
| 55 | +NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboarding |
| 56 | + |
| 57 | +# FastAPI — local dev URL |
| 58 | +NEXT_PUBLIC_API_URL=http://localhost:8000 |
| 59 | +``` |
| 60 | + |
| 61 | +Create `apps/api/.env`: |
| 62 | + |
| 63 | +```bash |
| 64 | +# Supabase (same values as above) |
| 65 | +SUPABASE_URL=https://your-project.supabase.co |
| 66 | +SUPABASE_KEY=your_service_role_key |
| 67 | + |
| 68 | +# CORS — allow local Next.js dev server |
| 69 | +CORS_ORIGINS=http://localhost:3000 |
| 70 | +``` |
| 71 | + |
| 72 | +### 3. Set up the database |
| 73 | + |
| 74 | +Link Supabase CLI to your project: |
| 75 | + |
| 76 | +```bash |
| 77 | +supabase login |
| 78 | +supabase link --project-ref your-project-ref |
| 79 | +``` |
| 80 | + |
| 81 | +Run the schema (creates users, snippets, review_logs tables): |
| 82 | + |
| 83 | +```bash |
| 84 | +supabase db query "$(cat supabase/schema.sql)" --linked |
| 85 | +``` |
| 86 | + |
| 87 | +> If `supabase/schema.sql` doesn't exist yet, copy the SQL from the Database Schema section below and paste it into the Supabase SQL editor at supabase.com. |
| 88 | +
|
| 89 | +### 4. Start the FastAPI backend |
| 90 | + |
| 91 | +```bash |
| 92 | +cd apps/api |
| 93 | +python -m venv .venv |
| 94 | +source .venv/bin/activate # Windows: .venv\Scripts\activate |
| 95 | +pip install -e ".[dev]" |
| 96 | +uvicorn app.main:app --reload --port 8000 |
| 97 | +``` |
| 98 | + |
| 99 | +API docs available at: **http://localhost:8000/docs** |
| 100 | + |
| 101 | +### 5. Start the Next.js frontend |
| 102 | + |
| 103 | +In a new terminal: |
| 104 | + |
| 105 | +```bash |
| 106 | +cd apps/web |
| 107 | +pnpm dev |
| 108 | +``` |
| 109 | + |
| 110 | +App runs at: **http://localhost:3000** |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +## Clerk Webhook (local dev) |
| 115 | + |
| 116 | +The Clerk webhook syncs new users to Supabase. For local testing, use the Clerk CLI to tunnel events to localhost: |
| 117 | + |
| 118 | +```bash |
| 119 | +npx @clerk/cli@latest webhooks listen \ |
| 120 | + --webhook-secret whsec_your_secret \ |
| 121 | + http://localhost:3000/api/webhooks/clerk |
| 122 | +``` |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +## Project Structure |
| 127 | + |
| 128 | +``` |
| 129 | +CodePulse/ |
| 130 | +├── apps/ |
| 131 | +│ ├── web/ # Next.js frontend |
| 132 | +│ │ ├── app/ |
| 133 | +│ │ │ ├── (app)/ # Authenticated routes (dashboard, review, search…) |
| 134 | +│ │ │ ├── (auth)/ # Sign-in / sign-up pages |
| 135 | +│ │ │ └── api/webhooks/ # Clerk webhook endpoint |
| 136 | +│ │ ├── components/ # UI components (sidebar, due-badge…) |
| 137 | +│ │ ├── hooks/ # TanStack Query hooks |
| 138 | +│ │ ├── lib/ # Supabase clients, API client |
| 139 | +│ │ └── types/ # TypeScript types |
| 140 | +│ │ |
| 141 | +│ └── api/ # FastAPI algorithm engine |
| 142 | +│ ├── app/ |
| 143 | +│ │ ├── algorithms/ # SM-2, TF-IDF, K-means, Levenshtein, summarizer |
| 144 | +│ │ ├── routes/ # FastAPI route handlers |
| 145 | +│ │ └── models/ # Pydantic schemas |
| 146 | +│ └── tests/ # pytest test suite |
| 147 | +│ |
| 148 | +├── package.json # Workspace root |
| 149 | +└── pnpm-workspace.yaml # pnpm monorepo config |
| 150 | +``` |
| 151 | + |
| 152 | +--- |
| 153 | + |
| 154 | +## Available Commands |
| 155 | + |
| 156 | +### Frontend |
| 157 | + |
| 158 | +```bash |
| 159 | +pnpm --filter web dev # Start dev server |
| 160 | +pnpm --filter web build # Production build |
| 161 | +pnpm --filter web typecheck # TypeScript check |
| 162 | +pnpm --filter web lint # ESLint |
| 163 | +``` |
| 164 | + |
| 165 | +### Backend |
| 166 | + |
| 167 | +```bash |
| 168 | +cd apps/api |
| 169 | +pytest -v # Run all tests |
| 170 | +pytest tests/test_sm2.py -v # Run specific test file |
| 171 | +uvicorn app.main:app --reload # Start dev server |
| 172 | +``` |
| 173 | + |
| 174 | +### Database |
| 175 | + |
| 176 | +```bash |
| 177 | +supabase db query "SELECT * FROM users;" --linked # Run SQL |
| 178 | +supabase db pull --linked # Pull remote schema |
| 179 | +``` |
| 180 | + |
| 181 | +--- |
| 182 | + |
| 183 | +## Database Schema |
| 184 | + |
| 185 | +```sql |
| 186 | +CREATE TABLE users ( |
| 187 | + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), |
| 188 | + clerk_id TEXT UNIQUE NOT NULL, |
| 189 | + email TEXT NOT NULL, |
| 190 | + display_name TEXT, |
| 191 | + preferred_languages TEXT[] DEFAULT '{typescript,javascript}', |
| 192 | + review_reminder_time TIME DEFAULT '09:00', |
| 193 | + created_at TIMESTAMPTZ DEFAULT now(), |
| 194 | + updated_at TIMESTAMPTZ DEFAULT now() |
| 195 | +); |
| 196 | + |
| 197 | +CREATE TABLE snippets ( |
| 198 | + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), |
| 199 | + user_id UUID REFERENCES users(id) ON DELETE CASCADE NOT NULL, |
| 200 | + title TEXT NOT NULL, |
| 201 | + code TEXT, |
| 202 | + description TEXT, |
| 203 | + language TEXT DEFAULT 'typescript', |
| 204 | + tags TEXT[] DEFAULT '{}', |
| 205 | + ease_factor FLOAT DEFAULT 2.5, |
| 206 | + interval_days INTEGER DEFAULT 1, |
| 207 | + repetitions INTEGER DEFAULT 0, |
| 208 | + next_review DATE DEFAULT CURRENT_DATE, |
| 209 | + created_at TIMESTAMPTZ DEFAULT now(), |
| 210 | + updated_at TIMESTAMPTZ DEFAULT now() |
| 211 | +); |
| 212 | + |
| 213 | +CREATE TABLE review_logs ( |
| 214 | + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), |
| 215 | + snippet_id UUID REFERENCES snippets(id) ON DELETE CASCADE NOT NULL, |
| 216 | + user_id UUID REFERENCES users(id) ON DELETE CASCADE NOT NULL, |
| 217 | + rating INTEGER NOT NULL CHECK (rating BETWEEN 0 AND 5), |
| 218 | + ease_factor_after FLOAT NOT NULL, |
| 219 | + interval_after INTEGER NOT NULL, |
| 220 | + reviewed_at TIMESTAMPTZ DEFAULT now() |
| 221 | +); |
| 222 | + |
| 223 | +CREATE INDEX idx_snippets_next_review ON snippets(user_id, next_review); |
| 224 | +CREATE INDEX idx_snippets_user ON snippets(user_id); |
| 225 | +CREATE INDEX idx_snippets_tags ON snippets USING GIN(tags); |
| 226 | +CREATE INDEX idx_review_logs_snippet ON review_logs(snippet_id); |
| 227 | +CREATE INDEX idx_review_logs_user ON review_logs(user_id, reviewed_at); |
| 228 | +``` |
| 229 | + |
| 230 | +--- |
| 231 | + |
| 232 | +## API Endpoints |
| 233 | + |
| 234 | +| Method | Endpoint | Description | |
| 235 | +|--------|----------|-------------| |
| 236 | +| GET | `/api/health` | Health check | |
| 237 | +| POST | `/api/review/schedule` | SM-2 spaced repetition scheduling | |
| 238 | +| POST | `/api/search` | TF-IDF semantic search | |
| 239 | +| POST | `/api/clusters` | K-means topic clustering | |
| 240 | +| POST | `/api/snippets/check-duplicate` | Levenshtein duplicate detection | |
| 241 | +| POST | `/api/summarize` | Extractive text summarization (MMR) | |
| 242 | + |
| 243 | +--- |
| 244 | + |
| 245 | +## Production |
| 246 | + |
| 247 | +### Frontend — Vercel |
| 248 | + |
| 249 | +The frontend auto-deploys from the `dev` branch on every push. |
| 250 | + |
| 251 | +**Manual deploy:** |
| 252 | +```bash |
| 253 | +cd apps/web |
| 254 | +npx vercel deploy --prod --yes |
| 255 | +``` |
| 256 | + |
| 257 | +**Environment variables** are managed in the Vercel dashboard or via: |
| 258 | +```bash |
| 259 | +npx vercel env ls |
| 260 | +npx vercel env add KEY production |
| 261 | +``` |
| 262 | + |
| 263 | +### Backend — Railway |
| 264 | + |
| 265 | +Coming in Day 19. The FastAPI app deploys from `apps/api/Dockerfile`. |
| 266 | + |
| 267 | +**After Railway setup**, update `NEXT_PUBLIC_API_URL` in Vercel: |
| 268 | +```bash |
| 269 | +printf "https://your-app.railway.app" | npx vercel env add NEXT_PUBLIC_API_URL production --force |
| 270 | +npx vercel deploy --prod --yes |
| 271 | +``` |
| 272 | + |
| 273 | +### Production URLs |
| 274 | + |
| 275 | +| Service | URL | |
| 276 | +|---------|-----| |
| 277 | +| Frontend | https://web-two-beta-49.vercel.app | |
| 278 | +| Backend API | TBD (Railway — Day 19) | |
| 279 | +| Database | https://supabase.com/dashboard/project/dkbsdgsuqqegjvvojfks | |
| 280 | + |
| 281 | +--- |
| 282 | + |
| 283 | +## Branching Strategy |
| 284 | + |
| 285 | +``` |
| 286 | +main ← stable, tagged releases (v0.1.0, v0.2.0…) |
| 287 | + └── dev ← integration branch, all features merge here |
| 288 | + ├── sprint-2/feat-clerk-auth |
| 289 | + ├── sprint-2/feat-api-hooks |
| 290 | + └── sprint-2/feat-app-layout |
| 291 | +``` |
| 292 | + |
| 293 | +Never commit directly to `main` or `dev`. Always work on a `sprint-N/type-description` branch. |
0 commit comments