Skip to content

Commit 280f272

Browse files
Josephrpbiniyam69
andauthored
adds brokerage, multiuser, link bank accounts , interface fixes and improvements
* phase 1 initial commit * adds nexus file sharing initial commit * adds prometheus metrics initial commit * adds prometheus metrics initial commit * adds prometheus metrics initial commit * adds prometheus, electron build passing , business logic , tsx bugfixes * adds prometheus metrics initial commit * adds prometheus metrics initial commit * adds bugfixes , electron build * adds logging , pm2 , tests , compatibility tests * Phase 1 Debug: Fix Critical Errors and Verify Build (#144) * Phase 1 Debug: Fix critical errors and verify build - Fix missing resolveApiUrl import in AuthContext.tsx (4 TS2304 errors) - Fix Python syntax error in server.py (duplicate else statement) - Verify TypeScript compilation: 0 errors - Verify production build: Success - Verify Python syntax: Valid - All critical blocking errors resolved * Fix: Remove duplicate x402 initialization block - Removed duplicate x402 payment service initialization block with pass statement - Proper initialization already exists at lines 144-168 - Addresses review comment on PR #144 * Delete ELECTRON_REQUIREMENTS.md --------- Co-authored-by: Tonic <joseph.pollack@emle.eu> * adds pm2 , dev scripts, environment , logs , ecosyste, server debug logging * adds e2e test for nexus file transfer , bugfixes, tests refactor , pm2 configs, and more * Delete scripts/dev/nexus_file_transfer_test_plan.md * adds e2e test for nexus file transfer , bugfixes, tests refactor , pm… (#147) * adds e2e test for nexus file transfer , bugfixes, tests refactor , pm2 configs, and more * Delete scripts/dev/nexus_file_transfer_test_plan.md * Issue #78: Trading Dashboard UI - Complete Implementation (#148) * feat(issue-78): Implement Trading Dashboard UI components - Add TradingDashboard main component with tabbed interface - Add OrderForm component for buy/sell order placement - Add PortfolioView component with positions and P&L display - Add MarketData component with real-time prices and order book - Add OrderHistory component with filtering - Integrate with UnifiedDashboard - Fix server.py syntax error (duplicate else statement) - Fix AuthContext missing resolveApiUrl import - All acceptance criteria met - Closes #78 * Delete PHASE_1_BRANCHES.md * Delete PHASE_2_BRANCHES.md --------- Co-authored-by: Tonic <joseph.pollack@emle.eu> * Issue #77: Document Review Workflows - Complete Implementation (#150) - Added ReviewComment and ReviewAssignment database models - Created Alembic migration for review tables - Implemented ReviewService with core business logic - Created diff utilities for version comparison - Added comprehensive review API routes - Implemented ReviewNotificationService for email notifications - Created ReviewCommentPanel component with threading - Created DiffView component for version comparison - Created ReviewAssignmentPanel for reviewer management - Enhanced ReviewInterface with edit mode and review tabs - Integrated review routes into server.py - Added deepdiff dependency for diff generation * Issue #76: Document Extraction Chains - Implementation & Tests (#145) * docs(issue-76): Add implementation status documentation - Document all requirements vs implementation status - Confirm all requirements are met - All features are production-ready * test(issue-76): Add comprehensive tests for document extraction chains - Add tests for simple extraction chain (<50k chars) - Add tests for map-reduce extraction chain (>50k chars) - Add tests for smart extraction with automatic strategy selection - Add tests for error handling and retry logic - Add tests for CDM validation - Add integration tests - All 15 tests passing Closes #76 * Delete docs/ISSUE_76_IMPLEMENTATION.md --------- Co-authored-by: Tonic <joseph.pollack@emle.eu> * Issue #79: Order Management System - Complete Implementation (#149) - Created Order database model with all required fields (order_id, symbol, side, order_type, quantity, price, status, etc.) - Implemented TradingAPIService abstraction for multiple trading APIs (Alpaca, Mock) - Created OrderService for order validation, execution, and status tracking - Added commission calculation integration - Implemented audit logging for all order operations - Created API routes for order management (/api/trades/orders) - Added portfolio and market data endpoints - Created database migration for orders table - Fixed SQLAlchemy reserved name conflict (metadata -> order_metadata) - Fixed import errors and syntax issues API Endpoints: - POST /api/trades/orders - Create and submit order - GET /api/trades/orders - List orders - GET /api/trades/orders/{order_id} - Get order details - POST /api/trades/orders/{order_id}/cancel - Cancel order - GET /api/trades/portfolio - Get portfolio - GET /api/trades/market-data/{symbol} - Get market data - GET /api/trades/orders/history - Get order history Closes #79 Co-authored-by: Tonic <joseph.pollack@emle.eu> * adds debugging , removes logs , improves agent routes (works now) , solves bugs in web search , various toools , responses , and reports * solves display bugs , trading interface , routes , verification routes , trading routes, local reranking , portfolioview , review interface bugs * removes x402 unused snippet with no args, adds else branch x402 * debugs unified dashboard view : trading , now displays * Tradingdash (#155) * fix: handle SecretStr type for LINK_ENCRYPTION_KEY * fix: make debug log path configurable via DEBUG_LOG_PATH env var * adds polymarket and revenuecat initial configuration * Issue #86: Implement Verification Auto-Hydration - Created VerificationHydrationService for embedding documents and data in links - Updated LinkPayloadGenerator to support hydrated payloads (v2.1) - Enhanced VerificationService.generate_verification_link() with auto_hydrate option - Updated /api/remote/verify/{payload} endpoint to handle hydrated payloads - Added /api/remote/verify/{payload}/document/{document_id} endpoint for downloading embedded documents - Implemented access token generation and validation - Added comprehensive tests for hydration functionality - Maintains backward compatibility with non-hydrated links (v2.0) Features: - Self-contained verification links with embedded documents (up to 10MB default) - Base64-encoded document content in encrypted payloads - Access token validation for link security - Automatic extraction of embedded documents on link access - Support for both hydrated and non-hydrated link generation * Issue #83: Native Signature Capture - Complete Implementation * adds dashboard , trading , polymarket , alpaca, orders , securitization , fdc3 compatibility , openfin , alembic migrations , whitelist dashboard , internal markets , atomic swap contracts, notarization , nfts , polymarket signals, tests , organisations , private blockchains , websearch fixes, stock prediction , modal gpus , configurations , revenuecat, x402 subscriptions , tiers, tokens , credits , docs , readme , data caching blockchain services , models , core , db, login --------- Co-authored-by: Biniyam Ajaw <odolbiniyam@gmail.com> Co-authored-by: goliathrr <91191700+biniyam69@users.noreply.github.com> * Addsguides (#156) * solves merge conflict with main * adds debug fixes, dash fixes, alpaca fixes, market data fixes , validators , utiities, fixes serializations , add blockchain services , configs, demotab improvements , env vars , docs, and more * adds bugfix , modal , predictions , market , hydration , session context, history , backtest (#159) * adds debugs , solves hydration in verification demos , heads merge conflict remove , some other fixes as required (#160) * Solves Interface p0 restructuring and core features (#196) * adds debugs , solves hydration in verification demos , heads merge conflict remove , some other fixes as required * adds interface enhancements initial commit (phase1 p0) * bugfixes , auth fixes * adds features , signing , gdpr , documents , orgs , admin , sidebar , datamodels , kyc , sign in sign up * adds phase 1 features, x402 routes, payment providers , sign up sign in , gdpr , client , server , organisations , blockchains , and plaid * adds phase 2 features, routes , interface improvements , portfolio aggregation services, and more * solves conflict markers * initial commit polymarket integration , funding , withdrawals , alpaca broker , polymarket builder api , byok , interface , signin , docs, tests, scripts and more * initial commit alpaca brokerage * adds bugfixes and improvements * adds kyc , user settings * some bug fixes * removes debug instrumentation --------- Co-authored-by: goliathrr <91191700+biniyam69@users.noreply.github.com> Co-authored-by: Biniyam Ajaw <odolbiniyam@gmail.com>
1 parent e5b5bad commit 280f272

158 files changed

Lines changed: 23750 additions & 986 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,32 @@ FILING_CHAIN_MAX_RETRIES=3
230230
SIGNATURE_CHAIN_MAX_RETRIES=3
231231

232232
# =============================================================================
233-
# DigiSigner API Configuration (for Digital Signatures)
233+
# Plaid / Banking (Trading Phase 1)
234234
# =============================================================================
235-
# DigiSigner API key (get from https://www.digisigner.com/)
236-
# Required for digital signature functionality
237-
DIGISIGNER_API_KEY=
238-
# DigiSigner API base URL (default: https://api.digisigner.com/v1)
239-
DIGISIGNER_BASE_URL=https://api.digisigner.com/v1
240-
# Webhook secret for verifying DigiSigner webhook signatures
241-
# Optional but recommended for production
242-
DIGISIGNER_WEBHOOK_SECRET=
235+
# Enable Plaid bank linking (accounts, balances, and transactions) for trading/portfolio views.
236+
# When enabled and correctly configured, the backend exposes:
237+
# - /api/banking/status, /link-token, /connect, /accounts, /balances, /transactions, /disconnect
238+
# and the frontend `LinkAccounts` app uses `react-plaid-link` to open Plaid Link.
239+
# No Plaid secrets are stored in the client; everything flows through these APIs.
240+
PLAID_ENABLED=false
241+
242+
# Plaid API credentials — obtain from the Plaid dashboard.
243+
# For development, use a sandbox or development client ID/secret.
244+
PLAID_CLIENT_ID=
245+
PLAID_SECRET=
246+
247+
# Plaid environment: sandbox, development, or production.
248+
# This controls which Plaid API host is used by `app.services.plaid_service`.
249+
PLAID_ENV=sandbox
250+
251+
# Brokerage funding: link bank (Auth product → processor token → Alpaca ACH), fund (INCOMING), withdraw (OUTGOING).
252+
# Requires PLAID_* above and ALPACA_BROKER_* below. See docs/guides/brokerage-funding.md.
253+
254+
# Plaid Transfer API (instant interbank: RTP when eligible, else ACH). Requires Transfer product enabled in Plaid dashboard.
255+
# Reuses PLAID_CLIENT_ID and PLAID_SECRET from above; no separate Transfer credentials.
256+
PLAID_TRANSFER_ENABLED=false
257+
# Origination account ID from Plaid (for debits). Required when PLAID_TRANSFER_ENABLED=true.
258+
PLAID_TRANSFER_ORIGINATION_ACCOUNT_ID=
243259

244260
# =============================================================================
245261
# Companies House API Configuration (for UK Regulatory Filings)
@@ -255,11 +271,39 @@ COMPANIES_HOUSE_API_KEY=
255271
# See docs/guides/alpaca-trading-setup.md
256272
# Trading: place/cancel orders, portfolio, market data in Trading Dashboard.
257273
# Historical bars: when ALPACA_DATA_ENABLED=true, used for stock prediction and backtest; else yahooquery.
274+
# Note: For multiuser brokerage use ALPACA_BROKER_* below; Trading API vars are for data/backtest only.
258275
ALPACA_BASE_URL=https://paper-api.alpaca.markets
259276
ALPACA_API_KEY=
260277
ALPACA_API_SECRET=
261278
ALPACA_DATA_ENABLED=false
262279

280+
# =============================================================================
281+
# Alpaca Broker API (multiuser brokerage)
282+
# =============================================================================
283+
# Each user gets an Alpaca customer account; orders are placed per account.
284+
# Sandbox: https://broker-api.sandbox.alpaca.markets | Live: https://broker-api.alpaca.markets
285+
ALPACA_BROKER_BASE_URL=https://broker-api.sandbox.alpaca.markets
286+
ALPACA_BROKER_API_KEY=
287+
ALPACA_BROKER_API_SECRET=
288+
ALPACA_BROKER_PAPER=true
289+
290+
# Brokerage onboarding product and optional fee (Plaid link-for-brokerage + payment)
291+
BROKERAGE_ONBOARDING_PRODUCT_ID=brokerage_onboarding
292+
BROKERAGE_ONBOARDING_FEE_ENABLED=false
293+
BROKERAGE_ONBOARDING_FEE_AMOUNT=0.00
294+
BROKERAGE_ONBOARDING_FEE_CURRENCY=USD
295+
296+
# Optional: max single transfer amount for brokerage fund/withdraw (e.g. 25000.00). Leave empty for no limit.
297+
BROKERAGE_MAX_SINGLE_TRANSFER=
298+
299+
# =============================================================================
300+
# Unified funding (credit top-up, Fund Polymarket, Alpaca via x402)
301+
# =============================================================================
302+
# POST /api/funding/request, POST /api/credits/top-up use the payment router (x402 + optional RevenueCat).
303+
# Required: X402_ENABLED and X402_* (see Payment & x402 section below) for MetaMask/facilitator payments.
304+
# Optional: REVENUECAT_ENABLED and REVENUECAT_* for "Add credits" / credit top-up via RevenueCat.
305+
# No additional env vars; funding types: credit_top_up, polymarket_funding, alpaca_funding.
306+
263307
# =============================================================================
264308
# Stock Prediction & Modal (Chronos)
265309
# =============================================================================
@@ -301,6 +345,12 @@ POLYMARKET_GAMMA_API_URL=https://gamma-api.polymarket.com
301345
POLYMARKET_DATA_API_URL=https://data-api.polymarket.com
302346
POLYMARKET_SURVEILLANCE_ENABLED=false
303347
POLYMARKET_PUBLISH_EXTERNAL=false
348+
# Builders Program: order attribution & relayer (obtain from polymarket.com/settings?tab=builder)
349+
POLY_BUILDER_API_KEY=
350+
POLY_BUILDER_SECRET=
351+
POLY_BUILDER_PASSPHRASE=
352+
POLYMARKET_BUILDER_SIGNING_MODE=remote
353+
POLYMARKET_RELAYER_URL=https://relayer-v2.polymarket.com/
304354

305355
# =============================================================================
306356
# Polymarket Cross-Chain (bridge, outcome tokens)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
[![Green Finance](https://img.shields.io/badge/Green-Finance-green?style=flat-square)](https://tonic-ai.mintlify.app/features/green-finance)
2828
[![Join us on Discord](https://img.shields.io/discord/1109943800132010065?label=Discord&logo=discord&style=flat-square)](https://discord.gg/qdfnvSPcqP)
2929

30-
CreditNexus is a next-generation financial operating system that bridges the gap between **Sustainabiity-Linked Loans (Legal Contracts)** and **Physical Reality (Satellite Data)**. It uses AI agents to extract covenants from PDF agreements and orchestrates "Ground Truth" verification using geospatial deep learning.
30+
CreditNexus is a next-generation financial operating system that bridges the gap between **Sustainabiity-Linked Loans (Legal Contracts)** and **Physical Reality (Satellite Data)**. It uses AI agents to extract covenants from PDF agreements and orchestrates "Ground Truth" verification using geospatial deep learning. **Multiuser trading brokerage** is supported via the Alpaca Broker API (one Alpaca customer account per user), with optional Plaid bank linking and onboarding fees.
3131

3232
> 📚 **[Full Documentation](https://tonic-ai.mintlify.app)** | 🏢 **[Company Site](https://josephrp.github.io/creditnexus)** | 🎥 **[Demo Video](https://www.youtube.com/watch?v=jg25So46Wks)**
3333
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""merge deal and internal signature heads
2+
3+
Revision ID: 1245cc8cc703
4+
Revises: 7d47d1a7fd1b, cafedeadbeef
5+
Create Date: 2026-01-28 11:19:05.845874
6+
7+
"""
8+
from typing import Sequence, Union
9+
10+
from alembic import op
11+
import sqlalchemy as sa
12+
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = '1245cc8cc703'
16+
down_revision: Union[str, Sequence[str], None] = ('7d47d1a7fd1b', 'cafedeadbeef')
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
"""Upgrade schema."""
23+
pass
24+
25+
26+
def downgrade() -> None:
27+
"""Downgrade schema."""
28+
pass
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""add document model enhancements
2+
3+
Revision ID: 2345bc8cc704
4+
Revises: 1245cc8cc703
5+
Create Date: 2026-01-28 14:30:00.000000
6+
7+
"""
8+
from typing import Sequence, Union
9+
10+
from alembic import op
11+
import sqlalchemy as sa
12+
from sqlalchemy.dialects import postgresql
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = '2345bc8cc704'
16+
down_revision: Union[str, Sequence[str], None] = '1245cc8cc703'
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
"""Add document model enhancement fields to documents table."""
23+
op.add_column('documents', sa.Column('classification', sa.String(length=50), nullable=True))
24+
op.add_column('documents', sa.Column('status', sa.String(length=50), server_default='draft', nullable=False))
25+
op.add_column('documents', sa.Column('retention_policy', sa.String(length=100), nullable=True))
26+
op.add_column('documents', sa.Column('retention_expires_at', sa.DateTime(), nullable=True))
27+
op.add_column('documents', sa.Column('parent_document_id', sa.Integer(), nullable=True))
28+
op.add_column('documents', sa.Column('compliance_status', sa.String(length=50), server_default='pending', nullable=False))
29+
op.add_column('documents', sa.Column('regulatory_check_metadata', postgresql.JSONB(astext_type=sa.Text()), nullable=True))
30+
31+
op.create_foreign_key('fk_documents_parent_document_id', 'documents', 'documents', ['parent_document_id'], ['id'])
32+
33+
op.create_index(op.f('ix_documents_classification'), 'documents', ['classification'], unique=False)
34+
op.create_index(op.f('ix_documents_status'), 'documents', ['status'], unique=False)
35+
op.create_index(op.f('ix_documents_parent_document_id'), 'documents', ['parent_document_id'], unique=False)
36+
op.create_index(op.f('ix_documents_compliance_status'), 'documents', ['compliance_status'], unique=False)
37+
38+
39+
def downgrade() -> None:
40+
"""Remove document model enhancement fields from documents table."""
41+
op.drop_index(op.f('ix_documents_compliance_status'), table_name='documents')
42+
op.drop_index(op.f('ix_documents_parent_document_id'), table_name='documents')
43+
op.drop_index(op.f('ix_documents_status'), table_name='documents')
44+
op.drop_index(op.f('ix_documents_classification'), table_name='documents')
45+
46+
op.drop_constraint('fk_documents_parent_document_id', 'documents', type_='foreignkey')
47+
48+
op.drop_column('documents', 'regulatory_check_metadata')
49+
op.drop_column('documents', 'compliance_status')
50+
op.drop_column('documents', 'parent_document_id')
51+
op.drop_column('documents', 'retention_expires_at')
52+
op.drop_column('documents', 'retention_policy')
53+
op.drop_column('documents', 'status')
54+
op.drop_column('documents', 'classification')
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""add kyc models
2+
3+
Revision ID: 3456cd9dd805
4+
Revises: 2345bc8cc704
5+
Create Date: 2026-01-28 14:40:00.000000
6+
7+
"""
8+
from typing import Sequence, Union
9+
10+
from alembic import op
11+
import sqlalchemy as sa
12+
from sqlalchemy.dialects import postgresql
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = '3456cd9dd805'
16+
down_revision: Union[str, Sequence[str], None] = '2345bc8cc704'
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
"""Add KYC verification, user licenses, and KYC documents tables."""
23+
# Create kyc_verifications table
24+
op.create_table('kyc_verifications',
25+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
26+
sa.Column('user_id', sa.Integer(), nullable=False),
27+
sa.Column('kyc_status', sa.String(length=50), nullable=False),
28+
sa.Column('kyc_level', sa.String(length=50), nullable=False),
29+
sa.Column('identity_verified', sa.Boolean(), nullable=False),
30+
sa.Column('address_verified', sa.Boolean(), nullable=False),
31+
sa.Column('document_verified', sa.Boolean(), nullable=False),
32+
sa.Column('license_verified', sa.Boolean(), nullable=False),
33+
sa.Column('sanctions_check_passed', sa.Boolean(), nullable=False),
34+
sa.Column('pep_check_passed', sa.Boolean(), nullable=False),
35+
sa.Column('verification_metadata', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
36+
sa.Column('policy_evaluation_result', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
37+
sa.Column('peoplehub_profile_id', sa.String(length=255), nullable=True),
38+
sa.Column('submitted_at', sa.DateTime(), nullable=False),
39+
sa.Column('completed_at', sa.DateTime(), nullable=True),
40+
sa.Column('expires_at', sa.DateTime(), nullable=True),
41+
sa.Column('reviewed_at', sa.DateTime(), nullable=True),
42+
sa.Column('reviewed_by', sa.Integer(), nullable=True),
43+
sa.ForeignKeyConstraint(['reviewed_by'], ['users.id'], ),
44+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
45+
sa.PrimaryKeyConstraint('id'),
46+
sa.UniqueConstraint('user_id')
47+
)
48+
op.create_index(op.f('ix_kyc_verifications_kyc_status'), 'kyc_verifications', ['kyc_status'], unique=False)
49+
50+
# Create kyc_documents table
51+
op.create_table('kyc_documents',
52+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
53+
sa.Column('user_id', sa.Integer(), nullable=False),
54+
sa.Column('kyc_verification_id', sa.Integer(), nullable=True),
55+
sa.Column('document_type', sa.String(length=100), nullable=False),
56+
sa.Column('document_category', sa.String(length=100), nullable=False),
57+
sa.Column('document_id', sa.Integer(), nullable=False),
58+
sa.Column('verification_status', sa.String(length=50), nullable=False),
59+
sa.Column('extracted_data', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
60+
sa.Column('ocr_confidence', sa.Float(), nullable=True),
61+
sa.Column('created_at', sa.DateTime(), nullable=False),
62+
sa.ForeignKeyConstraint(['document_id'], ['documents.id'], ),
63+
sa.ForeignKeyConstraint(['kyc_verification_id'], ['kyc_verifications.id'], ondelete='CASCADE'),
64+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
65+
sa.PrimaryKeyConstraint('id')
66+
)
67+
op.create_index(op.f('ix_kyc_documents_kyc_verification_id'), 'kyc_documents', ['kyc_verification_id'], unique=False)
68+
op.create_index(op.f('ix_kyc_documents_user_id'), 'kyc_documents', ['user_id'], unique=False)
69+
70+
# Create user_licenses table
71+
op.create_table('user_licenses',
72+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
73+
sa.Column('user_id', sa.Integer(), nullable=False),
74+
sa.Column('kyc_verification_id', sa.Integer(), nullable=True),
75+
sa.Column('license_type', sa.String(length=100), nullable=False),
76+
sa.Column('license_number', sa.String(length=255), nullable=False),
77+
sa.Column('license_category', sa.String(length=50), nullable=False),
78+
sa.Column('issuing_authority', sa.String(length=255), nullable=False),
79+
sa.Column('issue_date', sa.Date(), nullable=True),
80+
sa.Column('expiration_date', sa.Date(), nullable=True),
81+
sa.Column('document_id', sa.Integer(), nullable=True),
82+
sa.Column('verification_status', sa.String(length=50), nullable=False),
83+
sa.Column('created_at', sa.DateTime(), nullable=False),
84+
sa.Column('updated_at', sa.DateTime(), nullable=False),
85+
sa.ForeignKeyConstraint(['document_id'], ['documents.id'], ),
86+
sa.ForeignKeyConstraint(['kyc_verification_id'], ['kyc_verifications.id'], ondelete='CASCADE'),
87+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
88+
sa.PrimaryKeyConstraint('id')
89+
)
90+
op.create_index(op.f('ix_user_licenses_kyc_verification_id'), 'user_licenses', ['kyc_verification_id'], unique=False)
91+
op.create_index(op.f('ix_user_licenses_user_id'), 'user_licenses', ['user_id'], unique=False)
92+
93+
94+
def downgrade() -> None:
95+
"""Remove KYC verification, user licenses, and KYC documents tables."""
96+
op.drop_index(op.f('ix_user_licenses_user_id'), table_name='user_licenses')
97+
op.drop_index(op.f('ix_user_licenses_kyc_verification_id'), table_name='user_licenses')
98+
op.drop_table('user_licenses')
99+
op.drop_index(op.f('ix_kyc_documents_user_id'), table_name='kyc_documents')
100+
op.drop_index(op.f('ix_kyc_documents_kyc_verification_id'), table_name='kyc_documents')
101+
op.drop_table('kyc_documents')
102+
op.drop_index(op.f('ix_kyc_verifications_kyc_status'), table_name='kyc_verifications')
103+
op.drop_table('kyc_verifications')

0 commit comments

Comments
 (0)