A comprehensive, enterprise-grade platform for managing funding calls, applications, assessments, and results. Built with modern architecture, decentralized identity, AI-powered features, and high-performance WASM visualizations.
This platform provides a complete solution for organizations managing competitive funding programs, research grants, or any application-based selection process. It supports the entire lifecycle from call creation through application submission, expert assessment, and final results aggregation.
- Multi-Call Management - Create and manage multiple funding calls with customizable criteria
- Applicant Portal - Intuitive interface for application submission with file uploads
- Assessor Interface - Streamlined assessment workflow with CoI declarations
- Coordinator Dashboard - Full oversight with assignment management and progress tracking
- Master Results - Aggregated scoring with variance detection and analytics
- Decentralized Identity - Nostr-based DID authentication (NIP-05, NIP-07, NIP-98)
- Model-Agnostic AI - Configurable AI assistance (OpenAI, Anthropic, Ollama, LM Studio)
- WASM Visualizations - High-performance Rust/WebAssembly charts and graphs
- GDPR Compliant - Full audit logging, data export, and privacy controls
- WCAG 2.1 AA - Accessibility-first design system
πΈ Click to expand screenshots
|
Open Funding Calls Browse available funding opportunities with deadline badges and application counts. |
Landing Page GOV.UK-styled landing with navigation, search, and quick access to opportunities. |
|
Dashboard Sidebar Full management sidebar with navigation and pending item badges. |
AI Settings Panel Model-agnostic AI configuration with provider selection and feature toggles. |
|
Auth Layout Clean authentication interface supporting both JWT and Nostr DID login methods. |
flowchart TB
subgraph Frontend["Frontend (React 18 + TypeScript + Vite)"]
NostrAuth[Nostr DID Auth<br/>NIP-05/07/98]
DesignSystem[Design System<br/>WCAG 2.1 AA]
WASMViz[WASM Visualizations<br/>Rust + plotters]
end
subgraph Backend["Backend (Node.js + Express + TypeScript)"]
API[REST API<br/>OpenAPI 3.0]
RBAC[RBAC Middleware<br/>5 Roles]
Audit[Audit Logger<br/>GDPR Compliant]
AI[Model-Agnostic AI<br/>OpenAI/Anthropic/Ollama]
end
subgraph DataLayer["Data Layer"]
Postgres[(PostgreSQL 15<br/>UUID PKs)]
Redis[(Redis 7<br/>Sessions/Cache)]
S3[(AWS S3<br/>File Storage)]
end
Frontend --> Backend
Backend --> Postgres
Backend --> Redis
Backend --> S3
style Frontend fill:#e1f5fe,stroke:#01579b
style Backend fill:#fff3e0,stroke:#e65100
style DataLayer fill:#f3e5f5,stroke:#7b1fa2
- React 18 with TypeScript
- Vite for fast development and builds
- React Query for data fetching and caching
- React Router for navigation
- React Hook Form + Zod for form validation
- Custom Design System with CSS custom properties
- WASM/Rust visualizations using
plotters-canvas
- Node.js 20+ with Express
- TypeScript with strict mode
- PostgreSQL 15 with UUID primary keys
- Redis for session management and caching
- JWT + Nostr DID authentication
- Zod for API validation
- Winston for structured logging
- OpenAI (GPT-4, GPT-3.5)
- Anthropic (Claude)
- Ollama (local models)
- LM Studio (local inference)
- Custom endpoints (configurable)
- Docker + Docker Compose
- Kubernetes manifests
- GitHub Actions CI/CD
- Terraform infrastructure as code
- Prometheus + Grafana monitoring
- Node.js 20+
- PostgreSQL 15+
- Redis 7+
- Docker & Docker Compose (optional)
# Clone the repository
git clone https://github.com/dreamlab-ai/funding-platform.git
cd funding-platform
# Copy environment variables
cp .env.example .env
# Edit .env with your configuration
# Install dependencies
cd backend && npm install
cd ../frontend && npm install
# Run database migrations
cd ../database
psql -U postgres -d funding_platform -f migrations/001_initial_schema.sql
psql -U postgres -d funding_platform -f migrations/002_indexes.sql
psql -U postgres -d funding_platform -f migrations/003_user_identities.sql
# Start development servers
cd ../backend && npm run dev
cd ../frontend && npm run dev# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose downfunding-platform/
βββ backend/ # Node.js Express API
β βββ src/
β βββ ai/ # Model-agnostic AI integration
β β βββ providers/ # OpenAI, Anthropic, Ollama, LM Studio
β β βββ features/ # Summarize, scoring-assist, anomaly, similarity
β βββ auth/ # Nostr DID authentication
β βββ config/ # Configuration management
β βββ controllers/ # Route handlers
β βββ middleware/ # Auth, RBAC, validation, rate limiting
β βββ models/ # Data models
β βββ routes/ # API routes
β βββ security/ # JWT, RBAC, audit, CSRF
β βββ services/ # Business logic
β βββ types/ # TypeScript definitions
β βββ utils/ # Helpers and utilities
βββ frontend/ # React TypeScript application
β βββ src/
β βββ components/ # Reusable UI components
β β βββ ui/ # Design system components
β β βββ Visualizations/ # WASM chart wrappers
β βββ hooks/ # Custom React hooks
β βββ lib/ # Utilities and services
β β βββ nostr/ # Nostr DID client library
β βββ pages/ # Page components
β βββ services/ # API client services
β βββ stores/ # State management
β βββ styles/ # CSS and design tokens
β βββ wasm/ # WASM loader and bindings
βββ wasm-viz/ # Rust WASM visualization library
β βββ src/
β βββ charts/ # Chart implementations
β β βββ score_distribution.rs
β β βββ progress_tracker.rs
β β βββ variance_heatmap.rs
β β βββ timeline.rs
β β βββ network_graph.rs
β βββ lib.rs # WASM entry point
βββ database/ # PostgreSQL schemas
β βββ migrations/ # SQL migrations
β βββ seeds/ # Development data
βββ infrastructure/ # Infrastructure as code
β βββ terraform/ # AWS/GCP/Azure configs
βββ k8s/ # Kubernetes manifests
βββ docs/ # Documentation
β βββ api/ # OpenAPI specifications
β βββ architecture/ # Architecture decision records
βββ scripts/ # Utility scripts
βββ .github/ # GitHub Actions workflows
βββ docker-compose.yml # Docker development setup
| Role | Permissions |
|---|---|
| Applicant | Submit applications, upload files, track status |
| Assessor | View assigned applications, submit assessments, declare CoI |
| Coordinator | Manage calls, assign assessors, view all applications, export results |
| Scheme Owner | View results, approve funding decisions |
| Admin | Full system access, user management, audit logs |
flowchart LR
subgraph Roles["User Roles & Permissions"]
Admin["π Admin"]
Coord["π Coordinator"]
Owner["π° Scheme Owner"]
Assessor["π Assessor"]
Applicant["π€ Applicant"]
end
subgraph Actions
Users["Manage Users"]
Calls["Manage Calls"]
Assign["Assign Assessors"]
Review["Review Results"]
Assess["Submit Assessments"]
Apply["Submit Applications"]
end
Admin --> Users & Calls & Assign & Review & Assess & Apply
Coord --> Calls & Assign & Review
Owner --> Review
Assessor --> Assess
Applicant --> Apply
style Admin fill:#ff6b6b,stroke:#c92a2a
style Coord fill:#4dabf7,stroke:#1864ab
style Owner fill:#69db7c,stroke:#2b8a3e
style Assessor fill:#ffd43b,stroke:#f59f00
style Applicant fill:#e599f7,stroke:#9c36b5
stateDiagram-v2
[*] --> Draft: Create Application
Draft --> Draft: Edit & Save
Draft --> Submitted: Submit
Submitted --> UnderReview: Assign Assessors
UnderReview --> UnderReview: Assessments In Progress
UnderReview --> Assessed: All Assessments Complete
Assessed --> Ranked: Calculate Scores
Ranked --> Approved: Funding Decision
Ranked --> Rejected: Funding Decision
Approved --> [*]
Rejected --> [*]
note right of Draft: Applicant can edit
note right of Submitted: Locked for review
note right of UnderReview: 2+ assessors assigned
note right of Assessed: Variance check
sequenceDiagram
participant U as User
participant F as Frontend
participant B as Backend
participant N as Nostr Extension
participant DB as Database
alt JWT Authentication
U->>F: Enter email/password
F->>B: POST /auth/login
B->>DB: Verify credentials
DB-->>B: User record
B-->>F: JWT + Refresh Token
F->>F: Store tokens
end
alt Nostr DID Authentication
U->>F: Click "Sign in with Nostr"
F->>B: POST /auth/nostr/challenge
B-->>F: Challenge event
F->>N: Sign challenge (NIP-07)
N-->>F: Signed event
F->>B: POST /auth/nostr/verify
B->>B: Verify signature
B->>DB: Find/create user by pubkey
DB-->>B: User record
B-->>F: JWT + Refresh Token
end
Note over F,B: All subsequent requests include JWT in Authorization header
erDiagram
USERS ||--o{ APPLICATIONS : submits
USERS ||--o{ ASSESSMENTS : writes
USERS ||--o{ USER_IDENTITIES : has
FUNDING_CALLS ||--o{ APPLICATIONS : receives
FUNDING_CALLS ||--o{ ASSESSMENT_CRITERIA : defines
FUNDING_CALLS ||--o{ ASSESSOR_POOLS : has
APPLICATIONS ||--o{ ASSESSMENTS : evaluated_by
APPLICATIONS ||--o{ APPLICATION_FILES : contains
ASSIGNMENTS ||--|| APPLICATIONS : references
ASSIGNMENTS ||--|| USERS : assigned_to
ASSESSMENTS ||--o{ ASSESSMENT_SCORES : contains
ASSESSMENT_CRITERIA ||--o{ ASSESSMENT_SCORES : uses
USERS {
uuid user_id PK
string email UK
string password_hash
enum role
string first_name
string last_name
boolean is_active
timestamp last_login
}
USER_IDENTITIES {
uuid identity_id PK
uuid user_id FK
string nostr_pubkey UK
string did
string nip05_identifier
boolean nip05_verified
}
FUNDING_CALLS {
uuid call_id PK
string name
text description
enum status
timestamp open_at
timestamp close_at
jsonb settings
}
APPLICATIONS {
uuid application_id PK
uuid call_id FK
uuid applicant_id FK
enum status
jsonb form_data
timestamp submitted_at
}
ASSESSMENTS {
uuid assessment_id PK
uuid assignment_id FK
uuid assessor_id FK
enum status
text comments
boolean coi_declared
timestamp submitted_at
}
POST /api/v1/auth/register # Register new user
POST /api/v1/auth/login # Login with email/password
POST /api/v1/auth/nostr/challenge # Get Nostr challenge
POST /api/v1/auth/nostr/verify # Verify Nostr signature
POST /api/v1/auth/refresh # Refresh JWT token
GET /api/v1/calls/open # List open calls (public)
POST /api/v1/calls # Create new call
GET /api/v1/calls/:id # Get call details
PUT /api/v1/calls/:id # Update call
POST /api/v1/calls/:id/close # Close call
POST /api/v1/applications # Create application
GET /api/v1/applications/my # My applications
PUT /api/v1/applications/:id # Update draft
POST /api/v1/applications/:id/submit # Submit application
POST /api/v1/applications/:id/files # Upload files
GET /api/v1/assessments/my # My assignments
POST /api/v1/assessments/assignment/:id # Submit assessment
POST /api/v1/assessments/assignment/:id/submit # Final submit
POST /api/v1/assignments # Assign assessor
POST /api/v1/assignments/bulk # Bulk assign
GET /api/v1/assignments/progress/:callId # Progress overview
GET /api/v1/results/call/:id # Master results
GET /api/v1/results/call/:id/ranking # Ranking
GET /api/v1/results/call/:id/export # Export CSV
GET /api/v1/results/call/:id/analytics # Analytics
POST /api/v1/ai/summarize # Summarize application
POST /api/v1/ai/scoring-assist # AI scoring suggestions
POST /api/v1/ai/anomaly # Detect scoring anomalies
POST /api/v1/ai/similarity # Find similar applications
The platform supports decentralized identity through the Nostr protocol:
// Generate or import Nostr keys
import { generateKeyPair, getPublicKey } from '@/lib/nostr';
// Create DID from public key
const did = `did:nostr:${publicKeyHex}`;
// Sign authentication challenge
const event = await signEvent({
kind: 22242,
content: challenge,
tags: [['challenge', challengeId]]
});
// Verify with backend
await api.post('/auth/nostr/verify', { event });Supported NIPs:
- NIP-01: Basic protocol flow
- NIP-05: DNS-based verification
- NIP-07: Browser extension signing
- NIP-98: HTTP Auth events
High-performance charts rendered with Rust and WebAssembly:
// Rust implementation (wasm-viz/src/charts/score_distribution.rs)
#[wasm_bindgen]
pub fn render_score_distribution(
canvas_id: &str,
scores: &[f64],
options: JsValue
) -> Result<(), JsValue> {
let backend = CanvasBackend::new(canvas_id)?;
let root = backend.into_drawing_area();
// Histogram with customizable bins
let mut chart = ChartBuilder::on(&root)
.caption("Score Distribution", ("sans-serif", 20))
.build_cartesian_2d(range.clone(), 0u32..max_count)?;
chart.draw_series(Histogram::vertical(&chart)
.style(BLUE.filled())
.data(scores.iter().map(|x| (*x, 1))))?;
Ok(())
}// React wrapper
import { useWasmViz } from '@/wasm/hooks/useWasmViz';
function ScoreDistribution({ scores }) {
const { ready, renderChart } = useWasmViz();
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
if (ready && canvasRef.current) {
renderChart('score_distribution', canvasRef.current.id, scores);
}
}, [ready, scores]);
return <canvas ref={canvasRef} id="score-dist" />;
}Available visualizations:
- Score Distribution - Histogram with configurable bins
- Progress Radial - Circular progress indicators
- Variance Heatmap - Score variance visualization
- Submission Timeline - Time-series chart
- Assignment Network - Force-directed graph
flowchart TB
subgraph Client["Frontend Client"]
UI[AI Features UI]
end
subgraph Backend["Backend API"]
Router[AI Router]
Cache[(Response Cache)]
end
subgraph Providers["AI Providers"]
OpenAI[OpenAI<br/>GPT-4/3.5]
Anthropic[Anthropic<br/>Claude]
Ollama[Ollama<br/>Local Models]
LMStudio[LM Studio<br/>Local Inference]
Custom[Custom<br/>Any OpenAI-compatible]
end
subgraph Features["AI Features"]
Summarize[π Summarize<br/>Application summaries]
Scoring[π Scoring Assist<br/>AI suggestions]
Anomaly[β οΈ Anomaly Detection<br/>Score variance]
Similarity[π Similarity<br/>Find duplicates]
end
UI --> Router
Router --> Cache
Cache -.->|Cache Hit| Router
Router --> OpenAI & Anthropic & Ollama & LMStudio & Custom
Router --> Features
style OpenAI fill:#10a37f,stroke:#0d8a6f,color:#fff
style Anthropic fill:#d4a574,stroke:#b8956a
style Ollama fill:#1a1a1a,stroke:#333,color:#fff
style LMStudio fill:#6366f1,stroke:#4f46e5,color:#fff
Configure AI providers in .env:
# OpenAI
AI_OPENAI_API_KEY=sk-...
AI_OPENAI_MODEL=gpt-4
# Anthropic
AI_ANTHROPIC_API_KEY=sk-ant-...
AI_ANTHROPIC_MODEL=claude-3-sonnet
# Ollama (local)
AI_OLLAMA_BASE_URL=http://localhost:11434
AI_OLLAMA_MODEL=llama2
# LM Studio (local)
AI_LMSTUDIO_BASE_URL=http://localhost:1234
AI_LMSTUDIO_MODEL=local-model
# Custom endpoint
AI_CUSTOM_BASE_URL=http://your-endpoint
AI_CUSTOM_MODEL=your-model
AI_CUSTOM_API_KEY=your-key
# Default provider
AI_DEFAULT_PROVIDER=openai- RBAC - Role-based access control with fine-grained permissions
- JWT - Secure token-based authentication with refresh rotation
- Nostr DID - Decentralized identity verification
- CSRF Protection - Double-submit cookie pattern
- Rate Limiting - Request throttling per user/endpoint
- Input Sanitization - XSS prevention
- Audit Logging - Complete action trail
- File Validation - Type and size restrictions
- Encrypted Storage - Sensitive data encryption at rest
- Consent Management - Explicit consent tracking
- Data Export - User data export in machine-readable format
- Right to Erasure - Automated data deletion workflows
- Audit Trail - Complete history of data access and modifications
- Data Minimization - Collect only necessary information
- Anonymization - Support for anonymizing exported results
π§ͺ Click to view test breakdown
| Category | Files | Tests | Coverage |
|---|---|---|---|
| Unit - Security | 6 | ~313 | RBAC, JWT, Nostr DID, Audit |
| Unit - Services | 4 | ~167 | Scoring, File, Email, Export |
| Unit - Utils | 6 | ~380 | Validation, Logger, Helpers |
| Unit - AI | 7 | ~237 | Router, Similarity, Anomaly |
| Unit - Models | 5 | ~215 | User, Application, Assessment |
| Unit - Controllers | 5 | ~170 | Auth, Calls, Applications |
| Integration | 7 | ~190 | E2E flows, GDPR compliance |
| Total | 40 | 1,672 | β All Passing |
# Backend tests
cd backend
npm test
npm run test:coverage
# Frontend tests
cd frontend
npm test
npm run test:e2e
# WASM tests
cd wasm-viz
cargo test
wasm-pack test --headless --chrome# Linting
npm run lint
# Type checking
npm run typecheck
# Format
npm run format# Backend
cd backend && npm run build
# Frontend
cd frontend && npm run build
# WASM
cd wasm-viz && wasm-pack build --target webflowchart TB
subgraph Internet
Users[π₯ Users]
CDN[CloudFront/CDN]
end
subgraph LoadBalancer["Load Balancer"]
ALB[Application<br/>Load Balancer]
end
subgraph K8s["Kubernetes Cluster"]
subgraph Frontend["Frontend Pods"]
F1[React App]
F2[React App]
end
subgraph Backend["Backend Pods"]
B1[Express API]
B2[Express API]
B3[Express API]
end
subgraph Workers["Background Workers"]
W1[Email Worker]
W2[Export Worker]
end
end
subgraph DataStores["Data Layer"]
PG[(PostgreSQL<br/>Primary)]
PGR[(PostgreSQL<br/>Replica)]
Redis[(Redis<br/>Cluster)]
S3[(S3 Bucket<br/>Files)]
end
subgraph Monitoring["Observability"]
Prom[Prometheus]
Graf[Grafana]
Logs[CloudWatch<br/>Logs]
end
Users --> CDN --> ALB
ALB --> Frontend & Backend
Backend --> PG & Redis & S3
PG --> PGR
Workers --> PG & Redis
Backend --> Prom
Prom --> Graf
Backend --> Logs
style K8s fill:#326ce5,stroke:#1a4db0,color:#fff
style DataStores fill:#f3e5f5,stroke:#7b1fa2
style Monitoring fill:#fff3e0,stroke:#e65100
docker-compose -f docker-compose.prod.yml up -dkubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | - |
REDIS_URL |
Redis connection string | - |
JWT_SECRET |
JWT signing secret | - |
JWT_EXPIRY |
Token expiration | 15m |
AWS_S3_BUCKET |
S3 bucket for files | - |
AI_DEFAULT_PROVIDER |
Default AI provider | openai |
RATE_LIMIT_WINDOW |
Rate limit window (ms) | 60000 |
RATE_LIMIT_MAX |
Max requests per window | 100 |
See .env.example for complete configuration.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Built with Claude Flow V3 multi-agent orchestration and the Agentic QE Fleet quality engineering system.
Made with by DreamLab AI




