opencard 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.
Files changed (52) hide show
  1. package/API.md +564 -0
  2. package/DATABASE.md +143 -0
  3. package/README.md +106 -0
  4. package/admin/index.html +18 -0
  5. package/admin/package-lock.json +2663 -0
  6. package/admin/package.json +25 -0
  7. package/admin/postcss.config.js +6 -0
  8. package/admin/src/App.tsx +198 -0
  9. package/admin/src/index.css +44 -0
  10. package/admin/src/main.tsx +10 -0
  11. package/admin/src/pages/Cards.tsx +181 -0
  12. package/admin/src/pages/Dashboard.tsx +139 -0
  13. package/admin/src/pages/Transactions.tsx +223 -0
  14. package/admin/tailwind.config.js +27 -0
  15. package/admin/tsconfig.json +20 -0
  16. package/admin/tsconfig.tsbuildinfo +1 -0
  17. package/admin/vite.config.ts +17 -0
  18. package/drizzle.config.ts +11 -0
  19. package/examples/agent-client-sdk.ts +36 -0
  20. package/examples/agent-client.ts +111 -0
  21. package/examples/agent-fund-sdk.ts +35 -0
  22. package/package.json +41 -0
  23. package/sdk/README.md +139 -0
  24. package/sdk/package-lock.json +240 -0
  25. package/sdk/package.json +43 -0
  26. package/sdk/src/client.ts +194 -0
  27. package/sdk/src/errors.ts +66 -0
  28. package/sdk/src/index.ts +35 -0
  29. package/sdk/src/types.ts +138 -0
  30. package/sdk/src/x402.ts +158 -0
  31. package/sdk/tsconfig.json +20 -0
  32. package/src/config/env.ts +45 -0
  33. package/src/config/tiers.ts +51 -0
  34. package/src/db/index.ts +9 -0
  35. package/src/db/migrate.ts +16 -0
  36. package/src/db/schema.ts +82 -0
  37. package/src/index.ts +89 -0
  38. package/src/middleware/errorHandler.ts +27 -0
  39. package/src/middleware/rateLimit.ts +54 -0
  40. package/src/middleware/walletAuth.ts +89 -0
  41. package/src/middleware/x402.ts +194 -0
  42. package/src/routes/admin.ts +150 -0
  43. package/src/routes/cards.ts +120 -0
  44. package/src/routes/paid.ts +154 -0
  45. package/src/routes/public.ts +40 -0
  46. package/src/services/cardService.ts +395 -0
  47. package/src/services/kripicard.ts +128 -0
  48. package/src/services/walletService.ts +78 -0
  49. package/src/types/index.ts +128 -0
  50. package/src/utils/logger.ts +19 -0
  51. package/src/utils/pricing.ts +75 -0
  52. package/tsconfig.json +21 -0
