Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
13e80a7
FEAT - assign free plan scan to patient when upgrade
elwessdev May 3, 2026
6066b32
close notification
elwessdev May 5, 2026
e0c5d78
chore: add a blank line for better code readability in NotificationDe…
elwessdev May 7, 2026
dc8e3c6
feat: implement report generation and job status polling
elwessdev May 8, 2026
d912b66
fix: update favicon links and site manifest for proper branding
elwessdev May 8, 2026
61d3465
chore: improve code readability by adjusting comments and formatting …
elwessdev May 8, 2026
b9b498d
Add favicon images and web manifest for TumorLens
elwessdev May 8, 2026
1c8fcb5
fix deploy bugs
elwessdev May 8, 2026
abe1a0b
Update Landing page
elwessdev May 8, 2026
a62515a
feat: add CLAUDE.md for project overview and development guidance
elwessdev May 11, 2026
4492a12
feat: add client service with Docker configuration and nginx setup
elwessdev May 11, 2026
dcd679b
fix: add Redis environment variables and healthcheck to docker-compose
elwessdev May 12, 2026
c6d5ac6
fix: remove commented-out trust badge for institutions in BrandPanel
elwessdev May 17, 2026
5ad8a57
feat: add super admin module with services and controllers for user m…
elwessdev May 20, 2026
ec74d2d
refactor: simplify navigation and routing for super admin features
elwessdev May 20, 2026
070562b
refactor: update ticket detail page to use SuperAdminTicketDetailRout…
elwessdev May 21, 2026
4a4c541
feat: implement command palette for quick navigation and search funct…
elwessdev Jun 9, 2026
b680c14
feat: add Help & Support feature with contact form and legal pages
elwessdev Jun 10, 2026
d45e3b2
refactor: update deploy workflow description and clean up unused comm…
elwessdev Jun 11, 2026
0c001a3
refactor: remove unused cloudinary dependency from package.json and p…
elwessdev Jun 12, 2026
855b68c
refactor: remove unused isOrgMember variable from DashboardLayout com…
elwessdev Jun 12, 2026
907aaee
code refactoring
elwessdev Jun 12, 2026
a3f7fc5
ci: add test & lint pipeline (Jest + Ruff)
elwessdev Jun 12, 2026
2d2f034
ci: gate deploy builds on tests and lint
elwessdev Jun 12, 2026
86a3351
refactor: remove commented-out StickyPromoBanner component and unused…
elwessdev Jun 13, 2026
5185950
docs: add README.md with project overview, features, architecture, an…
elwessdev Jun 28, 2026
5adf034
docs: update README.md to center align title and logo
elwessdev Jun 28, 2026
80de379
docs: update logo path in README.md to correct location
elwessdev Jun 28, 2026
e35b9fb
docs: update formatting in README.md for consistency
elwessdev Jun 28, 2026
825a91b
docs: add medical disclaimer and proprietary license to README.md and…
elwessdev Jun 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: CI

on:
push:
branches: [dev]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
changes:
name: Detect changed folders
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.filter.outputs.backend }}
rag: ${{ steps.filter.outputs.rag }}
model: ${{ steps.filter.outputs.model }}
steps:
- uses: actions/checkout@v4

- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- 'server/**'
rag:
- 'scan_report/**'
model:
- 'scan_model/**'

test-backend:
name: Backend - Jest tests
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.backend == 'true'
defaults:
run:
working-directory: server
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: server/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test

lint-rag:
name: RAG - Ruff lint
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.rag == 'true'
steps:
- uses: actions/checkout@v4

- uses: astral-sh/ruff-action@v3
with:
src: ./scan_report

lint-model:
name: Model - Ruff lint
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.model == 'true'
steps:
- uses: actions/checkout@v4

- uses: astral-sh/ruff-action@v3
with:
src: ./scan_model
61 changes: 54 additions & 7 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
workflow_dispatch:
inputs:
force_build:
description: 'Force rebuild all services (backend/rag/model)'
description: 'Force rebuild all services'
required: false
default: 'false'

Expand Down Expand Up @@ -36,11 +36,58 @@ jobs:
model:
- 'scan_model/**'

build-backend:
name: Build & push backend image
test-backend:
name: Backend — Jest tests
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.backend == 'true'
defaults:
run:
working-directory: server
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: server/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test

lint-rag:
name: RAG — Ruff lint
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.rag == 'true'
steps:
- uses: actions/checkout@v4

- uses: astral-sh/ruff-action@v3
with:
src: ./scan_report

lint-model:
name: Model — Ruff lint
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.model == 'true'
steps:
- uses: actions/checkout@v4

- uses: astral-sh/ruff-action@v3
with:
src: ./scan_model

build-backend:
name: Build & push backend image
runs-on: ubuntu-latest
needs: [changes, test-backend]
if: needs.test-backend.result == 'success'
steps:
- uses: actions/checkout@v4

Expand All @@ -58,8 +105,8 @@ jobs:
build-rag:
name: Build & push rag image
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.rag == 'true'
needs: [changes, lint-rag]
if: needs.lint-rag.result == 'success'
steps:
- uses: actions/checkout@v4

Expand All @@ -77,8 +124,8 @@ jobs:
build-model:
name: Build & push model image
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.model == 'true'
needs: [changes, lint-model]
if: needs.lint-model.result == 'success'
steps:
- uses: actions/checkout@v4

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
doc
*.env
RPT

# compiled output
*/dist
Expand Down
125 changes: 125 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

TumorLens is a full-stack medical SaaS for brain tumor detection and reporting. It is a **monorepo** with four independent services:

