Cybersecurity-first enterprise platform serving Financial and Real Estate divisions — built on Next.js 15 with end-to-end type safety, regulated KYC onboarding, and role-based access control.
- Overview
- Tech Stack
- Architecture
- Quick Start
- Route Map
- Legacy Redirects
- API Reference
- Environment Variables
- Database
- Authentication Flow
- KYC Flow
- Deployment (Vercel)
- Admin Access
- Smoke Checks
- Contributing
- License
GEM Enterprise is a secure, invite-only platform that provides institutional and qualified clients with access to curated financial products and real estate investment opportunities. The platform enforces a fully-gated onboarding pipeline:
- Identity verification (KYC) — individuals, businesses, trusts, and family offices
- Compliance review — manual and automated approval workflows
- Entitlement gating — product and portfolio access is granted only after approval
- Audit trail — every sensitive action is logged for regulatory compliance
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 |
| ORM | Prisma 5 |
| Database | PostgreSQL 15+ |
| UI Components | shadcn/ui |
| Styling | Tailwind CSS 3 |
| Authentication | JWT (HTTP-only cookies) |
| Deployment | Vercel |
src/
├── app/ # Next.js App Router — pages and layouts
│ ├── (public)/ # Marketing and informational pages
│ ├── (auth)/ # Login and session management
│ ├── kyc/ # KYC onboarding flow
│ ├── decision/ # Post-KYC decision screens
│ ├── app/ # Protected client portal
│ │ └── admin/ # Admin-only panel
│ ├── api/ # Route Handlers (REST API)
│ └── (compliance)/ # Legal and compliance pages
├── components/ # Shared React components
├── lib/ # Utilities, auth helpers, Prisma client
└── types/ # Shared TypeScript types
prisma/
├── schema.prisma # Database schema
├── migrations/ # Prisma migration history
└── seed.ts # Database seed script
Key architectural decisions:
- Server Components by default — data fetching happens on the server; client components are opt-in via
"use client". - Route Handlers — all API logic lives in
app/api/and uses the Next.js Route Handler pattern. - Prisma ORM — single source of truth for the database schema; migrations are version-controlled.
- Middleware-based auth — JWT validation runs in
middleware.tsbefore protected routes are served.
- Node.js 20+
- npm 10+
- PostgreSQL 15+ (local or remote)
# 1. Clone the repository
git clone https://github.com/your-org/gem-enterprise.git
cd gem-enterprise
# 2. Install dependencies
npm install
# 3. Configure environment variables
cp .env.example .env.local
# Edit .env.local and fill in all required values
# 4. Push the Prisma schema to your database
npx prisma db push
# 5. Seed the database (creates admin user and reference data)
npx prisma db seed
# 6. Start the development server
npm run devThe application will be available at http://localhost:3000.
| Path | Label | Description | Auth Required |
|---|---|---|---|
/ |
Home | Marketing landing page | No |
/intel |
Intel | Market intelligence and insights | No |
/assets |
Assets | Asset overview and listings | No |
/community |
Community | Community hub | No |
/hub |
Hub | Resource hub | No |
/about |
About | Company information | No |
/contact |
Contact | Contact form | No |
/resources |
Resources | Downloadable resources | No |
/services |
Services | Service offerings | No |
/company |
Company | Company profile | No |
/get-started |
Get Started | Onboarding entry point | No |
/eligibility |
Eligibility | Eligibility pre-check | No |
| Path | Label | Description | Auth Required |
|---|---|---|---|
/client-login |
Client Login | Login form | No |
/portal |
Portal | Session entry redirect | No |
/access/continue |
Continue | Post-login routing gate | Partial |
| Path | Label | Description | Auth Required |
|---|---|---|---|
/kyc/start |
KYC Start | KYC flow entry point | Yes |
/kyc/individual |
Individual | Individual applicant form | Yes |
/kyc/business |
Business | Business entity form | Yes |
/kyc/trust |
Trust | Trust entity form | Yes |
/kyc/family-office |
Family Office | Family office form | Yes |
/kyc/upload |
Document Upload | Supporting document upload | Yes |
/kyc/review |
Review | Submission review and confirm | Yes |
/kyc/status |
KYC Status | Application status tracker | Yes |
| Path | Label | Description | Auth Required |
|---|---|---|---|
/decision/pending |
Pending | Application under review | Yes |
/decision/approved |
Approved | Approval confirmation | Yes |
/decision/rejected |
Rejected | Rejection notification | Yes |
/decision/manual-review |
Manual Review | Flagged for manual review | Yes |
| Path | Label | Description | Auth Required |
|---|---|---|---|
/app/dashboard |
Dashboard | Client overview dashboard | Yes — Client |
/app/products |
Products | Available investment products | Yes — Client |
/app/portfolios |
Portfolios | Portfolio management | Yes — Client |
/app/documents |
Documents | Document vault | Yes — Client |
/app/support |
Support | Support ticket system | Yes — Client |
/app/compliance |
Compliance | Compliance centre | Yes — Client |
/app/requests |
Requests | Service requests | Yes — Client |
/app/profile |
Profile | Profile management | Yes — Client |
/app/settings |
Settings | Account settings | Yes — Client |
/app/security |
Security | Security settings | Yes — Client |
/app/notifications |
Notifications | Notification centre | Yes — Client |
/app/messages |
Messages | Internal messaging | Yes — Client |
| Path | Label | Description | Auth Required |
|---|---|---|---|
/app/admin |
Admin | Admin overview | Yes — Admin |
/app/admin/kyc |
KYC Management | Review KYC submissions | Yes — Admin |
/app/admin/approvals |
Approvals | Manage approval queue | Yes — Admin |
/app/admin/users |
Users | User management | Yes — Admin |
/app/admin/allocations |
Allocations | Product allocations | Yes — Admin |
| Path | Label | Description | Auth Required |
|---|---|---|---|
/privacy |
Privacy Policy | Data privacy policy | No |
/terms |
Terms of Service | Terms and conditions | No |
/compliance-notice |
Compliance Notice | Regulatory disclosures | No |
The following redirects are configured to maintain backward compatibility:
| From (Legacy) | To (Canonical) | Type |
|---|---|---|
/login |
/client-login |
301 |
/register |
/get-started |
301 |
/apply |
/kyc/start |
301 |
/dashboard |
/app/dashboard |
301 |
/admin |
/app/admin |
301 |
/profile |
/app/profile |
301 |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/health |
No | Liveness check — returns { status: "ok" } |
GET |
/api/routes |
No | Lists all registered API routes |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/auth/login |
No | Authenticate with email and password; sets JWT cookie |
POST |
/api/auth/logout |
Yes | Clears JWT cookie |
GET |
/api/auth/session |
Yes | Returns current session user object |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/kyc |
Yes | Get current user's KYC submission status |
POST |
/api/kyc/submit |
Yes | Submit a completed KYC application |
POST |
/api/kyc/documents |
Yes | Upload supporting KYC documents (multipart) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/users/profile |
Yes | Get authenticated user's profile |
PATCH |
/api/users/profile |
Yes | Update authenticated user's profile |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/notifications |
Yes | List notifications for current user |
PATCH |
/api/notifications |
Yes | Mark notifications as read |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/support |
Yes | List support tickets for current user |
POST |
/api/support |
Yes | Create a new support ticket |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/requests |
Yes | List service requests for current user |
POST |
/api/requests |
Yes | Submit a new service request |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/admin/kyc |
Yes — Admin | List all KYC submissions with filters |
PATCH |
/api/admin/kyc |
Yes — Admin | Approve, reject, or flag a KYC submission |
GET |
/api/admin/users |
Yes — Admin | List all users with filters and pagination |
PATCH |
/api/admin/users |
Yes — Admin | Update user role or status |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/contact |
No | Submit a public contact form enquiry |
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string |
JWT_SECRET |
Yes | JWT signing secret, min 32 chars. App throws at startup in production if absent or default. |
ANTHROPIC_API_KEY |
No | Anthropic key for GEM Concierge chat. Falls back to rule-based replies if absent. |
NEXT_PUBLIC_AI_DISCLOSURE_TEXT |
Yes | Disclosure text shown before first AI message. SHA-256 stored in consent_records. |
NEXT_PUBLIC_APP_URL |
Yes | Canonical public URL of the application |
NEXT_PUBLIC_APP_NAME |
Yes | Display name used in UI and emails |
SMTP_HOST |
Yes | SMTP server hostname |
SMTP_PORT |
Yes | SMTP server port (587 or 465) |
SMTP_USER |
Yes | SMTP authentication username |
SMTP_PASS |
Yes | SMTP authentication password |
EMAIL_FROM |
Yes | From address used in outbound emails |
ADMIN_EMAIL |
Yes | Email address for the seeded admin account (seed script only) |
ADMIN_INITIAL_PASSWORD |
Yes | Temporary password for seeded admin. Change immediately after first login. |
AUDIT_ENABLED |
No | Set to true to persist compliance audit events to the database |
VERCEL_URL |
Auto | Auto-injected by Vercel at build time |
See .env.example for a copy-paste template.
Add variables in Vercel Dashboard → Project → Settings → Environment Variables. Do not place real values in
vercel.json. SeeDEPLOYMENT.mdfor full steps.
Required before first deploy:
# Add each via Vercel CLI or the dashboard
vercel env add DATABASE_URL
vercel env add JWT_SECRET # openssl rand -hex 32
vercel env add NEXT_PUBLIC_AI_DISCLOSURE_TEXT
vercel env add NEXT_PUBLIC_APP_URL
vercel env add NEXT_PUBLIC_APP_NAME
vercel env add SMTP_HOST
vercel env add SMTP_PORT
vercel env add SMTP_USER
vercel env add SMTP_PASS
vercel env add EMAIL_FROM
vercel env add ADMIN_EMAIL
vercel env add ADMIN_INITIAL_PASSWORD
vercel env add AUDIT_ENABLED
# Optional — enables live AI chat:
vercel env add ANTHROPIC_API_KEYAfter adding variables, force a redeploy (build-time variables are baked in at build):
vercel redeploy --forceApply database migrations (Vercel does not run this automatically):
DATABASE_URL="<production-url>" npx prisma migrate deployFull ordered steps including smoke tests: DEPLOYMENT.md.
The Prisma schema defines the following primary models:
| Model | Description |
|---|---|
User |
Platform user accounts with role, status, and KYC state |
KycSubmission |
KYC application data linked to a user |
KycDocument |
Uploaded documents associated with a KYC submission |
Notification |
In-app notification records per user |
SupportTicket |
Support request threads |
ServiceRequest |
Formal service requests from clients |
AuditLog |
Immutable compliance audit log entries |
# Generate and apply a new migration
npx prisma migrate dev --name describe-your-change
# Apply pending migrations in production (no schema changes)
npx prisma migrate deploy
# Inspect the current database schema
npx prisma db pull
# Open Prisma Studio (visual DB browser)
npx prisma studioThe seed script (prisma/seed.ts) creates:
- Initial admin user using
ADMIN_EMAILandADMIN_INITIAL_PASSWORD - Reference data (roles, statuses, categories)
npx prisma db seedUser submits credentials at /client-login
│
▼
POST /api/auth/login
├── Invalid → 401, show error on /client-login
└── Valid → Set JWT cookie → Redirect to /access/continue
│
▼
/access/continue (server-side routing gate)
│
├── No KYC submission → /kyc/start
├── KYC pending → /decision/pending
├── KYC rejected → /decision/rejected
├── KYC manual review → /decision/manual-review
└── KYC approved → /app/dashboard (or original destination)
All /app/* routes are protected by middleware.ts, which validates the JWT on every request and redirects unauthenticated users to /client-login.
/kyc/start
│
├── Individual → /kyc/individual
├── Business → /kyc/business
├── Trust → /kyc/trust
└── Family Office → /kyc/family-office
│
▼
/kyc/upload (supporting documents)
│
▼
/kyc/review (confirm all data before submission)
│
▼
POST /api/kyc/submit
│
▼
/kyc/status (polls submission status)
│
▼
Admin reviews at /app/admin/kyc
│
├── Approve → /decision/approved
├── Reject → /decision/rejected
└── Flag → /decision/manual-review
See DEPLOYMENT_QUICK_START.md for fast deployment options:
Option A: One-Click Deploy (Easiest)
- Click Deploy with Vercel button
- Creates new repo + project in 2 minutes
- Automatic deployment to production
Option B: Vercel CLI (3 minutes)
npm install -g vercel
npm run build
vercel --prodOption C: GitHub Auto-Deploy (5 minutes, best for teams)
- Push to GitHub
- Connect GitHub to Vercel
- Auto-deploy on every push
See VERCEL_DEPLOYMENT_GUIDE.md for the complete guide including:
- All required environment variables and where to add them
- Exact Vercel CLI commands
- Custom domain setup
- Performance monitoring
- Team collaboration setup
- Cost and limits
- Troubleshooting
The project is configured for easy deployment to any Vercel account:
-
Configuration files ready
vercel.json- Standard Next.js 20.x configuration (portable).env.example- All environment variable templatespackage.json- Standard npm scripts
-
Deploy to new account
# Option A: One-click (easiest) # Click deploy button in DEPLOYMENT_QUICK_START.md # Option B: Manual vercel login # Login with your Vercel account vercel link # Link to new project vercel --prod # Deploy
-
Add environment variables (if needed)
- Vercel Dashboard → Settings → Environment Variables
- Copy values from
.env.example
After every deployment, verify these endpoints:
| Endpoint | Expected |
|---|---|
/api/health |
200 { "status": "ok" } |
/ |
200 — landing page renders |
/client-login |
200 — login form renders |
/app/dashboard |
302 redirect to /client-login (without auth) |
POST /api/auth/login (bad creds) |
401 |
- After running
npx prisma db seed, an admin account is created using the values inADMIN_EMAILandADMIN_INITIAL_PASSWORD. - Log in at
/client-loginwith those credentials. - The auth middleware checks the
rolefield on the user record; the admin is granted roleADMIN. - Navigate to
/app/adminto access the administration panel. - Change the admin password immediately via
/app/settingsor/app/security.
After every deployment, verify the following URLs return the expected responses:
| URL | Expected |
|---|---|
/api/health |
200 { "status": "ok" } |
/ |
200 — landing page renders |
/client-login |
200 — login form renders |
/privacy |
200 — privacy policy renders |
/terms |
200 — terms page renders |
/get-started |
200 — onboarding entry renders |
/app/dashboard |
302 redirect to /client-login (unauthenticated) |
/app/admin |
302 redirect to /client-login (unauthenticated) |
/kyc/start |
302 redirect to /client-login (unauthenticated) |
POST /api/auth/login (bad creds) |
401 |
GET /api/auth/session (no cookie) |
401 |
- Branch from
mainusing the conventionfeat/,fix/, orchore/prefix. - Write or update tests for any changed behaviour.
- Ensure
npm run buildpasses with zero TypeScript errors. - Open a pull request with a clear description of the change and any compliance implications.
- Obtain at least one approval before merging.
Proprietary. All rights reserved. Unauthorised use, reproduction, or distribution of this software or any portion thereof is strictly prohibited.