{"id":46003350,"url":"https://github.com/eftekin/halic-exam-genius-pro","last_synced_at":"2026-03-01T23:01:05.342Z","repository":{"id":341096487,"uuid":"1164500592","full_name":"eftekin/halic-exam-genius-pro","owner":"eftekin","description":"The simplest way for Haliç University students to manage their exam schedules.","archived":false,"fork":false,"pushed_at":"2026-02-27T23:56:40.000Z","size":467,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-28T23:42:32.265Z","etag":null,"topics":["docker","exam-schedule","fastapi","fullstack","nextjs","nginx","postgres","python","tailwindcss"],"latest_commit_sha":null,"homepage":"https://halicexamgenius.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eftekin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-23T06:38:29.000Z","updated_at":"2026-02-28T07:08:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/eftekin/halic-exam-genius-pro","commit_stats":null,"previous_names":["eftekin/halic-exam-genius-pro"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eftekin/halic-exam-genius-pro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eftekin%2Fhalic-exam-genius-pro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eftekin%2Fhalic-exam-genius-pro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eftekin%2Fhalic-exam-genius-pro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eftekin%2Fhalic-exam-genius-pro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eftekin","download_url":"https://codeload.github.com/eftekin/halic-exam-genius-pro/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eftekin%2Fhalic-exam-genius-pro/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29987654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T22:42:38.399Z","status":"ssl_error","status_checked_at":"2026-03-01T22:41:51.863Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","exam-schedule","fastapi","fullstack","nextjs","nginx","postgres","python","tailwindcss"],"created_at":"2026-02-28T22:33:06.144Z","updated_at":"2026-03-01T23:01:05.335Z","avatar_url":"https://github.com/eftekin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Haliç Exam Genius Pro\n\n**The production-grade evolution of the original Exam Genius, rebuilt for performance and scale.**\n\n\u003e A complete rewrite of the initial [`halic-exam-genius`](https://github.com/eftekin/halic-exam-genius) project, introducing containerization, asynchronous logging, and robust analytics.\n\nA production-grade exam schedule application for Haliç University. Students search courses, export schedules to calendar (ICS) or image (PNG), with full Turkish/English support and optional analytics.\n\n![FastAPI](https://img.shields.io/badge/FastAPI-009688?logo=fastapi\u0026logoColor=white)\n![Next.js](https://img.shields.io/badge/Next.js-000000?logo=next.js\u0026logoColor=white)\n![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql\u0026logoColor=white)\n![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker\u0026logoColor=white)\n![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript\u0026logoColor=white)\n\n\u003c/div\u003e\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Tech Stack](#tech-stack)\n- [Architecture](#architecture)\n- [Getting Started](#getting-started)\n- [Configuration](#configuration)\n- [Deployment](#deployment)\n- [Project Structure](#project-structure)\n- [License](#license)\n\n---\n\n## Features\n\n| Feature | Description |\n|--------|-------------|\n| **Multi-select search** | Fuzzy search by course code, name, or acronym. |\n| **ICS export** | RFC 5545 calendar files with `VTIMEZONE` (iOS, Android, Outlook). |\n| **PNG export** | Schedule as image at 2× resolution; Web Share API when available. |\n| **Bilingual (TR/EN)** | Locale-aware UI with full translation. |\n| **Dark mode** | Follows `prefers-color-scheme`. |\n| **Analytics** | Search events logged to PostgreSQL via background tasks. |\n\n---\n\n## Tech Stack\n\n| Layer | Technologies |\n|-------|--------------|\n| **Frontend** | Next.js 16, React 19, TypeScript 5, Tailwind CSS 4, html-to-image, Lucide React |\n| **Backend** | FastAPI, Pydantic v2, Pandas, SQLModel + asyncpg, Uvicorn (4 workers) |\n| **Infrastructure** | Docker Compose, Nginx (TLS + reverse proxy), Let’s Encrypt; frontend on Vercel |\n\n---\n\n## Architecture\n\n```mermaid\ngraph LR\n    subgraph Internet\n        A[\"Browser\"]\n    end\n    subgraph Vercel[\"Vercel\"]\n        B[\"Next.js Frontend\"]\n    end\n    subgraph Server[\"Application Server\"]\n        C[\"Nginx\"]\n        D[\"FastAPI\"]\n        E[(\"PostgreSQL\")]\n    end\n    subgraph Halic[\"Haliç University\"]\n        F[\"Excel (.xlsx)\"]\n    end\n    A --\u003e B\n    B --\u003e C\n    C --\u003e D\n    D --\u003e E\n    D --\u003e F\n```\n\n- **Frontend** (Vercel): Serves the Next.js app over HTTPS.\n- **Backend** (Docker): Nginx terminates TLS and proxies to FastAPI; FastAPI caches the Excel schedule in memory (configurable TTL) and logs analytics to PostgreSQL in the background.\n- **Data**: Schedule URL is configured in code; no need to set it in server `.env` (see [Configuration](#configuration)).\n\n---\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js 20+, Python 3.11+, Docker \u0026 Docker Compose (for full stack).\n\n### Backend (local)\n\n```bash\ncd backend\npython -m venv .venv\nsource .venv/bin/activate   # Windows: .venv\\Scripts\\activate\npip install -r requirements.txt\nuvicorn main:app --reload --port 8000\n```\n\n### Frontend (local)\n\n```bash\ncd frontend\nnpm install\nnpm run dev\n```\n\nSet the frontend API base URL via environment (e.g. `NEXT_PUBLIC_API_URL=http://localhost:8000` if needed).\n\n### Full stack with Docker\n\n```bash\ncd backend\ncp .env.example .env\n# Edit .env: set EXAM_GENIUS_SECRET_KEY, EXAM_GENIUS_CORS_ORIGINS, POSTGRES_*, EXAM_GENIUS_DATABASE_URL\ndocker compose up -d --build\n```\n\nThe API runs behind Nginx on port 80 (and 443 if TLS is configured). Do **not** set `EXAM_GENIUS_EXAM_SCHEDULE_URL` in `.env`; the schedule URL is defined in code (see below).\n\n---\n\n## Configuration\n\nSemester and exam schedule are controlled in two places only. You do **not** need to change server `.env` for the schedule URL.\n\n| What | File | Purpose |\n|------|------|--------|\n| **Excel schedule URL** | `backend/app/config.py` | URL of the official `.xlsx` schedule. Update here when the university publishes a new file; deploy to apply. |\n| **Semester labels \u0026 exam type** | `frontend/src/config/constants.ts` | Academic year, semester name (e.g. Güz/Fall), exam type (e.g. Vize/Midterm). Update when the exam period changes. |\n\n- **Backend**: Edit `exam_schedule_url` in `backend/app/config.py`, then commit and push. The deploy workflow builds a new image and recreates containers; the app uses the value from code.\n- **Frontend**: Edit `frontend/src/config/constants.ts` (e.g. `ACADEMIC_YEAR`, `SEMESTER_TR`, `EXAM_TYPE_TR`) and deploy the frontend (e.g. Vercel).\n\nAll other backend settings (secret key, CORS, database URL, cache TTL, sync interval) remain in `.env` as in `.env.example`.\n\n**Automated sync**: The backend runs a background task that checks the Excel URL for changes (via `HEAD` requests, comparing `ETag`/`Last-Modified`). When the file changes, the cache is invalidated so the next request fetches fresh data. Set `EXAM_GENIUS_SYNC_CHECK_INTERVAL_SECONDS` (default 1800 = 30 min) to control the check frequency; set to `0` to disable.\n\n---\n\n## Deployment\n\n### Backend (GitHub Actions)\n\nPushes to `main` that touch `backend/**` or `backend/app/config.py` trigger an automated deploy:\n\n1. SSH to the server, `git pull`, then from `backend/`: clear optional cached `.xlsx` files, run `docker compose up -d --build --force-recreate`, optional DB table refresh, then health check against `/health`.\n\n**Required secrets:**\n\n- `SERVER_HOST` — Server hostname or IP\n- `SSH_PRIVATE_KEY` — Private key for SSH (e.g. `root@SERVER_HOST`)\n\n**Optional:**\n\n- `REFRESH_DB_TABLES` — Comma-separated table names to truncate on deploy (e.g. `search_logs,faculty_analytics`) when the Excel structure or semester changes.\n\nThe workflow file: `.github/workflows/deploy.yml`.\n\n### Frontend\n\nDeploy the `frontend/` app to Vercel (or your chosen host). Point `NEXT_PUBLIC_API_URL` to your backend (e.g. `https://your-api-domain.com`). Ensure backend CORS allows that origin in `EXAM_GENIUS_CORS_ORIGINS`.\n\n---\n\n## Project Structure\n\n```\nhalic-exam-genius-pro/\n├── backend/\n│   ├── main.py              # ASGI app, CORS, routes\n│   ├── Dockerfile           # Multi-stage build\n│   ├── docker-compose.yml   # API, PostgreSQL, Nginx\n│   ├── nginx.conf           # Reverse proxy, TLS\n│   └── app/\n│       ├── config.py        # Settings (exam_schedule_url lives here)\n│       ├── database.py      # Async PostgreSQL\n│       ├── models/          # Pydantic schemas, SQLModel\n│       ├── routes/          # API endpoints\n│       └── services/        # Excel, ICS, analytics\n├── frontend/\n│   └── src/\n│       ├── app/             # Next.js app router\n│       ├── components/      # UI components\n│       ├── config/\n│       │   └── constants.ts # Semester \u0026 exam-type labels\n│       └── lib/             # API client, i18n, utils\n└── .github/workflows/\n    └── deploy.yml           # Backend deploy workflow\n```\n\n---\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feftekin%2Fhalic-exam-genius-pro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feftekin%2Fhalic-exam-genius-pro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feftekin%2Fhalic-exam-genius-pro/lists"}