package/API.md ADDED
@@ -0,0 +1,564 @@
1
+ # OpenCard API Documentation
2
+
3
+ **Base URL**: `http://localhost:3000` (development) | `https://your-domain.com` (production)
4
+
5
+ ---
6
+
7
+ ## Authentication
8
+
9
+ OpenCard uses two authentication modes:
10
+
11
+ ### 1. x402 Payment (Paid Endpoints)
12
+
13
+ This flow is designed for **AI agents** to autonomously pay for services.
14
+
15
+ 1. **Agent Request**: `POST /cards/create/tier/10` (no payment)
16
+ 2. **Server Response**: `402 Payment Required`
17
+ ```json
18
+ {
19
+ "x402Version": 1,
20
+ "accepts": [
21
+ {
22
+ "scheme": "exact",
23
+ "network": "eip155:8453", // Base Mainnet
24
+ "asset": "0x8335...2913", // USDC Contract
25
+ "maxAmountRequired": "17200000", // 17.20 USDC (6 decimals)
26
+ "payTo": "0x3Be8...c288" // Treasury Address
27
+ }
28
+ ]
29
+ }
30
+ ```
31
+ 3. **Agent Action**: Parse `accepts`, send 17.20 USDC to `payTo` on Base.
32
+ 4. **Agent Retry**: Resend request with `X-Payment` header:
33
+ ```json
34
+ // Header value is base64-encoded JSON:
35
+ {
36
+ "scheme": "exact",
37
+ "network": "eip155:8453",
38
+ "payload": {
39
+ "authorization": {
40
+ "from": "0xAgentAddress",
41
+ "to": "0xTreasuryAddress",
42
+ "value": "17200000"
43
+ },
44
+ "txHash": "0xTxHash..."
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### 2. Wallet Signature (Free Endpoints)
50
+
51
+ Sign an EIP-712 typed message and include these headers:
52
+
53
+ | Header | Description |
54
+ | -------------------- | ----------------------------------------- |
55
+ | `X-WALLET-ADDRESS` | Your `0x...` wallet address |
56
+ | `X-WALLET-SIGNATURE` | EIP-712 signature |
57
+ | `X-WALLET-TIMESTAMP` | Unix timestamp (must be within 5 minutes) |
58
+
59
+ **EIP-712 Domain:**
60
+
61
+ ```json
62
+ {
63
+ "name": "OpenCard",
64
+ "version": "1",
65
+ "chainId": 8453
66
+ }
67
+ ```
68
+
69
+ **EIP-712 Types:**
70
+
71
+ ```json
72
+ {
73
+ "Auth": [
74
+ { "name": "action", "type": "string" },
75
+ { "name": "timestamp", "type": "uint256" }
76
+ ]
77
+ }
78
+ ```
79
+
80
+ **Message:**
81
+
82
+ ```json
83
+ {
84
+ "action": "opencard-auth",
85
+ "timestamp": 1707600000
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Public Endpoints
92
+
93
+ ### `GET /health`
94
+
95
+ Health check.
96
+
97
+ **Response** `200`:
98
+
99
+ ```json
100
+ {
101
+ "status": "ok",
102
+ "timestamp": "2026-02-11T14:00:00.000Z",
103
+ "version": "1.0.0"
104
+ }
105
+ ```
106
+
107
+ ---
108
+
109
+ ### `GET /pricing`
110
+
111
+ Returns full pricing breakdown for all tiers.
112
+
113
+ **Response** `200`:
114
+
115
+ ```json
116
+ {
117
+ "creation": {
118
+ "tiers": [
119
+ {
120
+ "loadAmount": 10,
121
+ "totalCost": 17.2,
122
+ "issuanceFee": 3.0,
123
+ "topUpFee": 2.2,
124
+ "ourFee": 2.0,
125
+ "endpoint": "/cards/create/tier/10"
126
+ }
127
+ ]
128
+ },
129
+ "funding": {
130
+ "tiers": [
131
+ {
132
+ "fundAmount": 10,
133
+ "totalCost": 14.2,
134
+ "topUpFee": 2.2,
135
+ "ourFee": 2.0,
136
+ "endpoint": "/cards/fund/tier/10"
137
+ }
138
+ ]
139
+ }
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ### `GET /cards/tiers`
146
+
147
+ Returns available tiers with endpoints and fee breakdowns.
148
+
149
+ **Response** `200`:
150
+
151
+ ```json
152
+ {
153
+ "creation": [
154
+ {
155
+ "loadAmount": 10,
156
+ "totalCost": 17.2,
157
+ "endpoint": "/cards/create/tier/10",
158
+ "breakdown": {
159
+ "cardLoad": 10,
160
+ "issuanceFee": 3,
161
+ "topUpFee": 2.2,
162
+ "ourFee": 2,
163
+ "buffer": 0
164
+ }
165
+ }
166
+ ],
167
+ "funding": [
168
+ {
169
+ "fundAmount": 10,
170
+ "totalCost": 14.2,
171
+ "endpoint": "/cards/fund/tier/10",
172
+ "breakdown": {
173
+ "fundAmount": 10,
174
+ "topUpFee": 2.2,
175
+ "ourFee": 2
176
+ }
177
+ }
178
+ ]
179
+ }
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Paid Endpoints (x402)
185
+
186
+ These endpoints require USDC payment via the x402 protocol on Base.
187
+
188
+ ### `POST /cards/create/tier/:amount`
189
+
190
+ Create a new virtual card loaded with the specified tier amount.
191
+
192
+ **Available tiers**: `10`, `25`, `50`, `100`, `200`, `500`
193
+
194
+ **Request Body:**
195
+
196
+ ```json
197
+ {
198
+ "nameOnCard": "JOHN DOE",
199
+ "email": "john@example.com"
200
+ }
201
+ ```
202
+
203
+ **402 Response** (when no payment provided):
204
+
205
+ ```json
206
+ {
207
+ "x402Version": 1,
208
+ "accepts": [
209
+ {
210
+ "scheme": "exact",
211
+ "network": "eip155:8453",
212
+ "maxAmountRequired": "17200000",
213
+ "resource": "/cards/create/tier/10",
214
+ "description": "Create card with $10 load",
215
+ "payTo": "0x3Be892b244B7CE6731A297A7eBca16F16f27c288",
216
+ "maxTimeoutSeconds": 300,
217
+ "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
218
+ }
219
+ ]
220
+ }
221
+ ```
222
+
223
+ **Success Response** `201`:
224
+
225
+ ```json
226
+ {
227
+ "success": true,
228
+ "card": {
229
+ "cardId": "uuid",
230
+ "kripiCardId": "kc_123",
231
+ "nameOnCard": "JOHN DOE",
232
+ "balance": 10,
233
+ "status": "active",
234
+ "createdAt": "2026-02-11T14:00:00.000Z"
235
+ },
236
+ "payment": {
237
+ "amountCharged": 17.2,
238
+ "txHash": "0x...",
239
+ "network": "base"
240
+ },
241
+ "details": {
242
+ "cardNumber": "4111111111111111",
243
+ "expiryMonth": 12,
244
+ "expiryYear": 2028,
245
+ "cvv": "123",
246
+ "billingAddress": {
247
+ "street": "123 Main St",
248
+ "city": "San Francisco",
249
+ "state": "CA",
250
+ "zip": "94105",
251
+ "country": "US"
252
+ }
253
+ }
254
+ }
255
+ ```
256
+
257
+ ---
258
+
259
+ ### `POST /cards/fund/tier/:amount`
260
+
261
+ Add funds to an existing card.
262
+
263
+ **Available tiers**: `10`, `25`, `50`, `100`, `200`, `500`
264
+
265
+ **Request Body:**
266
+
267
+ ```json
268
+ {
269
+ "cardId": "uuid-of-existing-card"
270
+ }
271
+ ```
272
+
273
+ **Success Response** `200`:
274
+
275
+ ```json
276
+ {
277
+ "success": true,
278
+ "cardId": "uuid",
279
+ "kripiCardId": "kc_123",
280
+ "fundedAmount": 25,
281
+ "newBalance": 35.0,
282
+ "payment": {
283
+ "amountCharged": 29.4,
284
+ "txHash": "0x...",
285
+ "network": "base"
286
+ }
287
+ }
288
+ ```
289
+
290
+ ---
291
+
292
+ ## Wallet-Signed Endpoints
293
+
294
+ All require [wallet signature auth headers](#2-wallet-signature-free-endpoints).
295
+
296
+ ### `GET /cards`
297
+
298
+ List all cards owned by the authenticated wallet.
299
+
300
+ **Response** `200`:
301
+
302
+ ```json
303
+ {
304
+ "cards": [
305
+ {
306
+ "cardId": "uuid",
307
+ "kripiCardId": "kc_123",
308
+ "nameOnCard": "JOHN DOE",
309
+ "lastFour": "****",
310
+ "balance": 10.0,
311
+ "status": "active",
312
+ "createdAt": "2026-02-11T14:00:00.000Z"
313
+ }
314
+ ]
315
+ }
316
+ ```
317
+
318
+ ---
319
+
320
+ ### `GET /cards/:cardId`
321
+
322
+ Get detailed card info (fetches live balance from KripiCard).
323
+
324
+ **Response** `200`:
325
+
326
+ ```json
327
+ {
328
+ "card": {
329
+ "cardId": "uuid",
330
+ "kripiCardId": "kc_123",
331
+ "nameOnCard": "JOHN DOE",
332
+ "email": "john@example.com",
333
+ "balance": 8.5,
334
+ "initialAmountUsd": 10,
335
+ "status": "active",
336
+ "createdAt": "2026-02-11T14:00:00.000Z",
337
+ "updatedAt": "2026-02-11T15:30:00.000Z"
338
+ }
339
+ }
340
+ ```
341
+
342
+ ---
343
+
344
+ ### `GET /cards/:cardId/details`
345
+
346
+ Get sensitive card details (number, CVV, expiry). **Rate limited: 3 requests per card per hour.**
347
+
348
+ **Response** `200`:
349
+
350
+ ```json
351
+ {
352
+ "details": {
353
+ "cardNumber": "4111111111111111",
354
+ "expiryMonth": 12,
355
+ "expiryYear": 2028,
356
+ "cvv": "123",
357
+ "billingAddress": {
358
+ "street": "123 Main St",
359
+ "city": "San Francisco",
360
+ "state": "CA",
361
+ "zip": "94105",
362
+ "country": "US"
363
+ }
364
+ }
365
+ }
366
+ ```
367
+
368
+ ---
369
+
370
+ ### `POST /cards/:cardId/freeze`
371
+
372
+ Freeze a card (blocks all transactions).
373
+
374
+ **Response** `200`:
375
+
376
+ ```json
377
+ {
378
+ "success": true,
379
+ "cardId": "uuid",
380
+ "status": "frozen"
381
+ }
382
+ ```
383
+
384
+ ---
385
+
386
+ ### `POST /cards/:cardId/unfreeze`
387
+
388
+ Unfreeze a previously frozen card.
389
+
390
+ **Response** `200`:
391
+
392
+ ```json
393
+ {
394
+ "success": true,
395
+ "cardId": "uuid",
396
+ "status": "active"
397
+ }
398
+ ```
399
+
400
+ ---
401
+
402
+ ## Admin Endpoints
403
+
404
+ All require `Authorization: Bearer <ADMIN_SECRET>` header.
405
+
406
+ ### `GET /admin/api/stats`
407
+
408
+ System-wide statistics.
409
+
410
+ **Response** `200`:
411
+
412
+ ```json
413
+ {
414
+ "cards": {
415
+ "totalCards": 15,
416
+ "activeCards": 12,
417
+ "frozenCards": 3
418
+ },
419
+ "transactions": {
420
+ "totalTransactions": 22,
421
+ "completedTransactions": 18,
422
+ "failedTransactions": 2,
423
+ "pendingTransactions": 2,
424
+ "totalRevenue": "156.00",
425
+ "totalVolume": "1250.00"
426
+ },
427
+ "wallets": {
428
+ "totalWallets": 8
429
+ }
430
+ }
431
+ ```
432
+
433
+ ---
434
+
435
+ ### `GET /admin/api/transactions`
436
+
437
+ List transactions with optional filtering.
438
+
439
+ **Query Parameters:**
440
+
441
+ | Param | Type | Default | Description |
442
+ | -------- | ------ | ------- | ---------------------------------------- |
443
+ | `status` | string | — | Filter: `completed`, `failed`, `pending` |
444
+ | `limit` | number | 50 | Max results (capped at 100) |
445
+ | `offset` | number | 0 | Pagination offset |
446
+
447
+ **Response** `200`:
448
+
449
+ ```json
450
+ {
451
+ "transactions": [
452
+ {
453
+ "id": "uuid",
454
+ "walletAddress": "0x...",
455
+ "cardId": "uuid",
456
+ "type": "card_creation",
457
+ "amountUsd": "17.20",
458
+ "cardAmountUsd": "10.00",
459
+ "feeUsd": "2.00",
460
+ "kripiCardFeeUsd": "5.20",
461
+ "txHash": "0x...",
462
+ "status": "completed",
463
+ "errorMessage": null,
464
+ "createdAt": "2026-02-11T14:00:00.000Z"
465
+ }
466
+ ],
467
+ "limit": 50,
468
+ "offset": 0
469
+ }
470
+ ```
471
+
472
+ ---
473
+
474
+ ### `GET /admin/api/cards`
475
+
476
+ List all cards with optional wallet filter.
477
+
478
+ **Query Parameters:**
479
+
480
+ | Param | Type | Default | Description |
481
+ | -------- | ------ | ------- | --------------------------- |
482
+ | `wallet` | string | — | Filter by wallet address |
483
+ | `limit` | number | 50 | Max results (capped at 100) |
484
+ | `offset` | number | 0 | Pagination offset |
485
+
486
+ ---
487
+
488
+ ### `GET /admin/api/wallets`
489
+
490
+ List all registered wallets (up to 100).
491
+
492
+ **Response** `200`:
493
+
494
+ ```json
495
+ {
496
+ "wallets": [
497
+ {
498
+ "id": "uuid",
499
+ "address": "0x...",
500
+ "firstSeenAt": "2026-02-11T14:00:00.000Z",
501
+ "totalSpentUsd": "154.20",
502
+ "cardCount": 3
503
+ }
504
+ ]
505
+ }
506
+ ```
507
+
508
+ ---
509
+
510
+ ## Error Responses
511
+
512
+ All errors follow the format:
513
+
514
+ ```json
515
+ {
516
+ "error": "Human-readable error message"
517
+ }
518
+ ```
519
+
520
+ | Status | Meaning |
521
+ | ------ | ------------------------------------------ |
522
+ | `400` | Invalid request body or parameters |
523
+ | `401` | Missing or invalid authentication |
524
+ | `402` | Payment required (x402 flow) |
525
+ | `404` | Card not found or doesn't belong to wallet |
526
+ | `429` | Rate limit exceeded |
527
+ | `500` | Internal server error |
528
+
529
+ ---
530
+
531
+ ## Rate Limits
532
+
533
+ | Scope | Limit |
534
+ | --------------- | ---------------------------- |
535
+ | General API | 100 requests / 15 min per IP |
536
+ | Paid endpoints | 10 requests / 5 min per IP |
537
+ | Card details | 3 requests / hour per card |
538
+ | Admin endpoints | 30 requests / 15 min per IP |
539
+
540
+ ---
541
+
542
+ ## Pricing Tiers
543
+
544
+ ### Card Creation
545
+
546
+ | Load | Issuance Fee | Top-Up Fee | Our Fee | **Total** |
547
+ | ---- | ------------ | ---------- | ------- | ----------- |
548
+ | $10 | $3.00 | $2.20 | $2.00 | **$17.20** |
549
+ | $25 | $3.00 | $2.50 | $2.00 | **$32.50** |
550
+ | $50 | $3.00 | $3.00 | $2.00 | **$58.00** |
551
+ | $100 | $3.00 | $4.00 | $3.00 | **$110.00** |
552
+ | $200 | $3.00 | $6.00 | $5.00 | **$214.00** |
553
+ | $500 | $3.00 | $12.00 | $7.00 | **$522.00** |
554
+
555
+ ### Card Funding
556
+
557
+ | Amount | Top-Up Fee | Our Fee | **Total** |
558
+ | ------ | ---------- | ------- | ----------- |
559
+ | $10 | $2.20 | $2.00 | **$14.20** |
560
+ | $25 | $2.50 | $2.00 | **$29.50** |
561
+ | $50 | $3.00 | $2.00 | **$55.00** |
562
+ | $100 | $4.00 | $3.00 | **$107.00** |
563
+ | $200 | $6.00 | $5.00 | **$211.00** |
564
+ | $500 | $12.00 | $7.00 | **$519.00** |
package/DATABASE.md ADDED
@@ -0,0 +1,143 @@
1
+ # OpenCard — Neon Database Setup
2
+
3
+ ## 1. Create a Neon Project
4
+
5
+ 1. Go to [https://neon.tech](https://neon.tech) and sign up / log in
6
+ 2. Click **"New Project"**
7
+ 3. Configure:
8
+ - **Project name**: `opencard`
9
+ - **Postgres version**: 16 (latest)
10
+ - **Region**: Pick closest to your server (e.g. `us-east-2` for US)
11
+ - **Compute size**: Free tier (0.25 CU) is fine for MVP
12
+ 4. Click **"Create Project"**
13
+
14
+ ## 2. Get Your Connection String
15
+
16
+ After project creation, Neon shows your connection details. Copy the **connection string**:
17
+
18
+ ```
19
+ postgresql://neondb_owner:YOUR_PASSWORD@ep-XXXXX.us-east-2.aws.neon.tech/neondb?sslmode=require
20
+ ```
21
+
22
+ > [!IMPORTANT]
23
+ > Save this immediately — the password is only shown once. You can reset it later from the Neon dashboard under **Connection Details**.
24
+
25
+ ## 3. Configure OpenCard
26
+
27
+ Add the connection string to your `.env` file:
28
+
29
+ ```env
30
+ DATABASE_URL=postgresql://neondb_owner:YOUR_PASSWORD@ep-XXXXX.us-east-2.aws.neon.tech/neondb?sslmode=require
31
+ ```
32
+
33
+ ## 4. Push the Schema
34
+
35
+ From the OpenCard project root, run:
36
+
37
+ ```bash
38
+ npm run db:push
39
+ ```
40
+
41
+ This uses Drizzle Kit to push the schema directly to Neon. It creates 3 tables:
42
+
43
+ | Table | Purpose |
44
+ | -------------- | -------------------------------------- |
45
+ | `wallets` | Agent wallet addresses, spend tracking |
46
+ | `cards` | Virtual cards linked to wallets |
47
+ | `transactions` | Payment & card operation history |
48
+
49
+ ### Expected Output
50
+
51
+ ```
52
+ [✓] Changes applied to database
53
+ - Created table "wallets"
54
+ - Created table "cards"
55
+ - Created table "transactions"
56
+ - Created indexes
57
+ ```
58
+
59
+ ## 5. Verify
60
+
61
+ You can verify tables were created in the **Neon Console**:
62
+
63
+ 1. Go to your project → **SQL Editor**
64
+ 2. Run:
65
+
66
+ ```sql
67
+ SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';
68
+ ```
69
+
70
+ You should see: `wallets`, `cards`, `transactions`
71
+
72
+ ## Schema Overview
73
+
74
+ ```
75
+ ┌──────────────────────┐
76
+ │ wallets │
77
+ ├──────────────────────┤
78
+ │ id (uuid) │──┐
79
+ │ address (text) │ │
80
+ │ first_seen_at (ts) │ │
81
+ │ total_spent_usd │ │
82
+ │ card_count │ │
83
+ └──────────────────────┘ │
84
+
85
+ ┌──────────────────────┐ │ ┌──────────────────────┐
86
+ │ cards │ │ │ transactions │
87
+ ├──────────────────────┤ │ ├──────────────────────┤
88
+ │ id (uuid) │──┼───→│ card_id (uuid) │
89
+ │ wallet_id (uuid)←──┘ │ │ wallet_address(text) │
90
+ │ wallet_address(text) │ │ │ type (text) │
91
+ │ kripi_card_id (text) │ │ │ amount_usd │
92
+ │ name_on_card (text) │ │ │ card_amount_usd │
93
+ │ email (text) │ │ │ fee_usd │
94
+ │ initial_amount_usd │ │ │ kripi_fee_usd │
95
+ │ current_balance_usd │ │ │ tx_hash (text) │
96
+ │ status (text) │ │ │ status (text) │
97
+ │ created_at (ts) │ │ │ error_message (text) │
98
+ │ updated_at (ts) │ │ │ created_at (ts) │
99
+ └──────────────────────┘ │ └──────────────────────┘
100
+
101
+ ```
102
+
103
+ ## Migrations (Optional)
104
+
105
+ If you prefer versioned migrations instead of `db:push`:
106
+
107
+ ```bash
108
+ # Generate migration files from schema changes
109
+ npm run db:generate
110
+
111
+ # Apply migrations
112
+ npm run db:migrate
113
+ ```
114
+
115
+ Migration files are saved to `drizzle/migrations/`.
116
+
117
+ ## Neon Free Tier Limits
118
+
119
+ | Resource | Limit |
120
+ | --------- | ----------------- |
121
+ | Compute | 191.9 hours/month |
122
+ | Storage | 512 MB |
123
+ | Branches | 10 |
124
+ | Databases | Unlimited |
125
+
126
+ This is more than enough for an MVP. The compute auto-suspends after 5 min of inactivity and resumes on the next query (~500ms cold start).
127
+
128
+ ## Troubleshooting
129
+
130
+ **"Connection refused"**
131
+
132
+ - Check that `?sslmode=require` is in your connection string
133
+ - Verify the endpoint ID matches your Neon project
134
+
135
+ **"Password authentication failed"**
136
+
137
+ - Reset your password in Neon Console → **Connection Details** → **Reset Password**
138
+ - Update `DATABASE_URL` in `.env`
139
+
140
+ **"Relation does not exist"**
141
+
142
+ - Run `npm run db:push` to create tables
143
+ - Check you're connecting to the correct database name