From e0dc9ba2ba2883e3abb4d4d361db2d0c8dec2912 Mon Sep 17 00:00:00 2001 From: Adem Date: Sun, 19 Apr 2026 01:42:00 +0100 Subject: [PATCH] backup point before blockchain --- AI_FEATURES_DOCUMENTATION.md | 34 +- app/(dashboard)/dashboard/page.tsx | 16 +- docs/ROUTING_ENDPOINTS.md | 45 ++ docs/implementation_plan.md | 309 ++++++++++++ features/contracts/api/contract.action.ts | 5 + .../components/list/contracts-list.tsx | 15 +- features/home/components/Footer.tsx | 77 +-- features/home/components/Stats.tsx | 378 ++++++-------- lib/services/ai.service.ts | 463 ++++++++++++++++-- lib/services/ai/analysis.types.ts | 1 + lib/services/rag.service.ts | 28 +- package-lock.json | 232 +++++++++ package.json | 1 + 13 files changed, 1261 insertions(+), 343 deletions(-) create mode 100644 docs/ROUTING_ENDPOINTS.md create mode 100644 docs/implementation_plan.md diff --git a/AI_FEATURES_DOCUMENTATION.md b/AI_FEATURES_DOCUMENTATION.md index 0d266df..e42db2f 100644 --- a/AI_FEATURES_DOCUMENTATION.md +++ b/AI_FEATURES_DOCUMENTATION.md @@ -64,14 +64,18 @@ The AI subsystem is centered on: ### 2.2 Models - Primary model: gemini-2.5-flash -- Fallback model: gemini-2.0-flash -- Model list is de-duplicated and iterated in order +- Optional secondary Gemini model: AI_MODEL_SECONDARY_GEMINI +- Fallback model provider: Groq (default: llama-3.3-70b-versatile) +- Gemini models are de-duplicated and iterated in order before Groq fallback +- Groq extraction fallback currently applies to image inputs in this pipeline; JSON repair and Q&A fallback are text-based ### 2.3 Environment Variables - AI_API_KEY (or AI_API_KEY2 / AI_API_KEY3 fallback) - AI_MODEL_PRIMARY (optional override) +- AI_MODEL_SECONDARY_GEMINI (optional override) - AI_MODEL_FALLBACK (optional override) +- GROQ_API_KEY (or AI_GROQ_API_KEY) ## 3. AI Capability Matrix @@ -162,13 +166,13 @@ sequenceDiagram autonumber participant AIS as AIService participant G1 as Gemini Primary - participant G2 as Gemini Fallback + participant G2 as Gemini Secondary (optional) AIS->>G1: buildPrevalidationPrompt + inline file alt Primary succeeds G1-->>AIS: JSON precheck else Primary fails - AIS->>G2: same precheck request + AIS->>G2: same precheck request (if configured) G2-->>AIS: JSON precheck end AIS->>AIS: parse precheck JSON @@ -201,26 +205,32 @@ sequenceDiagram autonumber participant AIS as AIService participant GP as Gemini Primary - participant GF as Gemini Fallback + participant GS as Gemini Secondary (optional) + participant GR as Groq Fallback AIS->>GP: generate analysis (strict JSON) alt GP success with usable output GP-->>AIS: text else GP fails - AIS->>GF: generate analysis (strict JSON) - alt GF success - GF-->>AIS: text - else GF fails + AIS->>GS: generate analysis (strict JSON) + alt GS success + GS-->>AIS: text + else GS fails AIS->>GP: lenient generation attempt - GP-->>AIS: raw text + alt lenient success + GP-->>AIS: raw text + else lenient fails + AIS->>GR: generate analysis (strict JSON) + GR-->>AIS: text + end end end AIS->>AIS: parseJsonResponse alt parse failed - AIS->>GF: repairMalformedJson(originalText, parseError) + AIS->>GR: repairMalformedJson(originalText, parseError) alt repair success - GF-->>AIS: repaired JSON text + GR-->>AIS: repaired JSON text AIS->>AIS: parse repaired JSON else repair failed AIS->>AIS: emergencyExtractFields(rawText) diff --git a/app/(dashboard)/dashboard/page.tsx b/app/(dashboard)/dashboard/page.tsx index 7462e49..cc7108e 100644 --- a/app/(dashboard)/dashboard/page.tsx +++ b/app/(dashboard)/dashboard/page.tsx @@ -293,7 +293,7 @@ export default function DashboardPage() { initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4 }} - className="grid gap-8 xl:grid-cols-[1.45fr,0.95fr] xl:items-end" + className="grid gap-8 lg:grid-cols-[1.45fr,0.95fr] lg:items-end" >

