You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

264 lines
7.2 KiB

import { PrismaClient } from '@prisma/client';
import { createHmac } from 'node:crypto';
const prisma = new PrismaClient();
const ACCESS_TOKEN_SALT =
process.env.ACCESS_TOKEN_SALT ?? 'agentforge-dev-salt-2026';
function hashToken(plain: string): string {
return createHmac('sha512', ACCESS_TOKEN_SALT).update(plain).digest('hex');
}
async function main() {
// Tags — always seeded (upstream default)
await prisma.tag.createMany({
data: [
{ id: '4452656d-9fa4-4bd0-ba38-70492e31d180', name: 'EMERGENCY_FUND' },
{
id: 'f2e868af-8333-459f-b161-cbc6544c24bd',
name: 'EXCLUDE_FROM_ANALYSIS'
}
],
skipDuplicates: true
});
// Demo portfolio data — opt-in via SEED_DEMO_DATA=true
if (process.env.SEED_DEMO_DATA === 'true') {
const DEMO_USER_ID = '403deeb8-edd5-4e64-99a9-3752782ad0a2';
const DEMO_ACCOUNT_ID = 'c2a0c0f6-366b-4992-97ac-1adfa81d6cbc';
const DEMO_ACCESS_TOKEN_PLAIN = 'demo-token-2026';
// Demo user
await prisma.user.upsert({
where: { id: DEMO_USER_ID },
update: {},
create: {
id: DEMO_USER_ID,
accessToken: hashToken(DEMO_ACCESS_TOKEN_PLAIN),
provider: 'ANONYMOUS',
role: 'ADMIN'
}
});
// Demo account
await prisma.account.upsert({
where: {
id_userId: { id: DEMO_ACCOUNT_ID, userId: DEMO_USER_ID }
},
update: {},
create: {
id: DEMO_ACCOUNT_ID,
userId: DEMO_USER_ID,
name: 'Main Brokerage',
balance: 5000,
currency: 'USD',
isExcluded: false
}
});
// Symbol profiles
const symbols = [
{
id: 'd8f0b8c3-212c-48ef-a837-fff75ef98176',
symbol: 'AAPL',
name: 'Apple Inc.',
currency: 'USD',
dataSource: 'YAHOO' as const,
assetClass: 'EQUITY' as const,
assetSubClass: 'STOCK' as const
},
{
id: '5bb696ab-aaf3-4924-a0e4-79c69bfcd81b',
symbol: 'MSFT',
name: 'Microsoft Corporation',
currency: 'USD',
dataSource: 'YAHOO' as const,
assetClass: 'EQUITY' as const,
assetSubClass: 'STOCK' as const
},
{
id: '7df6544c-c592-459c-af69-aafe65db60c9',
symbol: 'VOO',
name: 'Vanguard S&P 500 ETF',
currency: 'USD',
dataSource: 'YAHOO' as const,
assetClass: 'EQUITY' as const,
assetSubClass: 'ETF' as const
},
{
id: 'ba75d50e-34f6-4c9e-bbb7-71b43b7cbfc0',
symbol: 'GOOGL',
name: 'Alphabet Inc.',
currency: 'USD',
dataSource: 'YAHOO' as const,
assetClass: 'EQUITY' as const,
assetSubClass: 'STOCK' as const
},
{
id: '8b846370-2e16-4594-9785-a94da15d60a1',
symbol: 'bitcoin',
name: 'Bitcoin',
currency: 'USD',
dataSource: 'COINGECKO' as const,
assetClass: 'ALTERNATIVE_INVESTMENT' as const,
assetSubClass: 'CRYPTOCURRENCY' as const
}
];
for (const sp of symbols) {
await prisma.symbolProfile.upsert({
where: {
dataSource_symbol: { dataSource: sp.dataSource, symbol: sp.symbol }
},
update: {},
create: {
id: sp.id,
symbol: sp.symbol,
name: sp.name,
currency: sp.currency,
dataSource: sp.dataSource,
assetClass: sp.assetClass,
assetSubClass: sp.assetSubClass
}
});
}
// Resolve actual symbolProfile IDs (may differ if profiles pre-existed)
const profileLookup = new Map<string, string>();
for (const sp of symbols) {
const found = await prisma.symbolProfile.findUnique({
where: {
dataSource_symbol: { dataSource: sp.dataSource, symbol: sp.symbol }
},
select: { id: true }
});
if (found) {
profileLookup.set(sp.id, found.id);
}
}
// Orders
const orders = [
{
id: '49f6cba4-7dd2-47e1-918e-4d8538e3818f',
seedProfileId: 'd8f0b8c3-212c-48ef-a837-fff75ef98176',
type: 'BUY' as const,
quantity: 15,
unitPrice: 178.5,
fee: 0,
date: new Date('2024-03-15'),
currency: 'USD'
},
{
id: '7090411c-a046-4363-a89e-d61d28417820',
seedProfileId: '5bb696ab-aaf3-4924-a0e4-79c69bfcd81b',
type: 'BUY' as const,
quantity: 10,
unitPrice: 420.0,
fee: 0,
date: new Date('2024-04-01'),
currency: 'USD'
},
{
id: '06cd0784-c5f4-42a0-b799-eb48b61b7afb',
seedProfileId: '7df6544c-c592-459c-af69-aafe65db60c9',
type: 'BUY' as const,
quantity: 20,
unitPrice: 480.0,
fee: 0,
date: new Date('2024-01-10'),
currency: 'USD'
},
{
id: '151b2a27-f82f-4393-85b2-a57660fc2d25',
seedProfileId: 'ba75d50e-34f6-4c9e-bbb7-71b43b7cbfc0',
type: 'BUY' as const,
quantity: 8,
unitPrice: 155.0,
fee: 0,
date: new Date('2024-06-20'),
currency: 'USD'
},
{
id: 'abc07d0a-3be2-4185-9ae4-d2b0fa4a5d48',
seedProfileId: '8b846370-2e16-4594-9785-a94da15d60a1',
type: 'BUY' as const,
quantity: 0.5,
unitPrice: 43000.0,
fee: 0,
date: new Date('2024-02-01'),
currency: 'USD'
},
{
id: 'e3a1f7c2-8d94-4b61-a5e3-9c72d1f08e34',
seedProfileId: 'd8f0b8c3-212c-48ef-a837-fff75ef98176',
type: 'BUY' as const,
quantity: 5,
unitPrice: 195.0,
fee: 0,
date: new Date('2024-09-15'),
currency: 'USD'
},
{
id: 'f7b2c8d1-6e45-4a93-b812-d3e9f0a17c56',
seedProfileId: '7df6544c-c592-459c-af69-aafe65db60c9',
type: 'DIVIDEND' as const,
quantity: 0,
unitPrice: 1.78,
fee: 0,
date: new Date('2024-12-20'),
currency: 'USD'
},
{
id: 'a1c3e5f7-2b4d-4869-9a0c-e6f8d2b4a7c1',
seedProfileId: '5bb696ab-aaf3-4924-a0e4-79c69bfcd81b',
type: 'SELL' as const,
quantity: 3,
unitPrice: 450.0,
fee: 0,
date: new Date('2025-01-10'),
currency: 'USD'
}
];
for (const ord of orders) {
const symbolProfileId = profileLookup.get(ord.seedProfileId);
if (!symbolProfileId) {
console.warn(
`Skipping order ${ord.id}: no symbolProfile found for seed ID ${ord.seedProfileId}`
);
continue;
}
await prisma.order.upsert({
where: { id: ord.id },
update: { symbolProfileId },
create: {
id: ord.id,
userId: DEMO_USER_ID,
accountId: DEMO_ACCOUNT_ID,
accountUserId: DEMO_USER_ID,
symbolProfileId,
type: ord.type,
quantity: ord.quantity,
unitPrice: ord.unitPrice,
fee: ord.fee,
date: ord.date,
currency: ord.currency
}
});
}
console.log('Seeded demo user, account, symbols, and orders.');
console.log(` Login token: ${DEMO_ACCESS_TOKEN_PLAIN}`);
}
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});