| Service | Stack | Port |
|---------|-------|------|
| `client/` | React 19 + Vite + TanStack Router/Query + Ant Design | 5173 |
| `server/` | NestJS 11 + Prisma 7 + PostgreSQL | 3000 |
| `scan_model/` | Python (Gradio) — brain tumor ML model | 7860 |
| `scan_report/` | Python (FastAPI) — RAG report generation | 8000 |

There is no root `package.json`. Each service is managed independently.

## Development Commands

### Client (`cd client`)
```bash
npm run dev # Vite dev server with HMR
npm run build # tsc -b && vite build
npm run lint # ESLint
npm run preview # Preview production build
```

### Server (`cd server`)
```bash
npm run start:dev # NestJS watch mode
npm run build # NestJS compile to dist/
npm run start # Run compiled dist/main.js
npm run test # Jest unit tests (*.spec.ts)
npm run test:e2e # Jest e2e tests
npm run lint # ESLint --fix
npm run format # Prettier
```

### Prisma (`cd server`)
```bash
npx prisma migrate dev # Apply migrations in development
npx prisma generate # Regenerate Prisma client after schema changes
npx prisma studio # Visual DB browser
```

### Running a single test
```bash
# From server/
npx jest src/auth/auth.service.spec.ts
npx jest --testPathPattern=auth
```

### Full stack via Docker
```bash
docker-compose up # All services (backend, frontend, ML, RAG, postgres, redis)
docker-compose up backend # Single service
```

## Architecture

### Client

- **Routing**: TanStack Router (`client/src/router.ts`). All protected routes live under the dashboard layout.
- **Data fetching**: TanStack Query wraps all API calls. No direct `axios` calls in components — queries/mutations are co-located in `hooks.ts` files next to each feature.
- **Auth state**: Zustand store (`client/src/store/auth.store.ts`). Tokens are managed via HTTP-only cookies; the store holds user profile data.
- **HTTP client**: Single Axios instance at `client/src/lib/axios.ts` with interceptors for auth headers and 401 handling.
- **Features** live in `client/src/features/` — each folder is a route segment with its own pages, components, and hooks.

### Server

- **NestJS modules** are organized by domain in `server/src/`. Each module owns its controller, service, DTOs, and guards.
- **Database access** is exclusively via the Prisma client. No raw SQL outside of Prisma `$queryRaw`.
- **Authentication flow**: JWT access + refresh tokens delivered as HTTP-only cookies. Google OAuth via Passport strategy. 2FA via TOTP (otplib). Password reset via Resend email.
- **Async jobs**: Report generation is queued via BullMQ (Redis). The processor lives in `server/src/Report/`.
- **Real-time**: Server-Sent Events (SSE) for in-app notifications — see `server/src/Notifications/notifications.stream.ts`.
- **Storage**: DigitalOcean Spaces (S3-compatible) via AWS SDK — see `server/src/Storage/`.
- **Plan guards**: `@RequirePlan(Plan.DOCTOR)` decorator/guard enforces subscription tier on routes.
- **Public API**: API key authentication for external integrations in `server/src/Public-API/`.

### Key data models (Prisma schema in `server/prisma/schema.prisma`)

- `User` — roles: `USER | ADMIN`; plans: `FREE | DOCTOR | ORGANIZATION`; supports OTP/2FA
- `Organization` → `OrgMember` (multi-tenant hospital/clinic support with audit logs)
- `Patient` → `Scan` → `ScanResult` (core clinical data chain)
- `Subscription` + `Payment` (Stripe billing)
- `Session` (refresh token store)
- `ApiKey` (public API access)

### ML services

- `scan_model/` exposes a Gradio API; the NestJS server calls it via HTTP at `ML_MODEL_URL`.
- `scan_report/` exposes a FastAPI endpoint; the server calls it to generate RAG-based PDF reports.

## Environment Setup

**Server** — create `server/.env`:
```
DATABASE_URL=postgresql://...
JWT_ACCESS_SECRET=...
JWT_REFRESH_SECRET=...
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
ML_MODEL_URL=http://localhost:7860
ML_MODEL_API_KEY=...
DIGITAL_OCEAN_SPACE_KEY=...
DIGITAL_OCEAN_SPACE_SECRET=...
DIGITAL_OCEAN_SPACE_ENDPOINT=...
DIGITAL_OCEAN_SPACE_BUCKET=...
RESEND_API_KEY=...
STRIPE_SECRET_KEY=...
STRIPE_WEBHOOK_SECRET=...
REDIS_HOST=localhost
REDIS_PORT=6379
CLIENT_URL=http://localhost:5173
PORT=3000
```

**Client** — create `client/.env`:
```
VITE_API_URL=http://localhost:3000
```

## CI/CD

GitHub Actions (`.github/workflows/deploy.yml`) builds Docker images and deploys to a DigitalOcean Droplet on push to `main`. Path filters ensure only changed services are rebuilt (`server/`, `scan_report/`, `scan_model/`). Images are pushed to GHCR.
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Copyright (c) 2026 Osama. All Rights Reserved.

TumorLens - Proprietary Software License

This software and its associated source code, documentation, models, datasets,
and assets (collectively, the "Software") are the proprietary and confidential
property of the copyright holder.

NO PERMISSION is granted to any person to use, copy, modify, merge, publish,
distribute, sublicense, sell, or otherwise exploit the Software, in whole or in
part, by any means, without the prior written permission of the copyright
holder.

The Software is provided for viewing and evaluation purposes only, as an
academic final-year graduation project. Any other use is strictly prohibited.

MEDICAL DISCLAIMER

The Software is a research and educational project. It is NOT a certified
medical device and must NOT be used for actual clinical diagnosis, treatment,
or any real-world medical decision-making.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM,
OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading