ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
Practica para tu próxima entrevista técnica
Translation pending
EducationTypeScript · PythonGitHub @albertspOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
App para preparar entrevistas técnicas de desarrollo web con IA y flashcards personalizadas.
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Practica entrevistas técnicas reales con IA — preguntas de código, feedback inmediato y cards para repasar. Mientras estudiaba programación y me preparaba para mi primer empleo, me di cuenta de que practicar entrevistas técnicas solo con teoría no funciona. Necesitaba preguntas reales de código, alguien que me dijera exactamente qué había fallado, y una forma de repasar lo aprendido. No encontré ninguna herramienta que hiciera las tres cosas a la vez sin costar dinero, así que la construí.Read the full README ↗
Practice real technical interviews with AI: code questions, instant feedback, and study cards to review later.
🌐 interviewkit.dev · Repository
While learning to code and preparing for my first job, I realised that practising technical interviews with theory alone doesn't work. I needed real code questions, someone telling me exactly what went wrong, and a way to review what I had learned.
I couldn't find a free tool that did all three, so I built one.
InterviewKit generates 5 questions (2 theory + 3 code) tailored to your stack and level, evaluates your answers with AI, and saves every concept as a Q&A card you can review whenever you want.
| Layer | Technology |
|---|---|
| Frontend | Next.js 15 + React 19 + TypeScript |
| Styling | Tailwind CSS v4 + shadcn/ui |
| Animations | Framer Motion |
| Code editor | CodeMirror |
| Backend | Flask 3 (Python 3.12) |
| Database | PostgreSQL 16 + SQLAlchemy |
| Migrations | Alembic (Flask-Migrate) |
| Auth | JWT in httpOnly cookies + OAuth 2.0 (Authlib) |
| Rate limiting | Flask-Limiter |
| AI | Groq API (openai/gpt-oss-120b) |
| Testing | pytest (backend), Vitest + Testing Library (frontend) |
| CI | GitHub Actions |
| Deployment | Vercel (frontend) + Fly.io (backend) |
┌──────────────────┐ HTTPS + cookies ┌──────────────────┐ ┌────────────┐
│ Next.js 15 │ ───────────────────▶ │ Flask REST API │ ──▶ │ PostgreSQL │
│ (Vercel) │ ◀─────────────────── │ (Fly.io) │ └────────────┘
└──────────────────┘ └────────┬─────────┘
│
┌────────▼─────────┐
│ Groq API │
│ question + eval │
└──────────────────┘
frontend/.nvmrc; with nvm or fnm, run nvm use inside frontend/)git clone https://github.com/albertsp/interviewkit.git
cd interviewkit
# Database
docker compose up -d
# Backend
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # Fill in your keys (see below)
flask db upgrade
# Frontend
cd ../frontend
npm install
cp .env.example .env # NEXT_PUBLIC_API_URL=http://localhost:5000
# Terminal 1: backend
cd backend && flask run # http://localhost:5000
# Terminal 2: frontend
cd frontend && npm run dev # http://localhost:3000
The database container started in the setup step keeps running in the background.
backend/.env
| Variable | Required | Description |
|---|---|---|
JWT_SECRET_KEY | Yes | Secret used to sign JWTs. The app refuses to start without it. |
DATABASE_URL | Yes | e.g. postgresql://admin:admin@localhost:5432/interview_prep (matches docker-compose.yml). |
GROQ_API_KEY | Yes, for AI features | Groq API key used to generate and evaluate questions. |
FLASK_ENV | No | development locally, production when deployed. The /debug routes are only registered when it is not production. |
JWT_ACCESS_TOKEN_EXPIRES_HOURS | No | Lifetime of the access token. |
CORS_ORIGINS | Yes | Allowed frontend origins, e.g. http://localhost:3000. |
FRONTEND_URL | Yes | Where OAuth callbacks redirect the user. |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | For Google login | OAuth credentials. |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET | For GitHub login | OAuth credentials. |
frontend/.env
| Variable | Description |
|---|---|
NEXT_PUBLIC_API_URL | Base URL of the backend, e.g. http://localhost:5000. |
Never commit real secrets. Use
.env.exampleas the template and keep.envfiles out of git.
All endpoints except /auth/*, /stacks and the OAuth flow require a valid JWT, sent as a cookie or as an Authorization: Bearer header.
| Method | Endpoint | Description |
|---|---|---|
POST | /auth/register | Create an account with email and password |
POST | /auth/login | Log in and set the session cookie |
POST | /auth/logout | Clear the session cookie |
GET | /auth/google, /auth/github | Start the OAuth flow (callbacks at /auth/<provider>/callback) |
GET | /stacks/ | Available roles, technologies and levels |
POST | /sessions/ | Start a session and generate 5 questions: 2 theory + 3 code (AI) |
PATCH | /sessions/<id>/questions/<qid> | Submit an answer and get AI feedback |
POST | /sessions/<id>/complete | Complete a session and award XP |
GET | /cards/ | List your study cards |
POST | /cards/ | Create a card from a question |
PATCH / DELETE | /cards/<id> | Edit or delete a card |
GET | /me/stats | Aggregated statistics, XP and level |
GET / PATCH | /me/profile | Read or update your profile |
GET | /debug/db | Database diagnostics (non-production only) |
POST | /auth/oauth/exchange | Exchange the one-time OAuth code for an access token |
GET | /health | Liveness and database check (no auth) |
Rate limits (AI endpoints): 5 session creations per hour and 15 answer evaluations per hour per user, plus a global shared limit of 20 per minute and 40 per day to protect the Groq free-tier budget.
XP rules: 100 XP for a correct answer, 50 for a partially correct one, 10 for an incorrect one, plus a 50 XP completion bonus. Every 500 XP is a level.
# Backend (SQLite in memory, no database or API keys needed)
cd backend
source venv/bin/activate # Windows: venv\Scripts\activate
pytest
# Backend with coverage
pytest --cov=app --cov-report=term-missing
# Frontend
cd frontend
npm test # single run
npm run test:watch # watch mode
The backend has tests for authentication, OAuth, models, sessions, cards, user stats and the AI service (with the Groq client mocked). The frontend has tests for the authentication context.
Continuous integration: .github/workflows/ci.yml runs on every push and pull request, with the backend and frontend jobs in parallel (Python 3.12 and Node 22, with dependency caching). Backend: ruff lint + pytest with coverage (minimum 85%, reported to Codecov). Frontend: tsc type-check + next lint + vitest. No secrets are required.
interviewkit/
├── .github/workflows/ci.yml # CI: pytest + npm test
├── backend/
│ ├── app/
│ │ ├── models/ # User, Session, Question, Card, OAuthAccount
│ │ ├── routes/ # auth, oauth, sessions, cards, user, stacks, debug
│ │ ├── services/ # Business logic and Groq integration
│ │ ├── constants/ # Gamification rules and stacks
│ │ ├── __init__.py # App factory, rate limiter, OAuth init
│ │ └── config.py # Configuration from environment variables
│ ├── migrations/ # Alembic migrations
│ ├── tests/
│ ├── Dockerfile
│ ├── fly.toml
│ └── requirements.txt
├── frontend/
│ ├── app/(app)/
│ │ ├── page.tsx # Landing page
│ │ ├── login/ · register/
│ │ ├── auth/callback/ # OAuth callback handler
│ │ └── (protected)/ # dashboard, session, stats, profile
│ ├── src/
│ │ ├── components/
│ │ ├── context/ # AuthContext
│ │ ├── services/ # API calls
│ │ └── __tests__/
│ └── public/
├── docker-compose.yml # Local PostgreSQL
└── README.md
Backend: Fly.io
cd backend && fly deploy
Migrations run automatically on every deploy (release_command in fly.toml). Set environment variables with fly secrets set, and make sure FLASK_ENV=production.
Frontend: Vercel
A push to main deploys automatically. Set NEXT_PUBLIC_API_URL in the Vercel dashboard.
Because the frontend and backend live on different domains, the auth cookie is set with SameSite=None; Secure, and CORS_ORIGINS must list the exact frontend origin.
Why Flask and not Django or FastAPI? Flask gave me full control over the structure without imposing patterns. For a REST API of this size Django would have been overkill, and FastAPI would have meant learning async from scratch at the same time.
Why Groq and not OpenAI? Groq has a generous free tier and very low latency. When the user is waiting for questions in real time, speed matters, and the hosted open-weight model is capable enough to generate quality technical questions.
Which model, and why?
The app uses openai/gpt-oss-120b on Groq. It replaced llama-3.3-70b-versatile, which Groq retired on 2026-08-16 and listed gpt-oss-120b as its recommended replacement. It is a production-tier model (the other candidates are previews), fast enough for real-time use, and strong enough for technical questions and feedback. The model name is set in backend/app/services/ai_service.py. Keep in mind it is a reasoning model, so its reasoning tokens count against the free-tier token limits (8K tokens per minute, 200K per day).
Two-layer rate limiting The Groq free tier has one budget shared by the whole app. I implemented two limits: per user (so one account can't drain it) and global (to protect the real budget). With only a per-user limit, a coordinated attack could still exhaust the quota.
OAuth login with a one-time exchange code The OAuth flow redirects from the backend to the frontend. Instead of putting the token in the URL (visible in history and logs), the backend sends a signed, one-time code (valid for 60 seconds) in the URL fragment, which browsers never send to a server. The frontend reads it, clears the address bar and exchanges it at POST /auth/oauth/exchange for the token. The token is stored in localStorage and also set as an httpOnly cookie. This is a compromise: some browsers (Safari, Brave) block the cross-site cookie, so the header is needed, at the cost of some XSS protection. Serving the API from a subdomain of the same site would let me drop localStorage.
Prompt injection mitigation
User answers go straight to the AI model for evaluation. I wrapped user input in ###ANSWER_START### / ###ANSWER_END### delimiters and added explicit instructions to the system prompt to treat that block as data, not as instructions.
The N+1 problem in statistics
The first version of /me/stats ran one query per session to fetch its questions. It's unnoticeable with little data but scales badly. I found it by inspecting the queries SQLAlchemy generated and fixed it with a single JOIN. I also added missing foreign-key indexes.
OAuth is more complex than it looks
Social login with Google and GitHub seemed simple until the details: cross-origin cookies require SameSite=None; Secure, the JWT can't travel in the URL, and you have to decide what happens when someone signs in with Google using an email that already has a password account. Every decision has security implications.
Global auth state in Next.js Coordinating session state between the server (httpOnly cookie) and the client (React Context) with the Next.js 15 App Router was the hardest frontend challenge. The protected layout has to handle the loading state correctly so it never shows protected content before the session is verified.
Designing the AI prompts The quality of the generated questions depends entirely on the prompt. Early versions produced overly theoretical questions ("What is a closure?"). Iterating on the system prompt to force concrete code questions in the code block was trial and error that took much longer than I expected. LLM output also needs defensive parsing (stripping markdown fences, fixing double-escaped newlines in code).
| Problem | Likely cause and fix |
|---|---|
RuntimeError about JWT_SECRET_KEY on startup | The variable is missing in backend/.env. |
connection refused on port 5432 | The database container isn't running: docker compose up -d. |
| Login works but you're immediately logged out | CORS_ORIGINS doesn't match the frontend origin, or cookies are blocked cross-origin. Check SameSite/Secure settings in production. |
429 Too Many Requests when starting a session | You hit a rate limit (see API overview). Wait and retry. |
| AI requests fail with 401 | GROQ_API_KEY is missing or invalid. |
pip install fails locally | Use Python 3.12 (the version used in the Dockerfile and CI). |
Contributions are welcome. Please read CONTRIBUTING.md for the setup, the checks that must pass and the commit conventions.
Released under the MIT License.