Spaces:
Running
Running
File size: 4,172 Bytes
abc493d b2f5bb7 a381fc9 b2f5bb7 73e0e3c abc493d a381fc9 abc493d a381fc9 abc493d eda9962 abc493d a381fc9 abc493d 73e0e3c abc493d a381fc9 abc493d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import * as path from 'path';
// pg returns TIMESTAMP WITHOUT TIME ZONE (OID 1114) as a bare string like
// "2026-06-19 14:45:00.123456" with no timezone indicator. Node's Date
// constructor treats that as *local* time, baking the server's TZ offset
// into the serialised JSON before the browser ever sees it.
// Force both timestamp OIDs to be parsed as UTC so the stored value is
// faithfully preserved — Python always writes utcnow() (UTC, naive).
// eslint-disable-next-line @typescript-eslint/no-require-imports
const pgTypes = require('pg').types;
pgTypes.setTypeParser(1114, (v: string) =>
v ? new Date(v.replace(' ', 'T') + 'Z') : null,
);
pgTypes.setTypeParser(1184, (v: string) => (v ? new Date(v) : null));
import { SqliteDateSubscriber } from './common/sqlite-date.subscriber';
import { AgentRunsModule } from './agent-runs/agent-runs.module';
import { AuthModule } from './auth/auth.module';
import { AgentRun } from './common/entities/agent-run.entity';
import { AnalystReport } from './common/entities/analyst-report.entity';
import { Notification } from './common/entities/notification.entity';
import { PortfolioSnapshot } from './common/entities/portfolio-snapshot.entity';
import { Position } from './common/entities/position.entity';
import { RetrospectiveReport } from './common/entities/retrospective-report.entity';
import { Setting } from './common/entities/setting.entity';
import { Strategy } from './common/entities/strategy.entity';
import { Transaction } from './common/entities/transaction.entity';
import { User } from './common/entities/user.entity';
import { DashboardModule } from './dashboard/dashboard.module';
import { NotificationsModule } from './notifications/notifications.module';
import { PortfolioModule } from './portfolio/portfolio.module';
import { ReportsModule } from './reports/reports.module';
import { RetrospectiveReportsModule } from './retrospective-reports/retrospective-reports.module';
import { SettingsModule } from './settings/settings.module';
import { StrategiesModule } from './strategies/strategies.module';
import { TransactionsModule } from './transactions/transactions.module';
import { UsersModule } from './users/users.module';
// Resolve root .env whether running from api/ (dev) or project root (prod)
const ROOT_DIR = path.resolve(__dirname, '..', '..'); // api/dist → project root
const ENV_PATH = path.join(ROOT_DIR, '.env');
export const UI_DIST = path.join(ROOT_DIR, 'ui', 'dist');
const ENTITIES = [
User,
Setting,
Strategy,
AgentRun,
AnalystReport,
Position,
Transaction,
PortfolioSnapshot,
Notification,
RetrospectiveReport,
];
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, envFilePath: ENV_PATH }),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (cfg: ConfigService) => {
const url = cfg.get<string>('DATABASE_URL');
if (url && url.startsWith('postgresql')) {
// Neon PostgreSQL — strip channel_binding which pg driver doesn't support
const cleanUrl = url
.replace('&channel_binding=require', '')
.replace('?channel_binding=require&', '?');
return {
type: 'postgres' as const,
url: cleanUrl,
ssl: { rejectUnauthorized: false },
entities: ENTITIES,
synchronize: false,
};
}
// Fallback: local SQLite (dev without DATABASE_URL)
return {
type: 'better-sqlite3' as const,
database: path.join(ROOT_DIR, 'data', 'stockadvisor.db'),
entities: ENTITIES,
subscribers: [SqliteDateSubscriber],
synchronize: false,
};
},
}),
AuthModule,
UsersModule,
AgentRunsModule,
ReportsModule,
RetrospectiveReportsModule,
TransactionsModule,
PortfolioModule,
StrategiesModule,
NotificationsModule,
DashboardModule,
SettingsModule,
],
})
export class AppModule {}
|