@@ -429,7 +429,7 @@ export default function DashboardPage() {

-
+

Total Files

@@ -583,7 +583,7 @@ export default function DashboardPage() {
-
+

Completed Samples

@@ -648,9 +648,9 @@ export default function DashboardPage() { {hasChartData ? ( -

+
{chartData && chartData.trends.length > 0 && ( - +

@@ -664,7 +664,7 @@ export default function DashboardPage() { )} {chartData && chartData.byStatus.length > 0 && ( - +

Processing Status

@@ -681,7 +681,7 @@ export default function DashboardPage() { )} {chartData && chartData.byType.length > 0 && ( - +

@@ -694,7 +694,7 @@ export default function DashboardPage() { )} - +

Recent Analyses

diff --git a/docs/ROUTING_ENDPOINTS.md b/docs/ROUTING_ENDPOINTS.md new file mode 100644 index 0000000..6a9dada --- /dev/null +++ b/docs/ROUTING_ENDPOINTS.md @@ -0,0 +1,45 @@ +# API & Routing Endpoints + +## API Endpoints + +### 1. Clerk Webhook +- **Path:** `/api/webhooks/clerk` +- **Method:** `POST` +- **Purpose:** Handles Clerk webhook events (authentication, user sync, etc.) + +### 2. File Upload (UploadThing) +- **Path:** `/api/uploadthing` +- **Methods:** `GET`, `POST` +- **Purpose:** Handles file uploads (contracts, images) with authentication + +--- + +## Protected App Routes (Require Login) + +Defined in middleware ([proxy.ts](../proxy.ts)): +- `/dashboard` and all sub-pages +- `/contracts` and all sub-pages +- `/chat` and all sub-pages +- `/claims` and all sub-pages +- `/blockchain` and all sub-pages +- `/settings` and all sub-pages +- `/api/contracts` and all sub-pages +- `/api/chat` +- `/api/claims` + +--- + +## Feature API Actions (Server Actions) + +These are called from the frontend, not as REST endpoints: +- `/features/contracts/api/contract.action.ts` (contract CRUD, AI analysis) +- `/features/analytics/api/stats.action.ts` (dashboard stats) +- `/features/notifications/api/notification.action.ts` (notifications) +- `/features/auth/api/user.action.ts` (user sync) + +--- + +**Note:** +- All `/dashboard`, `/contracts`, `/chat`, `/claims`, `/blockchain`, `/settings` routes are protected and require authentication. +- API endpoints under `/api/` may also be protected by middleware. +- For more details, see the middleware configuration in [proxy.ts](../proxy.ts). diff --git a/docs/implementation_plan.md b/docs/implementation_plan.md new file mode 100644 index 0000000..2c569df --- /dev/null +++ b/docs/implementation_plan.md @@ -0,0 +1,309 @@ +# Blockchain Integration — LexiChain BFSI Platform + +## Goal + +Add a **fully functional, 100% free** blockchain module to the existing LexiChain platform. This module provides: + +1. **Proof of Deposit** — SHA-256 hash of each contract document is stored on-chain with a timestamp, making submission dates provable and tamper-proof. +2. **On-chain Verification** — Anyone can verify that a document existed at a specific time. +3. **Blockchain Explorer UI** — A new `/blockchain` page showing all on-chain transactions + per-contract verification status. + +--- + +## User Review Required + +> [!IMPORTANT] +> **Zero cost guaranteed.** The entire implementation uses: +> - **Hardhat local node** for development (free, instant, unlimited) +> - **Ethereum Sepolia testnet** for demo/presentation (free test ETH from faucets) +> - No MetaMask required for end-users — all blockchain operations run **server-side** via a backend wallet + +> [!WARNING] +> **Server-side wallet approach**: Instead of requiring users to install MetaMask and sign transactions, the server holds a private key and signs transactions on behalf of the platform. This is the right UX for a BFSI enterprise platform (users shouldn't need crypto knowledge). The private key is stored in `.env` and never exposed to the client. + +> [!IMPORTANT] +> **Dual-mode architecture**: +> - `NODE_ENV=development` → Hardhat local node (`http://127.0.0.1:8545`) +> - `NODE_ENV=production` or env flag → Sepolia testnet (via free Alchemy/Infura RPC) +> +> You can switch between modes with a single env variable change. + +--- + +## Proposed Changes + +### Component 1: Smart Contract (Hardhat + Solidity) + +Creates a standalone `blockchain/` directory at the project root with a Hardhat project for developing, testing, and deploying the smart contract. + +#### [NEW] [blockchain/contracts/DocumentRegistry.sol](file:///c:/Stage/Project-PFE/bfsi-project/blockchain/contracts/DocumentRegistry.sol) + +Solidity smart contract with: +- `registerDocument(bytes32 docHash, string calldata fileName)` — stores hash + metadata on-chain +- `verifyDocument(bytes32 docHash)` — checks if a hash exists and returns timestamp + depositor +- `getDocumentsByDepositor(address depositor)` — lists all docs registered by an address +- Events: `DocumentRegistered(bytes32 indexed docHash, uint256 timestamp, address indexed depositor, string fileName)` +- Modifier to prevent duplicate registrations + +#### [NEW] [blockchain/hardhat.config.ts](file:///c:/Stage/Project-PFE/bfsi-project/blockchain/hardhat.config.ts) + +Hardhat config with: +- Local Hardhat network (default, free) +- Sepolia network config (reads RPC URL + private key from env) +- Solidity 0.8.24 compiler + +#### [NEW] [blockchain/test/DocumentRegistry.test.ts](file:///c:/Stage/Project-PFE/bfsi-project/blockchain/test/DocumentRegistry.test.ts) + +Comprehensive tests: +- Register a document and verify timestamp +- Prevent duplicate registration +- Verify non-existent document returns zero +- Multiple documents by same depositor + +#### [NEW] [blockchain/scripts/deploy.ts](file:///c:/Stage/Project-PFE/bfsi-project/blockchain/scripts/deploy.ts) + +Deployment script that outputs the contract address for use in `.env`. + +#### [NEW] [blockchain/package.json](file:///c:/Stage/Project-PFE/bfsi-project/blockchain/package.json) + +Separate package.json for the Hardhat project (keeps blockchain dependencies isolated from the Next.js app). + +--- + +### Component 2: Next.js Blockchain Service Layer + +Server-side service that connects to the blockchain from Next.js server actions. No browser wallet needed. + +#### [NEW] [lib/services/blockchain.service.ts](file:///c:/Stage/Project-PFE/bfsi-project/lib/services/blockchain.service.ts) + +Core blockchain service: +- `hashDocument(fileUrl: string): Promise` — downloads contract PDF and computes SHA-256 +- `registerOnChain(documentHash: string, fileName: string): Promise<{ txHash, blockNumber, blockTimestamp }>` — sends transaction to smart contract +- `verifyOnChain(documentHash: string): Promise<{ exists, timestamp, depositor }>` — reads on-chain data +- Uses `ethers.js v6` with `JsonRpcProvider` + `Wallet` (server-side, no MetaMask) +- Auto-detects network mode from env vars + +#### [NEW] [lib/services/blockchain.types.ts](file:///c:/Stage/Project-PFE/bfsi-project/lib/services/blockchain.types.ts) + +TypeScript types for blockchain data: +```typescript +interface BlockchainProof { + documentHash: string; + txHash: string; + blockNumber: number; + blockTimestamp: Date; + network: 'hardhat' | 'sepolia'; + contractAddress: string; + explorerUrl: string | null; // Sepolia etherscan link +} +``` + +--- + +### Component 3: Server Actions & Integration + +#### [NEW] [features/blockchain/api/blockchain.action.ts](file:///c:/Stage/Project-PFE/bfsi-project/features/blockchain/api/blockchain.action.ts) + +New server actions: +- `registerContractOnBlockchain(contractId: string)` — hashes + registers + saves proof to DB +- `verifyContractOnBlockchain(contractId: string)` — verifies on-chain status +- `getBlockchainTransactions()` — fetches all blockchain proofs for the authenticated user + +#### [MODIFY] [features/contracts/api/contract.action.ts](file:///c:/Stage/Project-PFE/bfsi-project/features/contracts/api/contract.action.ts) + +After successful AI analysis, **automatically trigger** blockchain registration: +- In `analyzeContractAction()`, after `ContractService.updateWithAIResults()`, call `BlockchainService.hashAndRegister()` +- Save `documentHash`, `txHash` to the contract record +- This means every analyzed contract gets an automatic on-chain proof + +--- + +### Component 4: Database Schema Update + +#### [MODIFY] [prisma/schema.prisma](file:///c:/Stage/Project-PFE/bfsi-project/prisma/schema.prisma) + +Expand the existing blockchain placeholder fields on `Contract`: +```diff + // Blockchain (later) +- documentHash String? +- txHash String? +- ipfsUrl String? ++ documentHash String? ++ txHash String? ++ blockNumber Int? ++ blockTimestamp DateTime? ++ blockchainNetwork String? // 'hardhat' | 'sepolia' ++ contractAddress String? // smart contract address used +``` + +Add a new `BlockchainTransaction` model for the explorer view: +```prisma +model BlockchainTransaction { + id String @id @default(cuid()) + userId String + user User @relation(...) + contractId String + contract Contract @relation(...) + + documentHash String + txHash String @unique + blockNumber Int + blockTimestamp DateTime + network String // 'hardhat' | 'sepolia' + contractAddress String + status String @default("CONFIRMED") // PENDING, CONFIRMED, FAILED + + createdAt DateTime @default(now()) +} +``` + +--- + +### Component 5: Frontend — Blockchain Explorer Page + +#### [NEW] [app/(dashboard)/blockchain/page.tsx](file:///c:/Stage/Project-PFE/bfsi-project/app/(dashboard)/blockchain/page.tsx) + +New dashboard page at `/blockchain` with: +- **Header stats**: Total verified contracts, latest block, network status +- **Transaction table**: All blockchain proofs with txHash, contract name, timestamp, verification status +- **Verification panel**: Paste a document hash to check its on-chain status +- **Network indicator**: Shows whether connected to Hardhat (local) or Sepolia + +#### [NEW] [features/blockchain/components/blockchain-explorer.tsx](file:///c:/Stage/Project-PFE/bfsi-project/features/blockchain/components/blockchain-explorer.tsx) + +Main explorer component with: +- Animated blockchain-themed cards +- Transaction list with expandable details +- Real-time verification status badges +- Network health indicator + +#### [NEW] [features/blockchain/components/verify-document.tsx](file:///c:/Stage/Project-PFE/bfsi-project/features/blockchain/components/verify-document.tsx) + +Standalone verification widget: +- File upload → compute hash → check on-chain +- Shows proof details if found (timestamp, block, depositor) +- Visual "Verified ✓" / "Not Found ✗" result + +#### [NEW] [features/blockchain/components/blockchain-proof-badge.tsx](file:///c:/Stage/Project-PFE/bfsi-project/features/blockchain/components/blockchain-proof-badge.tsx) + +Small badge component to show on contract cards: +- 🟢 "On-Chain Verified" (with txHash link) +- 🟡 "Pending" (registration in progress) +- ⚫ "Not Registered" (no blockchain proof yet) + +--- + +### Component 6: Navigation & Integration Updates + +#### [MODIFY] [components/layout/navigation.tsx](file:///c:/Stage/Project-PFE/bfsi-project/components/layout/navigation.tsx) + +Add new nav item: +```typescript +{ + href: "/blockchain", + label: "Blockchain", + icon: , + description: "On-chain proofs", +} +``` + +#### [MODIFY] [types/contract.types.ts](file:///c:/Stage/Project-PFE/bfsi-project/types/contract.types.ts) + +Add blockchain fields to the Contract interface: +```typescript +blockNumber: number | null; +blockTimestamp: Date | null; +blockchainNetwork: string | null; +contractAddress: string | null; +``` + +#### [MODIFY] [.env.example](file:///c:/Stage/Project-PFE/bfsi-project/.env.example) + +Add blockchain env vars: +```env +# Blockchain +BLOCKCHAIN_PRIVATE_KEY= # Server wallet private key (Hardhat default for dev) +BLOCKCHAIN_RPC_URL= # RPC endpoint (empty = Hardhat local) +BLOCKCHAIN_CONTRACT_ADDRESS= # Deployed DocumentRegistry address +BLOCKCHAIN_NETWORK=hardhat # 'hardhat' or 'sepolia' +SEPOLIA_RPC_URL= # Free Alchemy/Infura Sepolia RPC +``` + +--- + +## Architecture Diagram + +```mermaid +flowchart TD + U[User Browser] --> UI[Next.js App Router] + + UI -->|Server Action| BA[blockchain.action.ts] + BA --> BS[BlockchainService] + BS -->|ethers.js v6| BC[Smart Contract on Blockchain] + BS -->|Hash document| PDF[Contract PDF from UploadThing] + BA --> DB[(PostgreSQL - BlockchainTransaction)] + + UI -->|Server Action| CA[contract.action.ts] + CA -->|After AI analysis| BA + + subgraph "Local Dev" + HN[Hardhat Node :8545] + end + + subgraph "Demo/Production" + SN[Sepolia Testnet] + end + + BC -.-> HN + BC -.-> SN +``` + +--- + +## Implementation Order + +| Step | Component | Estimated Effort | +|------|-----------|-----------------| +| 1 | Hardhat project + Smart Contract + Tests | ~30 min | +| 2 | Deploy to local Hardhat node | ~5 min | +| 3 | `BlockchainService` (server-side ethers.js) | ~30 min | +| 4 | Prisma schema update + migration | ~10 min | +| 5 | Server actions (`blockchain.action.ts`) | ~20 min | +| 6 | Integration into `analyzeContractAction` | ~10 min | +| 7 | Blockchain Explorer page + components | ~45 min | +| 8 | Navigation update + proof badges | ~15 min | +| 9 | Deploy to Sepolia testnet (optional, for demo) | ~15 min | + +**Total: ~3 hours of implementation** + +--- + +## Open Questions + +> [!IMPORTANT] +> **1. Auto-register vs. Manual button?** +> The plan currently auto-registers contracts on the blockchain after AI analysis completes. Alternatively, we could add a manual "Register on Blockchain" button per contract. Which do you prefer? (I recommend **both**: auto-register + manual re-register option) + +> [!IMPORTANT] +> **2. Sepolia for presentation?** +> Do you want me to also set up the Sepolia testnet deployment for your PFE presentation/jury? This gives you real Etherscan links to show. You'll just need to grab free Sepolia ETH from a faucet (takes 2 minutes). We can start with Hardhat local and add Sepolia later. + +> [!IMPORTANT] +> **3. IPFS integration?** +> Your schema has an `ipfsUrl` field. Do you want to also store contract files on IPFS (using a free service like Pinata with 1GB free tier)? This would give you decentralized file storage + on-chain hash. Or should we skip this to keep things simpler? + +--- + +## Verification Plan + +### Automated Tests +1. **Smart contract tests** — `cd blockchain && npx hardhat test` (tests register, verify, duplicate prevention) +2. **Integration test** — Upload a contract → AI analysis → verify blockchain fields are populated in DB +3. **Service test** — Call `BlockchainService.hashDocument()` + `registerOnChain()` directly + +### Manual Verification +1. Start Hardhat node → deploy contract → upload a contract in the app → check `/blockchain` page shows the transaction +2. Use the verification panel to re-verify a document hash +3. Check the contract detail view shows the "On-Chain Verified" badge +4. If Sepolia is configured: verify the txHash on [Sepolia Etherscan](https://sepolia.etherscan.io/) + diff --git a/features/contracts/api/contract.action.ts b/features/contracts/api/contract.action.ts index 3bf62e1..215b489 100644 --- a/features/contracts/api/contract.action.ts +++ b/features/contracts/api/contract.action.ts @@ -428,10 +428,15 @@ export async function analyzeContractAction(id: string) { }); // Analyze with AI + const forceFallbackModelTest = + process.env.AI_FORCE_FALLBACK_TEST === "1" || + String(process.env.AI_FORCE_FALLBACK_TEST).toLowerCase() === "true"; + const aiResults = await AIService.analyzeContract(contract.fileUrl, { userId: contract.userId, fileName: contract.fileName, maxRetries: 3, + forceFallbackModelTest, }); // Validate results diff --git a/features/contracts/components/list/contracts-list.tsx b/features/contracts/components/list/contracts-list.tsx index fc812f5..cf6946f 100644 --- a/features/contracts/components/list/contracts-list.tsx +++ b/features/contracts/components/list/contracts-list.tsx @@ -52,7 +52,11 @@ import { import { toast } from "sonner"; import { ContractChatModal } from "@/features/contracts/components/modals/contract-chat-modal"; import { ContractProofModal } from "@/features/contracts/components/modals/contract-proof-modal"; -import { stripMarkdown, exportToCSV, exportToPDF } from "@/features/contracts/utils/export.utils"; +import { + stripMarkdown, + exportToCSV, + exportToPDF, +} from "@/features/contracts/utils/export.utils"; interface Contract { id: string; @@ -1080,12 +1084,12 @@ export function ContractsList({ refreshTrigger }: { refreshTrigger?: number }) { title="Download contract" onClick={() => { if (contract.fileUrl) { - const downloadUrl = contract.fileUrl + "?download=1"; - const link = document.createElement("a"); - link.href = downloadUrl; + link.href = contract.fileUrl; link.download = contract.fileUrl.split("/").pop() || "contract"; + link.target = "_blank"; + link.rel = "noopener noreferrer"; document.body.appendChild(link); link.click(); document.body.removeChild(link); @@ -1307,7 +1311,8 @@ export function ContractsList({ refreshTrigger }: { refreshTrigger?: number }) {

- {stripMarkdown(selectedContract.policyNumber) || "N/A"} + {stripMarkdown(selectedContract.policyNumber) || + "N/A"}

diff --git a/features/home/components/Footer.tsx b/features/home/components/Footer.tsx index 081a65a..b7c19a1 100644 --- a/features/home/components/Footer.tsx +++ b/features/home/components/Footer.tsx @@ -1,10 +1,12 @@ "use client"; import { useScrollAnimation } from "@/hooks/useScrollAnimation"; -import { Sparkles, Github, Twitter, Linkedin, Mail } from "lucide-react"; +import { Github, Twitter, Linkedin, Mail } from "lucide-react"; import Image from "next/image"; -// Social Icon Component +// ========================================== +// Composant : Icône Sociale Premium +// ========================================== function SocialIcon({ icon: Icon, href, @@ -20,13 +22,20 @@ function SocialIcon({ target="_blank" rel="noopener noreferrer" aria-label={label} - className="text-slate-500 hover:text-slate-900 dark:hover:text-white transition-colors duration-200" + className="group relative flex items-center justify-center w-10 h-10 rounded-full bg-slate-50 dark:bg-white/[0.03] border border-slate-200 dark:border-white/10 transition-all duration-300 hover:-translate-y-1 hover:border-primary/50 hover:shadow-[0_0_20px_rgba(var(--primary),0.2)]" > - + {/* Lueur d'arrière-plan au survol */} +
+ + {/* Icône */} + ); } +// ========================================== +// Composant Principal : Footer +// ========================================== export function Footer() { const { ref, isVisible } = useScrollAnimation({ threshold: 0.1, @@ -42,60 +51,66 @@ export function Footer() {