{"id":50695748,"url":"https://github.com/hngprojects/clinical-be-new","last_synced_at":"2026-06-09T06:08:35.139Z","repository":{"id":357599061,"uuid":"1237425242","full_name":"hngprojects/clinical-be-new","owner":"hngprojects","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-13T14:08:43.000Z","size":1472,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"dev","last_synced_at":"2026-05-13T14:11:53.564Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hngprojects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"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-05-13T07:08:00.000Z","updated_at":"2026-05-13T12:34:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hngprojects/clinical-be-new","commit_stats":null,"previous_names":["hngprojects/clinical-be-new"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hngprojects/clinical-be-new","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fclinical-be-new","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fclinical-be-new/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fclinical-be-new/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fclinical-be-new/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hngprojects","download_url":"https://codeload.github.com/hngprojects/clinical-be-new/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fclinical-be-new/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34093840,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2026-06-09T06:08:34.141Z","updated_at":"2026-06-09T06:08:35.133Z","avatar_url":"https://github.com/hngprojects.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Clinsights\n\n## 1. Product Overview\nClinsight is an AI-powered clinical support platform that helps users understand their laboratory test results instantly. Users upload a laboratory report as an image or PDF, and Clinsight extracts the medical values, interprets them using AI, and explains the results in plain, human language.\nThe MVP focuses on one core problem: people receive laboratory results but cannot understand what they mean without waiting for a doctor. Clinsight reduces that waiting time by giving users immediate explanations, risk indicators, and guidance on what questions to ask a doctor next.\n\n## 2. Key Features\n- **Guest Upload**: Upload + full AI interpretation without an account. Prompted to sign up after 3 responses.\n- **Authentication**: Email/password signup with OTP verification. Google OAuth. Password reset. Session persistence.\n- **Lab Results Upload**: Camera capture + file upload (JPG, PNG, PDF). Validation, loading, and error states included.\n- **OCR Extraction**: Extracts test names, values, reference ranges. Preview screen before AI runs.\n- **AI Interpretation**: Plain-language explanation. Summary + suggested questions. Medical disclaimer on every screen.\n- **Follow-Up Chat**: Context-aware chat tied to each upload. Persistent thread per session. Suggested prompt questions for new users.\n- **History**: Authenticated users can view, reopen, and delete past interpretations.\n- **Notifications \u0026 Settings**: Push notification when interpretation is ready. Notification preferences, profile editing, email/password update, account deletion.\n\n## 3. Tech Stack\n- **Backend**: Python FastAPI\n- **Authentication**: OTP-based (email/phone), no passwords, Google OAuth\n- **OCR**: Document/image text extraction\n- **Database**: PostgreSQL\n\n## 4. Inputs \u0026 Outputs\n| Feature | User Input | System Output |\n| :--- | :--- | :--- |\n| **Upload** | Photo or file (JPG/PNG/PDF) | Validated file → OCR pipeline |\n| **OCR** | Uploaded image / PDF | Test names, values, reference ranges extracted |\n| **AI Interpretation** | Confirmed OCR values | Plain-language explanations, summary, follow-up questions |\n| **Chat** | Free-text question, Suggested questions | Context-aware AI response using report data |\n| **Signup** | Email + password or Google OAuthentication | Account created; OTP verification email sent |\n| **Guest Migration**| Sign up after guest upload | Guest session linked to account; interpretation saved |\n\n## 5. High-Level Logic \u0026 Behaviour\n- **Upload**: Accepted: JPG, PNG, PDF. Unreadable/unsupported file → error state + reupload. OCR timeout at 15s → error + reupload.\n- **AI Engine**: Classifies each value as Normal / Caution / Abnormal against reference. Disclaimer appended automatically. AI error → fallback message + retry.\n- **Guest Flow**: Upload-to-interpretation without account. The session expires in 1hr. Sign-up prompt on: After 3 messages; chat history migration is automatic on signup.\n- **Auth \u0026 Session**: OTP valid 15 mins, single-use. Password reset link expires in 1hr. Google OAuth via OAuth 2.0. Tokens stored securely on device.\n- **Notifications**: Push sent on interpretation complete. Suppressed if the user is actively on the result screen. Users who opt out can still access results in-app.\n\n## 6. Acceptance Criteria\n- **Lab result uploaded in under 30 seconds**: ≤ 30s\n- **OCR extracts values accurately**: 85%+\n- **AI interpretation generated successfully**: 90%+\n- **AI interpretation completes within 15 seconds**: \u003c 15s\n- **Chat produces context-aware responses**: Pass\n- **Guest session migrates without data loss**: Pass\n- **Authentication flows complete without errors**: Pass\n- **Crash-free sessions across core flow**: 95%+\n- **Medical disclaimer on every interpretation screen**: 100%\n- **Users can view past interpretations**: Pass\n\n## 7. Out of Scope\n- Doctor/patient matching \u0026 telemedicine\n- Doctor dashboard, onboarding, verification\n- PDF export\n- Long-term patient health tracking\n- Multi-language support\n- Hospital / lab system integrations\n- AI learning loop \u0026 model retraining\n- Admin analytics system\n\n## Project structure\n\nThis is the **target layout for the full MVP**. Interns should follow this exactly — add files in the right domain folders rather than creating new top-level directories.\n\n```text\nclinsights-be/\n├── app/\n│   ├── main.py                            # FastAPI app, global exception handlers\n│   ├── core/\n│   │   ├── config.py                      # Settings loaded from .env (pydantic-settings)\n│   │   └── security.py                    # JWT + password hashing utilities\n│   ├── api/\n│   │   ├── deps.py                        # Shared dependencies: DBSession, CurrentUser, GuestSession\n│   │   └── v1/\n│   │       ├── router.py                  # Aggregates all v1 domain routers\n│   │       └── endpoints/\n│   │           ├── auth.py                # /auth — signup, login, OTP verify, Google OAuth\n│   │           ├── users.py               # /users — profile, settings, account deletion\n│   │           ├── upload.py              # /upload — file upload (JPG, PNG, PDF)\n│   │           ├── ocr.py                 # /ocr — trigger extraction, preview extracted values\n│   │           ├── interpretation.py      # /interpretation — AI result + risk classification\n│   │           ├── chat.py                # /chat — follow-up Q\u0026A tied to an interpretation\n│   │           ├── history.py             # /history — list, view, delete past interpretations\n│   │           └── notifications.py       # /notifications — preferences, push settings\n│   ├── db/\n│   │   └── session.py                     # Async engine + session factory + get_session()\n│   ├── models/\n│   │   ├── __init__.py                    # Imports all models — required for Alembic discovery\n│   │   ├── user.py                        # User ORM model\n│   │   ├── otp.py                         # OTP codes\n│   │   ├── lab_report.py                  # LabReport — file path, upload status, guest session link\n│   │   ├── ocr_result.py                  # OCRResult — extracted test names, values, ranges\n│   │   ├── interpretation.py              # Interpretation — AI output, risk level, disclaimer\n│   │   ├── chat.py                        # ChatSession + ChatMessage — per-report chat threads\n│   │   └── notification.py                # NotificationPreference — per-user push settings\n│   ├── schemas/\n│   │   ├── auth.py                        # Signup, Login, OTP request/response schemas\n│   │   ├── user.py                        # User profile schemas\n│   │   ├── upload.py                      # Upload response schemas\n│   │   ├── ocr.py                         # OCR preview + confirm schemas\n│   │   ├── interpretation.py              # AI interpretation response schemas\n│   │   ├── chat.py                        # Chat message request/response schemas\n│   │   ├── history.py                     # History list/detail schemas\n│   │   └── notification.py                # Notification preference schemas\n│   └── services/\n│       ├── auth/                          # Modular auth services\n│       │   ├── email.py                   # Auth-specific email dispatch\n│       │   ├── otp.py                     # OTP generation + validation logic\n│       │   ├── service.py                 # Core auth business logic\n│       │   └── tokens.py                  # JWT lifecycle logic\n│       ├── email.py                       # General transactional email client (Resend)\n│       ├── oauth.py                       # Google OAuth integration\n│       ├── upload.py                      # File validation, storage (local/S3), size checks\n│       ├── ocr.py                         # OCR extraction pipeline (PDF/image → structured data)\n│       ├── ai.py                          # AI interpretation engine — prompting, risk classification\n│       ├── chat.py                        # Chat service — context injection, response generation\n│       ├── guest.py                       # Guest session management + migration to user account\n│       └── notification.py               # Push notification dispatch + preference management\n├── alembic/\n│   ├── env.py                             # Wired to app.models.Base.metadata + settings\n│   └── versions/                          # Migration files — one per schema change\n├── tests/                                 # Pytest suite\n├── .env.example\n├── alembic.ini\n├── pyproject.toml\n└── uv.lock\n```\n\n### Why this layout\n\n- **`api/deps.py`** — all shared FastAPI dependencies live here. Routes import `DBSession`, `CurrentUser`, and `GuestSession` from one place.\n- **`models` / `schemas` / `services` split** — DB shape, API shape, and business logic stay decoupled. They diverge faster than you'd think.\n- **`db/session.py` separate from `models/`** — engine setup is infrastructure; models are domain.\n- **One file per domain in `endpoints/`, `models/`, `schemas/`, `services/`** — makes it easy to find where any feature lives and keeps PRs focused.\n\n---\n\n## Getting started\n\n### 1. Prerequisites\n\n- Python 3.12+\n- [uv](https://docs.astral.sh/uv/) (`curl -LsSf https://astral.sh/uv/install.sh | sh`)\n- A running Postgres instance (local, Docker, or Supabase)\n\n### 2. Install\n\n```bash\nuv sync\n```\n\n### 3. Configure\n\n```bash\ncp .env.example .env\n```\n\nFill in `.env` with your database credentials and secrets:\n\n```env\nDATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/clinsights\nJWT_SECRET=\u003cgenerate: python3 -c \"import secrets; print(secrets.token_urlsafe(64))\"\u003e\nJWT_ALGORITHM=HS256\nOTP_PEPPER=\u003cgenerate: python3 -c \"import secrets; print(secrets.token_urlsafe(64))\"\u003e\n```\n\n### 4. Database Setup\n\nEnsure your local PostgreSQL database is created (`clinsights`) and the proper roles exist. Open your `psql` terminal and execute:\n\n```sql\nALTER SCHEMA public OWNER TO postgres;\nGRANT ALL ON SCHEMA public TO postgres;\nGRANT CREATE ON SCHEMA public TO postgres;\nGRANT USAGE ON SCHEMA public TO postgres;\nGRANT ALL PRIVILEGES ON DATABASE clinsights TO postgres;\n```\n\nThen run migrations:\n\n```bash\nuv run alembic upgrade head\n```\n\n### 5. Start the dev server\n\n```bash\nuv run fastapi dev app/main.py\n```\n\nOr run via Uvicorn explicitly:\n\n```bash\nuv run uvicorn app.main:app --reload\n```\n\n- Root API → `http://127.0.0.1:8000`\n- Swagger UI → `http://127.0.0.1:8000/docs`\n- ReDoc → `http://127.0.0.1:8000/redoc`\n\n---\n\n## Migrations workflow\n\nWe use Alembic integrated with `uv` to manage database schema migrations.\n\n### Typical cycle\n\n```bash\n# 1. Edit a model in app/models/\n# 2. Generate a migration\nuv run alembic revision --autogenerate -m \"describe the change\"\n# 3. Review the generated file carefully before applying\n# 4. Apply\nuv run alembic upgrade head\n```\n\n### Important: add new models to `app/models/__init__.py`\n\nAlembic discovers models by importing them. If a model file is not imported in `__init__.py`, Alembic won't see it.\n\n```python\n# app/models/__init__.py — every model must be listed here\nfrom app.models.user import User\nfrom app.models.otp import OTP\n```\n\n---\n\n## Adding new code\n\n### New endpoint\n1. Add route handlers to the relevant file in `app/api/v1/endpoints/`\n2. Import and register in `app/api/v1/router.py`\n\n### New model\n1. Create or extend a file in `app/models/`\n2. Import the model in `app/models/__init__.py` so Alembic discovers it\n3. Generate and apply a migration\n\n### New schema\nAdd Pydantic request/response models to `app/schemas/`. Keep them separate from ORM models.\n\n### New business logic\nAdd it to `app/services/`. Routes should stay thin: validate input → call service → return response.\n\n---\n\n## Contributing\n\n1. Fork the repository and create your feature branch (`git checkout -b feature/your-feature`)\n2. Install dependencies: `uv sync`\n3. Run tests before committing: `uv run pytest`\n4. Install pre-commit hook (`uv run pre-commit install`)\n5. Commit your changes (`git commit -m 'Add feature'`)\n6. Push to your branch (`git push origin feature/your-feature`)\n7. Open a Pull Request\n\n### Guidelines\n\n- Follow existing code style and conventions\n- Write clear, descriptive commit messages\n- Include tests for new features\n- Keep PRs focused and manageable in size\n- Never commit secrets, keys, or credentials\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhngprojects%2Fclinical-be-new","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhngprojects%2Fclinical-be-new","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhngprojects%2Fclinical-be-new/lists"}