@ratim818/allyve-wellness-backend 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example ADDED
@@ -0,0 +1,49 @@
1
+ # ============================================
2
+ # ALLYVE WELLNESS AI — BACKEND CONFIGURATION
3
+ # HIPAA-Compliant Environment Variables
4
+ # ============================================
5
+ # IMPORTANT: Never commit this file to version control.
6
+ # Copy to .env and fill in your values.
7
+
8
+ # ── Server ────────────────────────────────────
9
+ NODE_ENV=development
10
+ PORT=3001
11
+ API_VERSION=v1
12
+ CORS_ORIGIN=http://localhost:5173
13
+
14
+ # ── Database (PostgreSQL with SSL) ────────────
15
+ # Use a HIPAA-eligible provider: AWS RDS, GCP Cloud SQL, Azure DB, or Supabase Pro
16
+ DATABASE_URL=postgresql://allyve_user:STRONG_PASSWORD@localhost:5432/allyve_wellness
17
+ DATABASE_SSL=false
18
+ DATABASE_POOL_MIN=2
19
+ DATABASE_POOL_MAX=10
20
+
21
+ # ── Encryption ────────────────────────────────
22
+ # AES-256 key for encrypting PHI at rest (generate with: openssl rand -hex 32)
23
+ ENCRYPTION_KEY=GENERATE_WITH_openssl_rand_hex_32
24
+ ENCRYPTION_IV_LENGTH=16
25
+
26
+ # ── Authentication ────────────────────────────
27
+ # JWT secret (generate with: openssl rand -base64 64)
28
+ JWT_SECRET=GENERATE_WITH_openssl_rand_base64_64
29
+ JWT_EXPIRES_IN=15m
30
+ JWT_REFRESH_EXPIRES_IN=7d
31
+
32
+ # ── Session ───────────────────────────────────
33
+ SESSION_SECRET=GENERATE_WITH_openssl_rand_base64_32
34
+ SESSION_MAX_AGE=900000
35
+
36
+ # ── HIPAA Audit ───────────────────────────────
37
+ AUDIT_LOG_RETENTION_DAYS=2190
38
+ AUDIT_LOG_LEVEL=info
39
+
40
+ # ── Rate Limiting ─────────────────────────────
41
+ RATE_LIMIT_WINDOW_MS=900000
42
+ RATE_LIMIT_MAX_REQUESTS=100
43
+
44
+ # ── Wearable Integration (future) ────────────
45
+ # APPLE_HEALTHKIT_KEY=
46
+ # GOOGLE_FIT_CLIENT_ID=
47
+ # GOOGLE_FIT_CLIENT_SECRET=
48
+ # FITBIT_CLIENT_ID=
49
+ # FITBIT_CLIENT_SECRET=
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ build-and-test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [18, 20]
16
+
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js ${{ matrix.node-version }}
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: ${{ matrix.node-version }}
25
+ cache: 'npm'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci
29
+
30
+ - name: Build
31
+ run: npm run build
32
+
33
+ - name: Run tests
34
+ run: npx vitest run --passWithNoTests
@@ -0,0 +1,81 @@
1
+ name: Publish Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout repository
12
+ uses: actions/checkout@v4
13
+
14
+ - name: Setup Node.js
15
+ uses: actions/setup-node@v4
16
+ with:
17
+ node-version: 20
18
+ cache: 'npm'
19
+
20
+ - name: Install dependencies
21
+ run: npm ci
22
+
23
+ - name: Build
24
+ run: npm run build
25
+
26
+ - name: Run tests
27
+ run: npx vitest run --passWithNoTests
28
+
29
+ publish-npm:
30
+ needs: build
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - name: Checkout repository
34
+ uses: actions/checkout@v4
35
+
36
+ - name: Setup Node.js for npm
37
+ uses: actions/setup-node@v4
38
+ with:
39
+ node-version: 20
40
+ registry-url: 'https://registry.npmjs.org'
41
+ cache: 'npm'
42
+
43
+ - name: Install dependencies
44
+ run: npm ci
45
+
46
+ - name: Build
47
+ run: npm run build
48
+
49
+ - name: Publish to npm
50
+ run: npm publish --access public
51
+ env:
52
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
53
+
54
+ publish-gpr:
55
+ needs: build
56
+ runs-on: ubuntu-latest
57
+ permissions:
58
+ contents: read
59
+ packages: write
60
+ steps:
61
+ - name: Checkout repository
62
+ uses: actions/checkout@v4
63
+
64
+ - name: Setup Node.js for GitHub Packages
65
+ uses: actions/setup-node@v4
66
+ with:
67
+ node-version: 20
68
+ registry-url: 'https://npm.pkg.github.com'
69
+ scope: '@ratim818'
70
+ cache: 'npm'
71
+
72
+ - name: Install dependencies
73
+ run: npm ci
74
+
75
+ - name: Build
76
+ run: npm run build
77
+
78
+ - name: Publish to GitHub Packages
79
+ run: npm publish
80
+ env:
81
+ NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # 🩺 Allyve Wellness AI — HIPAA-Compliant Backend
2
+
3
+ Production-grade backend for the Allyve maternal health monitoring platform.
4
+ Built with Express, TypeScript, PostgreSQL, and full HIPAA technical safeguards.
5
+
6
+ ## Quick Start
7
+
8
+ ### Prerequisites
9
+
10
+ - **Node.js** ≥ 18
11
+ - **PostgreSQL** ≥ 15
12
+ - **OpenSSL** (for generating keys)
13
+
14
+ ### 1. Install dependencies
15
+
16
+ ```bash
17
+ npm install
18
+ ```
19
+
20
+ ### 2. Configure environment
21
+
22
+ ```bash
23
+ cp .env.example .env
24
+ ```
25
+
26
+ Generate your secrets:
27
+ ```bash
28
+ # Encryption key (AES-256 — 32 bytes)
29
+ openssl rand -hex 32
30
+
31
+ # JWT secret
32
+ openssl rand -base64 64
33
+
34
+ # Session secret
35
+ openssl rand -base64 32
36
+ ```
37
+
38
+ Paste these into your `.env` file.
39
+
40
+ ### 3. Create the database
41
+
42
+ ```bash
43
+ createdb allyve_wellness
44
+ ```
45
+
46
+ ### 4. Run migrations
47
+
48
+ ```bash
49
+ npm run migrate
50
+ ```
51
+
52
+ ### 5. Seed demo data (optional)
53
+
54
+ ```bash
55
+ npm run seed
56
+ ```
57
+
58
+ Demo login: `sarah.johnson@example.com` / `SecureDemo123!`
59
+
60
+ ### 6. Start the server
61
+
62
+ ```bash
63
+ npm run dev
64
+ ```
65
+
66
+ Server starts at `http://localhost:3001`. API docs at `http://localhost:3001/api/v1`.
67
+
68
+ ---
69
+
70
+ ## Architecture
71
+
72
+ ```
73
+ src/
74
+ ├── config/ # Environment config, database connection
75
+ ├── middleware/ # Auth (JWT), security (Helmet, CORS, rate limiting)
76
+ ├── migrations/ # Database schema, seed data
77
+ ├── routes/ # API endpoints (auth, health, appointments, sharing, audit)
78
+ ├── services/ # Core logic (auth, encryption, audit trail)
79
+ ├── utils/ # Logger (HIPAA-compliant, no PHI in logs)
80
+ └── server.ts # Express app entry point
81
+ ```
82
+
83
+ ## HIPAA Safeguards
84
+
85
+ | Safeguard | Implementation |
86
+ |---|---|
87
+ | **Encryption at rest** | AES-256-GCM on all PHI fields |
88
+ | **Encryption in transit** | HSTS, TLS required in production |
89
+ | **Authentication** | JWT + bcrypt (12 rounds) + account lockout |
90
+ | **Access control** | RBAC (patient/provider/admin) + ownership checks |
91
+ | **Audit trail** | Immutable PostgreSQL table with DB-level triggers |
92
+ | **Session management** | 15-min timeout, sliding window, revocation |
93
+ | **Input validation** | Zod schemas on every endpoint |
94
+ | **Rate limiting** | 100 req/15min general, 10/15min for auth |
95
+
96
+ See `docs/HIPAA_COMPLIANCE.md` for the full compliance reference.
97
+
98
+ ## Connecting the Frontend
99
+
100
+ Copy `docs/frontend-api-client.ts` into your Lovable frontend at `src/services/api.ts`.
101
+
102
+ Add to your frontend `.env`:
103
+ ```
104
+ VITE_API_URL=http://localhost:3001/api/v1
105
+ ```
106
+
107
+ Then update your components to import from `services/api` instead of `data/mockData`.
108
+
109
+ ---
110
+
111
+ ## API Endpoints
112
+
113
+ | Method | Endpoint | Auth | Description |
114
+ |---|---|---|---|
115
+ | POST | /auth/register | ✗ | Create account |
116
+ | POST | /auth/login | ✗ | Login → JWT tokens |
117
+ | POST | /auth/refresh | ✗ | Refresh access token |
118
+ | POST | /auth/logout | ✓ | Logout + revoke session |
119
+ | GET | /auth/me | ✓ | Current user profile |
120
+ | GET | /health/metrics | ✓ | List health metrics |
121
+ | POST | /health/metrics | ✓ | Record health metric |
122
+ | GET | /health/symptoms | ✓ | List symptoms |
123
+ | POST | /health/symptoms | ✓ | Record symptom |
124
+ | GET | /health/mood | ✓ | List mood entries |
125
+ | POST | /health/mood | ✓ | Record mood |
126
+ | GET | /health/journal | ✓ | List journal entries |
127
+ | POST | /health/journal | ✓ | Record journal entry |
128
+ | GET | /health/cardiovascular-risk | ✓ | Latest CV risk |
129
+ | GET | /appointments | ✓ | List appointments |
130
+ | POST | /appointments | ✓ | Create appointment |
131
+ | PUT | /appointments/:id | ✓ | Update appointment |
132
+ | DELETE | /appointments/:id | ✓ | Soft-delete appointment |
133
+ | GET | /share | ✓ | List shared data |
134
+ | POST | /share | ✓ | Share data + consent |
135
+ | POST | /share/:id/revoke | ✓ | Revoke sharing |
136
+ | GET | /audit/logs | ✓ admin | Query audit trail |
137
+
138
+ ## License
139
+
140
+ Proprietary — Allyve Wellness AI
@@ -0,0 +1,141 @@
1
+ # Allyve Wellness AI — HIPAA Compliance Reference
2
+
3
+ ## Overview
4
+
5
+ This backend implements the **HIPAA Security Rule** technical safeguards
6
+ (45 CFR §164.312) for protecting electronic Protected Health Information (ePHI).
7
+
8
+ ---
9
+
10
+ ## Technical Safeguards Implemented
11
+
12
+ ### §164.312(a)(1) — Access Control
13
+
14
+ | Requirement | Implementation |
15
+ |---|---|
16
+ | Unique user identification | UUID-based user IDs, unique email (HMAC-indexed) |
17
+ | Emergency access procedure | `EMERGENCY_ACCESS` audit action, admin override role |
18
+ | Automatic logoff | 15-min session timeout with sliding window |
19
+ | Encryption/decryption | AES-256-GCM for all PHI at rest |
20
+
21
+ **Files:** `middleware/auth.ts`, `services/encryption.ts`, `services/auth.ts`
22
+
23
+ ### §164.312(b) — Audit Controls
24
+
25
+ | Requirement | Implementation |
26
+ |---|---|
27
+ | Hardware/software/procedure audit | Immutable `audit_logs` table with DB-level triggers |
28
+ | Tamper evidence | PostgreSQL triggers prevent UPDATE/DELETE on audit_logs |
29
+ | 6-year retention | Configurable retention, default 2190 days (6 years) |
30
+ | Audit trail contents | WHO, WHAT, WHEN, WHERE, OUTCOME for every action |
31
+
32
+ **Files:** `services/audit.ts`, `routes/audit.ts`, `migrations/schema.ts`
33
+
34
+ ### §164.312(c)(1) — Integrity Controls
35
+
36
+ | Requirement | Implementation |
37
+ |---|---|
38
+ | Data integrity | AES-256-GCM provides authenticated encryption (tamper detection) |
39
+ | Soft deletes | `is_deleted` flags — no hard deletes of PHI |
40
+ | Input validation | Zod schemas on all API inputs |
41
+
42
+ **Files:** `services/encryption.ts`, `routes/health.ts`
43
+
44
+ ### §164.312(d) — Authentication
45
+
46
+ | Requirement | Implementation |
47
+ |---|---|
48
+ | Person/entity authentication | JWT tokens (short-lived) + refresh tokens |
49
+ | Password requirements | 12+ chars, upper, lower, number, special character |
50
+ | Account lockout | 5 failed attempts → 30-minute lockout |
51
+ | Brute force protection | Rate limiting (10 auth requests / 15 min) |
52
+
53
+ **Files:** `services/auth.ts`, `middleware/security.ts`
54
+
55
+ ### §164.312(e)(1) — Transmission Security
56
+
57
+ | Requirement | Implementation |
58
+ |---|---|
59
+ | Encryption in transit | HSTS headers, TLS required in production |
60
+ | Integrity controls | Helmet security headers, CORS restrictions |
61
+ | Cookie security | httpOnly, secure, sameSite=strict |
62
+
63
+ **Files:** `middleware/security.ts`
64
+
65
+ ---
66
+
67
+ ## Data Encryption Map
68
+
69
+ | Data Field | Storage | Encryption |
70
+ |---|---|---|
71
+ | Email | `email_encrypted` | AES-256-GCM |
72
+ | Email (lookup) | `email_hash` | HMAC-SHA256 |
73
+ | Password | `password_hash` | bcrypt (12 rounds) |
74
+ | Full name | `full_name_encrypted` | AES-256-GCM |
75
+ | Date of birth | `date_of_birth_encrypted` | AES-256-GCM |
76
+ | Phone number | `phone_encrypted` | AES-256-GCM |
77
+ | Health metric values | `value_encrypted` | AES-256-GCM |
78
+ | ECG waveform data | `waveform_encrypted` | AES-256-GCM |
79
+ | Symptom notes | `notes_encrypted` | AES-256-GCM |
80
+ | Mood notes | `notes_encrypted` | AES-256-GCM |
81
+ | Journal content | `content_encrypted` | AES-256-GCM |
82
+ | Appointment location | `location_encrypted` | AES-256-GCM |
83
+ | Provider contact info | `*_encrypted` | AES-256-GCM |
84
+
85
+ ---
86
+
87
+ ## Remaining Steps for Full HIPAA Compliance
88
+
89
+ > ⚠️ **This codebase provides the technical safeguards. Full HIPAA compliance
90
+ > also requires administrative and physical safeguards.**
91
+
92
+ ### Before Production
93
+
94
+ - [ ] **Business Associate Agreement (BAA)** — Sign with your cloud provider
95
+ (AWS, GCP, Azure, or Supabase Pro all offer HIPAA BAAs)
96
+ - [ ] **SSL/TLS Certificate** — Enforce HTTPS in production (nginx/Caddy/CloudFront)
97
+ - [ ] **Database encryption at rest** — Enable at the infrastructure level
98
+ (AWS RDS encryption, GCP Cloud SQL encryption)
99
+ - [ ] **Key management** — Move `ENCRYPTION_KEY` to a KMS (AWS KMS, GCP KMS, HashiCorp Vault)
100
+ - [ ] **Backup encryption** — All database backups must be encrypted
101
+ - [ ] **Penetration testing** — Annual security assessment
102
+ - [ ] **Risk assessment** — Document threats, vulnerabilities, and mitigations
103
+ - [ ] **Workforce training** — All team members handling PHI must be trained
104
+ - [ ] **Incident response plan** — Document breach notification procedures
105
+ - [ ] **Privacy officer** — Designate a HIPAA privacy officer
106
+
107
+ ### Administrative Safeguards (Organizational)
108
+
109
+ - [ ] Written security policies and procedures
110
+ - [ ] Workforce access management procedures
111
+ - [ ] Security incident response procedures
112
+ - [ ] Contingency / disaster recovery plan
113
+ - [ ] Regular security evaluations
114
+
115
+ ### Physical Safeguards
116
+
117
+ - [ ] Facility access controls (if self-hosting)
118
+ - [ ] Workstation security policies
119
+ - [ ] Device and media disposal procedures
120
+
121
+ ---
122
+
123
+ ## API Security Headers
124
+
125
+ All responses include these security headers (via Helmet):
126
+
127
+ ```
128
+ Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
129
+ X-Content-Type-Options: nosniff
130
+ X-Frame-Options: DENY
131
+ X-XSS-Protection: 1; mode=block
132
+ Content-Security-Policy: default-src 'self'
133
+ Referrer-Policy: strict-origin-when-cross-origin
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Contact
139
+
140
+ For HIPAA compliance questions or to report a security concern,
141
+ contact your designated Security Officer.
@@ -0,0 +1,259 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════
3
+ * ALLYVE API CLIENT
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * Drop this file into your Lovable frontend at:
6
+ * src/services/api.ts
7
+ *
8
+ * Then update your hooks and components to use these functions
9
+ * instead of importing from data/mockData.ts.
10
+ * ═══════════════════════════════════════════════════════════════
11
+ */
12
+
13
+ const API_BASE = import.meta.env.VITE_API_URL || "http://localhost:3001/api/v1";
14
+
15
+ // ── Token Management ────────────────────────────────────────
16
+
17
+ let accessToken: string | null = null;
18
+
19
+ export function setAccessToken(token: string | null) {
20
+ accessToken = token;
21
+ }
22
+
23
+ export function getAccessToken(): string | null {
24
+ return accessToken;
25
+ }
26
+
27
+ // ── HTTP Client with Auto-Refresh ───────────────────────────
28
+
29
+ async function apiRequest<T>(
30
+ endpoint: string,
31
+ options: RequestInit = {}
32
+ ): Promise<T> {
33
+ const url = `${API_BASE}${endpoint}`;
34
+
35
+ const headers: Record<string, string> = {
36
+ "Content-Type": "application/json",
37
+ ...(options.headers as Record<string, string>),
38
+ };
39
+
40
+ if (accessToken) {
41
+ headers["Authorization"] = `Bearer ${accessToken}`;
42
+ }
43
+
44
+ let response = await fetch(url, { ...options, headers, credentials: "include" });
45
+
46
+ // Auto-refresh on 401 with TOKEN_EXPIRED
47
+ if (response.status === 401) {
48
+ const body = await response.json();
49
+ if (body.code === "TOKEN_EXPIRED") {
50
+ const refreshed = await refreshToken();
51
+ if (refreshed) {
52
+ headers["Authorization"] = `Bearer ${accessToken}`;
53
+ response = await fetch(url, { ...options, headers, credentials: "include" });
54
+ }
55
+ }
56
+ }
57
+
58
+ if (!response.ok) {
59
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
60
+ throw new Error(error.error || `HTTP ${response.status}`);
61
+ }
62
+
63
+ return response.json();
64
+ }
65
+
66
+ // ── Auth API ────────────────────────────────────────────────
67
+
68
+ export async function login(email: string, password: string) {
69
+ const data = await apiRequest<{ accessToken: string; expiresIn: string }>("/auth/login", {
70
+ method: "POST",
71
+ body: JSON.stringify({ email, password }),
72
+ });
73
+ setAccessToken(data.accessToken);
74
+ return data;
75
+ }
76
+
77
+ export async function register(data: {
78
+ email: string;
79
+ password: string;
80
+ fullName: string;
81
+ dateOfBirth: string;
82
+ phone?: string;
83
+ }) {
84
+ return apiRequest<{ userId: string }>("/auth/register", {
85
+ method: "POST",
86
+ body: JSON.stringify(data),
87
+ });
88
+ }
89
+
90
+ export async function refreshToken(): Promise<boolean> {
91
+ try {
92
+ const data = await apiRequest<{ accessToken: string }>("/auth/refresh", {
93
+ method: "POST",
94
+ });
95
+ setAccessToken(data.accessToken);
96
+ return true;
97
+ } catch {
98
+ setAccessToken(null);
99
+ return false;
100
+ }
101
+ }
102
+
103
+ export async function logout() {
104
+ try {
105
+ await apiRequest("/auth/logout", { method: "POST" });
106
+ } finally {
107
+ setAccessToken(null);
108
+ }
109
+ }
110
+
111
+ export async function getProfile() {
112
+ return apiRequest<{
113
+ id: string;
114
+ email: string;
115
+ fullName: string;
116
+ dateOfBirth: string;
117
+ phone: string | null;
118
+ pregnancyWeek: number | null;
119
+ role: string;
120
+ }>("/auth/me");
121
+ }
122
+
123
+ // ── Health Metrics API ──────────────────────────────────────
124
+
125
+ export async function getHealthMetrics(params?: { limit?: number; metric?: string; since?: string }) {
126
+ const query = new URLSearchParams();
127
+ if (params?.limit) query.set("limit", String(params.limit));
128
+ if (params?.metric) query.set("metric", params.metric);
129
+ if (params?.since) query.set("since", params.since);
130
+
131
+ return apiRequest<{ data: any[]; total: number }>(`/health/metrics?${query}`);
132
+ }
133
+
134
+ export async function recordHealthMetric(data: {
135
+ metricName: string;
136
+ value: number | string;
137
+ unit: string;
138
+ status: "normal" | "warning" | "critical" | "unknown";
139
+ trend?: string;
140
+ }) {
141
+ return apiRequest<{ id: string }>("/health/metrics", {
142
+ method: "POST",
143
+ body: JSON.stringify(data),
144
+ });
145
+ }
146
+
147
+ // ── Symptoms API ────────────────────────────────────────────
148
+
149
+ export async function getSymptoms(limit?: number) {
150
+ return apiRequest<{ data: any[] }>(`/health/symptoms?limit=${limit || 50}`);
151
+ }
152
+
153
+ export async function recordSymptom(data: {
154
+ name: string;
155
+ severity: number;
156
+ notes?: string;
157
+ isCardiovascularRelated: boolean;
158
+ }) {
159
+ return apiRequest<{ id: string }>("/health/symptoms", {
160
+ method: "POST",
161
+ body: JSON.stringify(data),
162
+ });
163
+ }
164
+
165
+ // ── Mood API ────────────────────────────────────────────────
166
+
167
+ export async function getMoodEntries(limit?: number) {
168
+ return apiRequest<{ data: any[] }>(`/health/mood?limit=${limit || 50}`);
169
+ }
170
+
171
+ export async function recordMood(data: {
172
+ mood: string;
173
+ notes?: string;
174
+ anxietyLevel?: number;
175
+ }) {
176
+ return apiRequest<{ id: string }>("/health/mood", {
177
+ method: "POST",
178
+ body: JSON.stringify(data),
179
+ });
180
+ }
181
+
182
+ // ── Journal API ─────────────────────────────────────────────
183
+
184
+ export async function getJournalEntries(limit?: number) {
185
+ return apiRequest<{ data: any[] }>(`/health/journal?limit=${limit || 50}`);
186
+ }
187
+
188
+ export async function recordJournalEntry(data: {
189
+ content: string;
190
+ tags?: string[];
191
+ painScore?: number;
192
+ anxietyLevel?: number;
193
+ }) {
194
+ return apiRequest<{ id: string }>("/health/journal", {
195
+ method: "POST",
196
+ body: JSON.stringify(data),
197
+ });
198
+ }
199
+
200
+ // ── Cardiovascular Risk API ─────────────────────────────────
201
+
202
+ export async function getCardiovascularRisk() {
203
+ return apiRequest<{ data: any }>("/health/cardiovascular-risk");
204
+ }
205
+
206
+ // ── Appointments API ────────────────────────────────────────
207
+
208
+ export async function getAppointments() {
209
+ return apiRequest<{ data: any[] }>("/appointments");
210
+ }
211
+
212
+ export async function createAppointment(data: {
213
+ title: string;
214
+ providerName: string;
215
+ providerType: string;
216
+ date: string;
217
+ location?: string;
218
+ notes?: string;
219
+ isTelehealth?: boolean;
220
+ }) {
221
+ return apiRequest<{ id: string }>("/appointments", {
222
+ method: "POST",
223
+ body: JSON.stringify(data),
224
+ });
225
+ }
226
+
227
+ export async function updateAppointment(id: string, data: Record<string, unknown>) {
228
+ return apiRequest(`/appointments/${id}`, {
229
+ method: "PUT",
230
+ body: JSON.stringify(data),
231
+ });
232
+ }
233
+
234
+ export async function deleteAppointment(id: string) {
235
+ return apiRequest(`/appointments/${id}`, { method: "DELETE" });
236
+ }
237
+
238
+ // ── Data Sharing API ────────────────────────────────────────
239
+
240
+ export async function getSharedData() {
241
+ return apiRequest<{ data: any[] }>("/share");
242
+ }
243
+
244
+ export async function shareData(data: {
245
+ recipientName: string;
246
+ recipientType: "provider" | "family" | "other";
247
+ recipientEmail?: string;
248
+ dataTypes: string[];
249
+ expiresInDays?: number;
250
+ }) {
251
+ return apiRequest<{ id: string }>("/share", {
252
+ method: "POST",
253
+ body: JSON.stringify(data),
254
+ });
255
+ }
256
+
257
+ export async function revokeShare(id: string) {
258
+ return apiRequest(`/share/${id}/revoke`, { method: "POST" });
259
+ }