NestJS backend for the InsightArena prediction market platform.
- Node.js 20+
- pnpm 9 —
npm install -g pnpm - PostgreSQL database
- Make
make install
# or directly
pnpm install --frozen-lockfilecp .env.example .env
# Edit .env with your local DB credentials and secrets| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://user:pass@localhost:5432/insightarena |
JWT_SECRET |
Secret for signing JWTs — min 32 chars | any long random string |
JWT_EXPIRES_IN |
JWT expiry duration | 7d |
STELLAR_NETWORK |
Stellar network to connect to | testnet or mainnet |
SOROBAN_CONTRACT_ID |
Deployed Soroban contract ID — leave as placeholder until contract is deployed | your-contract-id-here |
SERVER_SECRET_KEY |
Stellar secret key used by the server to sign transactions. Generate one at Stellar Laboratory or run node -e "const sdk=require('@stellar/stellar-sdk'); console.log(sdk.Keypair.random().secret())" |
SXXXXX... |
PORT |
HTTP port the server listens on | 3000 |
Note:
SERVER_SECRET_KEYmust be a valid Stellar secret key starting withS. On testnet you can generate and fund one for free at Stellar Laboratory.
# Run migrations
pnpm run migration:run
# Generate a new migration
pnpm run migration:generate -- src/migrations/MigrationName
# Revert last migration
pnpm run migration:revert# Development (watch mode)
pnpm run start:dev
# Standard start
pnpm run start
# Production
pnpm run start:prodAPI: http://localhost:3000/api/v1
Swagger: http://localhost:3000/api/v1/docs
Endpoint: GET /api/v1/health (public, no auth)
Verifies:
- HTTP service is responding
- PostgreSQL connection is active
- Disk space is available (alerts at 90% usage)
curl -f http://localhost:3000/api/v1/health || exit 1# 1. Create a feature branch
git checkout -b feature/your-feature-name
# 2. Develop with watch mode
pnpm run start:dev
# 3. Run CI checks before committing
make ci
# 4. Commit and push only if all checks pass
git add .
git commit -m "feat: describe your change"
git push origin feature/your-feature-nameAlways run the full pipeline before committing. This mirrors exactly what GitHub Actions runs.
make ciThis runs in order:
- ✅ ESLint — code quality
- ✅ Jest unit tests — all
*.spec.tsfiles - ✅ TypeScript build — via NestJS CLI
make lint # Run ESLint only
make test # Run Jest only
make build # Build only
make clean # Remove dist/ and coverage/
make help # List all targets# Auto-fix most issues
pnpm run lint
# Check without fixing
pnpm run lint -- --fix=false
# Check a specific file
pnpm run lint -- src/path/to/file.ts# Run a specific test file
pnpm run test -- roles.guard.spec.ts
# Run in watch mode for debugging
pnpm run test:watch
# Run with coverage report
pnpm run test:cov# Clean and rebuild
make clean && make buildnpm install -g pnpmUbuntu/Debian:
sudo apt-get install build-essentialmacOS:
xcode-select --installWindows: Use WSL or run commands directly:
pnpm run lint && pnpm run test && pnpm run buildEnsure DATABASE_URL in .env is correct:
DATABASE_URL=postgresql://user:password@localhost:5432/insightarena
This happens when a TypeORM @Column decorator is on a property typed as a union (e.g. string | null) without an explicit type. TypeScript emits Object as the reflected metadata for union types, which TypeORM can't map to Postgres.
Fix: Always specify type explicitly on nullable columns:
// ❌ Bad — TypeScript emits Object for string | null
@Column({ nullable: true })
my_field: string | null;
// ✅ Good — explicit type prevents the issue
@Column({ type: 'text', nullable: true })
my_field: string | null;
// ✅ Good — for UUID foreign keys
@Column({ type: 'uuid', nullable: true })
resolved_by: string | null;The database table hasn't been created yet. You need to run migrations:
pnpm migration:runIf migration:run says "No migrations are pending" but the table still doesn't exist, the migration path glob may not be resolving. As a one-time fix you can temporarily set synchronize: true in src/app.module.ts, start the server once to create all tables, then set it back to false.
When you add or change an entity, always generate a migration — never rely on synchronize: true in production:
# Generate a migration from entity diff
pnpm migration:generate src/migrations/DescribeYourChange
# Review the generated file before running it
# Make sure it only contains the changes you expect — not a full schema dump
# Apply it
pnpm migration:runWarning: If
migration:generateproduces a file that recreates existing tables (users, markets, etc.), it means it diffed against an empty database instead of your live one. Delete that file and check yourDATABASE_URLis pointing to the correct database before regenerating.
- Avoid
any— use strict types - Prefer interfaces for object shapes
- Use enums for fixed value sets
- Write unit tests for all guards, services, and controllers
- Target >80% code coverage
- Test both success and error paths
- Use descriptive test names
- ESLint rules must pass (
make lint) - Prettier handles formatting (configured in
.prettierrc) - No unused variables or imports
- Check README.md for setup instructions
- Open an issue for bugs or questions
- Join the community on Telegram: https://t.me/+hR9dZKau8f84YTk0