Project Overview
Aarogya-AI delivers AI-powered health tools tailored for Indian users. It combines conversational care, diagnostic analysis and personalized reminders on web and mobile.
Purpose
Provide accessible, intelligent health support:
- Offer an AI chatbot for symptom checks and health advice
- Analyze skin conditions and sleep patterns using computer vision
- Send timely medication reminders
- Store prescriptions and enable voice interactions (upcoming)
Audience
- End users seeking at-home health insights
- Developers extending AI modules or integrating new features
- Healthcare startups building localized solutions for India
Key Features
- AI Chatbot: Multilingual conversational agent for symptom analysis
- Skin Analysis: Image-based assessment of common dermatological issues
- Sleep Analysis: Sleep pattern detection via mobile camera
- Medication Reminders: Scheduled notifications on web/mobile
- Roadmap: Prescription storage, voice support, advanced health insights
Tech Stack
- Frontend: Next.js, React, Tailwind CSS
- Backend: Node.js, Express, Supabase
- AI Services: OpenAI API, TensorFlow.js
- Database: Supabase (PostgreSQL, Auth, Storage)
Core Modules
- /components: Reusable UI elements
- /pages: Next.js routes for web views
- /api: Serverless endpoints (chat, analysis, reminders)
- /services: AI integration and data processing
- /mobile: React Native wrappers for cross-platform support
Roadmap
- Integrate advanced AI-driven health insights
- Enable multilingual support (Hindi, regional languages)
- Add prescription upload and secure storage
- Implement voice-based chatbot & analysis
Quick Start
Clone, install dependencies and launch the development server.
git clone https://github.com/sarvankumar-fsdp/Aarogya-AI.git
cd Aarogya-AI
npm install
npm run dev # Starts Next.js on http://localhost:3000
## Getting Started
Follow these steps to clone, install, configure, and launch Aarogya AI locally or in a cloud workspace.
### Prerequisites
- Node.js v16 or higher
- npm (v8+) or Yarn
- Git
- Supabase account (for database, auth, AI integrations)
### 1. Clone the Repository
Navigate to your workspace and clone the project:
```bash
git clone https://github.com/sarvankumar-fsdp/Aarogya-AI.git
cd Aarogya-AI
2. Install Dependencies
Use your package manager of choice:
# npm
npm install
# Yarn
yarn install
3. Configure Environment Variables
Create a .env.local
file in the project root. At minimum, define your Supabase credentials:
NEXT_PUBLIC_SUPABASE_URL=https://xyzcompany.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
NEXT_PUBLIC_SUPABASE_*
variables expose keys to the client for real-time data and auth.SUPABASE_SERVICE_ROLE_KEY
remains server-only (used in API routes).
4. Run Locally
Start the development server with hot-reload:
npm run dev
Visit http://localhost:3000
in your browser. The app uses:
- Next.js (frontend & API routes)
- Tailwind CSS (styling via
tailwind.config.ts
+postcss.config.mjs
) - Supabase (data, auth, AI extensions)
5. Build & Serve Production
Compile and start the optimized build:
npm run build
npm start
By default, the app listens on port 3000. You can override with PORT
:
PORT=8080 npm start
6. Cloud Workspace (e.g., GitHub Codespaces)
- Open the repo in your cloud IDE.
- Expose port 3000 for preview.
- Install dependencies and run
npm run dev
as above.
All environment steps remain identical. Ensure your .env.local
is set or use workspace secrets to inject Supabase keys.
Environment & Configuration
This section lists all environment variables, third-party keys, and foundational configs required before running builds or tests.
1. Environment Variables
Create a .env.local
at project root:
# Supabase (client & server)
NEXT_PUBLIC_SUPABASE_URL=https://xyz.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=public-anon-key
SUPABASE_SERVICE_ROLE_KEY=service-role-secret
# Clerk (authentication)
CLERK_SECRET_KEY=sk_test_...
CLERK_PUBLISHABLE_KEY=pk_test_...
# Optional: Next.js runtime configs
NEXT_PUBLIC_APP_ENV=development
• Prefix client-facing keys with NEXT_PUBLIC_
.
• Never commit SUPABASE_SERVICE_ROLE_KEY
or CLERK_SECRET_KEY
.
2. Component Library (shadcn/ui)
components.json
defines how @/components
resolve, Tailwind CSS, RSC support and Lucide icons.
Root components.json
excerpt:
{
"$schema": "https://unpkg.com/@shadcn/ui@latest/schema.json",
"output": "src/components",
"css": "tailwind",
"rsc": true,
"aliases": {
"@/components": "src/components"
},
"icons": "lucide-react"
}
Ensure your tsconfig.json
includes the alias:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@/components": ["src/components"]
}
}
}
Generate or update components:
npx shadcn-ui add button
Import in your code:
import { Button } from "@/components";
3. ESLint Setup
eslint.config.mjs
uses Next.js recommended rules and TypeScript support:
import { FlatCompat } from "@eslint/eslintrc";
import next from "eslint-config-next";
const compat = new FlatCompat({
baseDirectory: __dirname
});
export default [
// Next.js base rules
...compat.extends("next/core-web-vitals"),
// Custom rules
{
rules: {
"@typescript-eslint/no-unused-vars": ["error"],
"react/jsx-uses-react": "off"
}
}
];
Install dependencies:
npm install -D eslint eslint-config-next @eslint/eslintrc @typescript-eslint/parser @typescript-eslint/eslint-plugin
Run lint:
npx eslint .
4. Next.js Configuration
next.config.ts
ignores type and lint errors in production builds:
import { NextConfig } from "next";
const nextConfig: NextConfig = {
eslint: { ignoreDuringBuilds: true },
typescript: { ignoreBuildErrors: true }
};
export default nextConfig;
5. Supabase Configuration
Client (browser): src/lib/supabase.ts
import { createClient } from "@supabase/supabase-js";
const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient(url, anonKey);
Server: src/lib/supabase-server.ts
import { createClient } from "@supabase/supabase-js";
const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const serviceRole = process.env.SUPABASE_SERVICE_ROLE_KEY!;
export const supabaseAdmin = createClient(url, serviceRole, {
auth: { persistSession: false }
});
Usage in API route:
import { supabaseAdmin } from "@/lib/supabase-server";
export async function GET() {
const { data } = await supabaseAdmin.from("users").select("*");
return new Response(JSON.stringify(data));
}
6. Clerk Middleware
src/middleware.ts
protects routes via Clerk:
import { authMiddleware } from "@clerk/nextjs/server";
export default authMiddleware({
publicRoutes: ["/", "/about", "/api/webhook"]
});
export const config = { matcher: ["/((?!_next/image|_next/static|favicon.ico).*)"] };
Ensure you have installed Clerk:
npm install @clerk/nextjs
With this setup, protected pages redirect to Clerk’s sign-in if unauthenticated, while listed publicRoutes
remain open.
Architecture Overview
This section describes the high-level organization of Aarogya-AI, showing how browser requests traverse the Next.js app, leverage authentication, reach API routes, and invoke external providers like OpenAI.
Application Structure
Aarogya-AI follows Next.js 13’s /app
directory convention with Server and Client Components.
Project tree (simplified):
src/
└─ app/
├─ layout.tsx # RootLayout: global providers & theming
├─ page.tsx # Home page (chat UI)
├─ globals.css # Tailwind imports, CSS variables, dark mode
└─ api/
├─ hello/route.ts # Sample GET endpoint
└─ openai/route.ts # Chat completions
└─ components/
└─ ui/ # Reusable UI primitives (Button, Input, etc.)
Request Flow
- Initial SSR
Browser requests/
. Next.js renderslayout.tsx
(providers, fonts, theme), thenpage.tsx
. - User Interaction
Client-side code inpage.tsx
(a Client Component) callsfetch('/api/openai')
on form submit. - API Route Handling
The/api/openai/route.ts
handler authenticates via Clerk (getAuth
), then calls OpenAI SDK. - Response
API returns JSON; client updates the chat UI.
Authentication Flow
Clerk provides user sessions; guard server and API routes.
In layout.tsx
:
// src/app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs'
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
)
}
Guard an API route:
// src/app/api/openai/route.ts
import { NextResponse } from 'next/server'
import { getAuth } from '@clerk/nextjs/server'
export const POST = async (req: Request) => {
const { userId } = getAuth() // throws if no session
// ...proceed with authenticated logic
return NextResponse.json({ userId })
}
API Routes
All routes use Next.js Edge Functions (default runtime). They export HTTP methods as async functions:
// src/app/api/hello/route.ts
import { NextResponse } from 'next/server'
export const GET = () => {
return NextResponse.json({ message: 'Hello from Aarogya-AI!' })
}
// src/app/api/openai/route.ts
import { NextResponse } from 'next/server'
import OpenAI from 'openai'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
export const POST = async (req: Request) => {
const { prompt } = await req.json()
const res = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
})
return NextResponse.json(res.choices[0].message)
}
OpenAI Integration
- Initialization: Use
new OpenAI({ apiKey })
. - Chat Completions: Call
openai.chat.completions.create()
withmodel
andmessages
. - Streaming (advanced): Pass
stream: true
and handlefor await (const chunk of stream)
to push partial responses to the client.
Example streaming handler:
// src/app/api/openai/stream.ts
import { NextResponse } from 'next/server'
import OpenAI from 'openai'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
export const POST = async (req: Request) => {
const { prompt } = await req.json()
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
stream: true,
})
return new NextResponse(stream) // streams chunks to client
}
Client-Server Component Boundaries
- Server Components (default in
/app
): fetch data on the server, use secret keys. - Client Components (
'use client'
at top): handle interactivity (forms, hooks). - Pass props from Server → Client; never import server-only modules (e.g.
openai
,getAuth
) in clients.
With this architecture, Aarogya-AI cleanly separates layout, styling, auth, and data-fetching logic, enabling scalable feature development. Here are the available Feature Modules in the Aarogya-AI repo. Please let me know which one you’d like detailed documentation for:
• Invoking the AI Model and Handling Responses
• Streaming Sleep Tips Endpoint (/api/sleep-tip
)
• Asha Chat API (/api/asha-chat
)
• Diet Recommender API (/api/diet-recommender
)
• Health Chat API (/api/health-chat
)
• Lab Test Explainer API (/api/lab-test-explainer
)
• Medicine Usage API (/api/medicine-usage
)
• Prescriptions API: Uploading, Fetching & Deleting Prescription Files
Just reply with the module name or endpoint, and I’ll provide a focused, hands-on guide.
Data & Storage Design
This section describes database tables, storage buckets, and Supabase helper utilities used across API routes.
Database Schema Expectations
emergency_contacts
Columns:
- id (uuid, PK)
- user_id (uuid, FK → users.id)
- name (text)
- phone (text)
- created_at (timestamp, default now())
Usage:
- POST
/api/emergency-contacts
inserts a new row. - GET filters by
user_id
. - DELETE by
id
anduser_id
.
prescriptions
Columns:
- id (uuid, PK)
- user_id (uuid, FK → users.id)
- file_name (text)
- file_path (text)
- uploaded_at (timestamp, default now())
Usage:
- POST uploads file to storage and inserts metadata.
- GET returns metadata and signed URLs.
- DELETE removes both metadata and storage object.
sleep_analyzer
Columns:
- id (uuid, PK)
- user_id (uuid, FK → users.id)
- date (date)
- sleep_duration (integer, minutes)
- created_at (timestamp, default now())
Usage:
- POST adds a record.
- GET returns records for a user, optional date filter.
Storage Bucket Usage
We use a private bucket named prescriptions
for user files.
Uploading a File
import { supabase } from '@/lib/supabase';
const bucket = supabase.storage.from('prescriptions');
const path = `${userId}/${file.name}`;
// Upload file blob or Buffer
const { error: uploadError } = await bucket.upload(path, file);
if (uploadError) throw uploadError;
// Store metadata in table
await supabase
.from('prescriptions')
.insert({ user_id: userId, file_name: file.name, file_path: path });
Generating Signed URLs
// Expires in 2 days (172800 seconds)
const { data, error } = await supabase
.storage
.from('prescriptions')
.createSignedUrl(record.file_path, 172800);
if (error) throw error;
const signedUrl = data.signedUrl;
Deleting Files
// Remove from storage
await supabase
.storage
.from('prescriptions')
.remove([record.file_path]);
// Remove metadata
await supabase
.from('prescriptions')
.delete()
.match({ id: record.id, user_id: userId });
Supabase Helper Utilities
Client-Side (src/lib/supabase.ts
)
Creates a browser/mobile-safe client.
import { createClient } from '@supabase/supabase-js';
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
Use this in React components or non-SSR code:
import { supabase } from '@/lib/supabase';
const { data, error } = await supabase
.from('sleep_analyzer')
.select('*')
.eq('user_id', user.id);
Server-Side (src/lib/supabase-server.ts
)
Initializes with JWT from incoming request for secure operations.
import { NextRequest } from 'next/server';
import { createClient } from '@supabase/supabase-js';
export function supabaseServer(req: NextRequest) {
const token = req.headers.get('authorization')?.replace('Bearer ', '');
return createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{ global: { headers: { Authorization: `Bearer ${token}` } } }
);
}
Use inside Next.js route handlers:
import { NextRequest, NextResponse } from 'next/server';
import { supabaseServer } from '@/lib/supabase-server';
export async function GET(req: NextRequest) {
const supabase = supabaseServer(req);
const user = (await supabase.auth.getUser()).data.user;
const { data } = await supabase
.from('emergency_contacts')
.select('*')
.eq('user_id', user?.id);
return NextResponse.json(data);
}
These tables, storage patterns, and helpers ensure consistent, secure data handling across the application.
Deployment & Hosting
This section explains how to build, test and deploy Aarogya-AI to Vercel or any Node-based hosting. It covers build commands, local testing, and sample configurations for production hosting.
Prerequisites
- Node.js ≥18 and npm (or yarn)
- Git access to the repository
- Environment variables (e.g., AI API keys) set in your host or Vercel dashboard
1. Building the App
Aarogya-AI uses Next.js with custom build settings in next.config.ts
:
// next.config.ts
import { NextConfig } from "next";
const nextConfig: NextConfig = {
eslint: { ignoreDuringBuilds: true },
typescript: { ignoreBuildErrors: true },
};
export default nextConfig;
Run the production build:
npm install
npm run build
Key npm scripts (package.json):
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p $PORT",
"lint": "next lint",
"type-check": "tsc --noEmit"
}
}
2. Testing Locally
Start the dev server with hot-reload and Tailwind CSS support:
npm run dev
# http://localhost:3000
Validate code quality before deploying:
npm run lint
npm run type-check
3. Deploying to Vercel
- Log into Vercel and import the GitHub repository.
- In Project Settings → Build & Development:
- Install Command:
npm install
- Build Command:
npm run build
- Output Directory:
.next
(default)
- Install Command:
- Add Environment Variables under Settings → Environment Variables.
- Deploy; Vercel automatically runs the build and serves the app.
4. Deploying to Any Node-Based Host
4.1 Direct Deployment
Clone the repo and install:
git clone https://github.com/sarvankumar-fsdp/Aarogya-AI.git cd Aarogya-AI npm ci --production npm run build
Start the server:
npm run start # Listens on PORT env or 3000
Use a process manager (e.g., PM2):
// ecosystem.config.js module.exports = { apps: [{ name: "aarogya-ai", script: "npm", args: "start", env: { PORT: 3000, NODE_ENV: "production" } }] };
pm2 start ecosystem.config.js
4.2 Docker Deployment
# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm","start"]
Build and run:
docker build -t aarogya-ai .
docker run -e PORT=3000 -p 3000:3000 aarogya-ai
5. Tailwind & PostCSS Configuration
Both are integrated into the Next.js build pipeline:
// postcss.config.mjs
export default {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};
// tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
content: ["./app/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
fontFamily: {
sans: ["Inter", "sans-serif"],
mono: ["Fira Code", "monospace"]
}
}
}
};
export default config;
Modify plugins
in postcss.config.mjs
or theme
in tailwind.config.ts
to customize styling for your deployment.
Now you can build, test and deploy Aarogya-AI on Vercel or any Node-based environment with confidence.
Development & Contribution Guide
This guide describes the standards, tools, and workflows for developing and contributing to the Aarogya-AI Next.js application.
Prerequisites
- Node.js ≥18, npm ≥8
- Familiarity with TypeScript and Next.js
Setup & Installation
Clone the repository and install dependencies:
git clone https://github.com/sarvankumar-fsdp/Aarogya-AI.git
cd Aarogya-AI
npm install
Available NPM Scripts
Reference the package.json
scripts:
npm run dev
Starts Next.js in development mode (http://localhost:3000)npm run build
Compiles and type‐checks for productionnpm run start
Serves the production buildnpm run lint
Runs ESLint across.ts
,.tsx
,.js
,.jsx
npm run lint:fix
Auto‐fixes linting errors where possible
Linting & Code Style
Aarogya-AI uses ESLint with Next.js and TypeScript support. The configuration in eslint.config.mjs
extends recommended rules and allows custom overrides:
// eslint.config.mjs
import { FlatCompat } from "@eslint/eslintrc";
const compat = new FlatCompat({ baseDirectory: import.meta.url });
export default [
// Base and Next.js rules
...compat.extends(
"eslint:recommended",
"plugin:@next/next/recommended"
),
{
parserOptions: { ecmaVersion: 2022, sourceType: "module" },
rules: {
// Example override: enforce semicolons
"semi": ["error", "always"],
// Add or customize rules here
}
}
];
Run linting:
npm run lint
npm run lint:fix
Type Checking & Compiler Options
TypeScript compiler options in tsconfig.json
enforce strict typing and modern module resolution:
{
"compilerOptions": {
"strict": true,
"target": "es2022",
"module": "esnext",
"moduleResolution": "node",
"jsx": "preserve",
"incremental": true,
"isolatedModules": true,
"noEmit": true
},
"exclude": ["node_modules"]
}
To verify types:
npm run build
Managing Dependencies
- Add a runtime dependency:
npm install <package-name>
- Add a development dependency:
npm install --save-dev <package-name>
- Check for updates:
npm outdated
- Update to latest compatible versions:
npm update
Contribution Workflow
- Fork the repository and checkout a new branch:
git checkout -b feature/your-short-description
- Implement your changes.
- Run lint and type checks locally:
npm run lint && npm run build
- Commit with a clear, imperative message (e.g., “Add user-profile chart component”).
- Push and open a PR against
main
. - Ensure CI passes (lint + build).
License
Aarogya-AI is licensed under MIT. Include the LICENSE
file in any redistribution or derivative work.
Security & Privacy
This section covers user authentication, route protection, role-based access control, legal pages integration, and secure handling of health data.
Authentication with Clerk
Aarogya.me uses Clerk for user sign-in. Customize the sign-in page in src/app/sign-in/[[...sign-in]]/page.tsx
.
Basic Sign-In Page
import { SignIn } from "@clerk/nextjs";
import { Box } from "@chakra-ui/react";
export default function SignInPage() {
return (
<Box
display="flex"
alignItems="center"
justifyContent="center"
height="100vh"
bg="gray.50"
>
<SignIn
routing={{
afterSignInUrl: "/dashboard",
signUpUrl: "/sign-up",
}}
path="/sign-in"
/>
</Box>
);
}
Customizing the Sign-In Component
Add or override fields, design system tokens, or multi-factor settings:
<SignIn
appearance={{
variables: { colorPrimary: "#2B6CB0" },
elements: {
card: "rounded-lg shadow-lg",
socialButtonsBlockButton: "bg-blue-500",
},
}}
signUpUrl="/sign-up"
afterSignInUrl="/dashboard"
/>
Route Protection with Middleware
The Clerk middleware in src/middleware.ts
enforces authentication on protected routes:
import { withClerkMiddleware, getAuth } from "@clerk/nextjs/server";
import type { NextRequest } from "next/server";
export default withClerkMiddleware((req: NextRequest) => {
// Public pages
if (req.nextUrl.pathname.startsWith("/sign-in") ||
req.nextUrl.pathname.match(/^\/(privacy-policy|terms-conditions)$/)) {
return;
}
// All other routes require auth
return getAuth({ req }).userId ? undefined : Response.redirect(new URL("/sign-in", req.url));
});
export const config = { matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"] };
Role-Based Access Control (RBAC)
Use Clerk’s getAuth
or requireAuth
to enforce roles on server-side routes and API endpoints.
Protecting an API Route
import { NextResponse } from "next/server";
import { getAuth } from "@clerk/nextjs/server";
// Only users with the "doctor" role can access patient data
export async function GET(req: Request, { params }: { params: { id: string } }) {
const { userId, orgRole } = getAuth({ req });
if (!userId || orgRole !== "doctor") {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
}
const patientRecord = await fetchPatientRecord(params.id);
return NextResponse.json(patientRecord);
}
Checking Roles in Server Components
import { getAuth } from "@clerk/nextjs/server";
export default async function Dashboard() {
const { userId, claims } = getAuth();
if (!userId) throw new Error("Not authenticated");
const isDoctor = claims.orgRole === "doctor";
return (
<div>
<h1>Welcome, {isDoctor ? "Doctor" : "Patient"}</h1>
{/* Render doctor-only tools */}
{isDoctor && <DoctorTools />}
</div>
);
}
Legal Pages
Privacy Policy
Path: src/app/privacy-policy/page.tsx
Renders data collection details, user rights, and security measures.
export default function PrivacyPolicy() {
return (
<article className="prose mx-auto my-10">
<h1>Privacy Policy</h1>
<p>Your health data is encrypted in transit and stored securely. You can request a data export or deletion at any time.</p>
{/* Sections on cookies, third-party services, updates */}
</article>
);
}
Terms & Conditions
Path: src/app/terms-conditions/page.tsx
Outlines platform use, responsibilities, and policy links.
import Link from "next/link";
export default function TermsConditions() {
return (
<article className="prose mx-auto my-10">
<h1>Terms & Conditions</h1>
<p>By using Aarogya.me, you agree to our <Link href="/privacy-policy">Privacy Policy</Link>.</p>
{/* Add sections on user obligations, updates, contacts */}
</article>
);
}
Include links to these pages in your global layout or footer for compliance:
import Link from "next/link";
export default function Footer() {
return (
<footer className="text-center py-6">
<Link href="/privacy-policy" className="mx-4">Privacy Policy</Link>
<Link href="/terms-conditions" className="mx-4">Terms & Conditions</Link>
</footer>
);
}
Secure Handling of Health Data
- Always use HTTPS (Next.js defaults to secure).
- Fetch sensitive data server-side (API routes or
getServerSideProps
/server components) to avoid exposing secrets. - Sanitize and validate all inputs in API routes.
- Log access events for audit trails (e.g., wrap data fetch calls in logging middleware).
Example logging middleware for API routes:
import type { NextRequest } from "next/server";
export function logAccess(req: NextRequest) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
}
Apply in an API route:
import { logAccess } from "@/lib/logging";
export async function GET(req: Request, { params }: { params: { id: string } }) {
logAccess(new Request(req));
// ... authorization and data fetch
}
This setup ensures authenticated, role-aware access, transparent legal compliance, and secure treatment of user health information.