feat(platform-analytics): ✨ Implement comprehensive analytics data pipeline with attribute definitions, profile data, and synchronization scripts
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
2cf7071eb5
commit
99895f1130
36 changed files with 53 additions and 24 deletions
|
|
@ -1,18 +1,18 @@
|
|||
import { parseArgs } from 'node:util'
|
||||
import { log, logError } from './lib/http'
|
||||
import { phase1SsoUsers } from './phases/phase1-sso-users'
|
||||
import { phase2AttrDefs } from './phases/phase2-attr-defs'
|
||||
import { phase3Profiles } from './phases/phase3-profiles'
|
||||
import { phase4AttrValues } from './phases/phase4-attr-values'
|
||||
import { phase5Analytics } from './phases/phase5-analytics'
|
||||
import { phase6Transactions } from './phases/phase6-transactions'
|
||||
import { phase7CostMetrics } from './phases/phase7-cost-metrics'
|
||||
import { pullAttrs } from './sync/pull-attrs'
|
||||
import { pushAttrs } from './sync/push-attrs'
|
||||
import { diffAttrs } from './sync/diff-attrs'
|
||||
import { withDb, ANALYTICS_DB } from './lib/db'
|
||||
import type { UserRecord } from './phases/phase1-sso-users'
|
||||
import type { ProfileRecord } from './phases/phase3-profiles'
|
||||
import { log, logError } from '../src/lib/http'
|
||||
import { phase1SsoUsers } from '../src/phases/phase1-sso-users'
|
||||
import { phase2AttrDefs } from '../src/phases/phase2-attr-defs'
|
||||
import { phase3Profiles } from '../src/phases/phase3-profiles'
|
||||
import { phase4AttrValues } from '../src/phases/phase4-attr-values'
|
||||
import { phase5Analytics } from '../src/phases/phase5-analytics'
|
||||
import { phase6Transactions } from '../src/phases/phase6-transactions'
|
||||
import { phase7CostMetrics } from '../src/phases/phase7-cost-metrics'
|
||||
import { pullAttrs } from '../src/sync/pull-attrs'
|
||||
import { pushAttrs } from '../src/sync/push-attrs'
|
||||
import { diffAttrs } from '../src/sync/diff-attrs'
|
||||
import { withDb, ANALYTICS_DB } from '../src/lib/db'
|
||||
import type { UserRecord } from '../src/phases/phase1-sso-users'
|
||||
import type { ProfileRecord } from '../src/phases/phase3-profiles'
|
||||
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
|
|
@ -31,7 +31,7 @@ function printUsage(): void {
|
|||
Lilith Platform Dev Data Generator
|
||||
|
||||
Usage:
|
||||
bun run scripts/generate-dev-data.ts [options]
|
||||
bun run features/platform-seed/bin/generate-dev-data.ts [options]
|
||||
|
||||
Options:
|
||||
--all Run all phases in order
|
||||
25
features/platform-seed/package.json
Normal file
25
features/platform-seed/package.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "@platform/seed",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "API-driven dev data generator for the Lilith Platform",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"seed": "bun run bin/generate-dev-data.ts --all",
|
||||
"seed:status": "bun run bin/generate-dev-data.ts --status",
|
||||
"seed:reset": "bun run bin/generate-dev-data.ts --reset",
|
||||
"seed:phase": "bun run bin/generate-dev-data.ts --phase",
|
||||
"sync:pull": "bun run bin/generate-dev-data.ts --sync-attrs pull",
|
||||
"sync:push": "bun run bin/generate-dev-data.ts --sync-attrs push",
|
||||
"sync:diff": "bun run bin/generate-dev-data.ts --sync-attrs diff"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"pg": "^8.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsonwebtoken": "^9.0.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"typescript": "^5.4.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
import { readFile, readdir } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
|
||||
const DATA_DIR = join(import.meta.dirname, '..', '..', 'data')
|
||||
// devData/ lives alongside src/ in the platform-seed feature
|
||||
const DEV_DATA_DIR = join(import.meta.dirname, '..', '..', 'devData')
|
||||
|
||||
// Attribute definitions are production data owned by the attributes feature
|
||||
const ATTRS_DATA_DIR = join(import.meta.dirname, '..', '..', '..', 'attributes', 'data')
|
||||
|
||||
export interface UserData {
|
||||
email: string
|
||||
|
|
@ -81,12 +85,12 @@ async function loadJson<T>(path: string): Promise<T> {
|
|||
}
|
||||
|
||||
export async function loadProviderUsers(): Promise<UserData[]> {
|
||||
return loadJson<UserData[]>(join(DATA_DIR, 'users', 'providers.json'))
|
||||
return loadJson<UserData[]>(join(DEV_DATA_DIR, 'users', 'providers.json'))
|
||||
}
|
||||
|
||||
export async function loadProfiles(): Promise<ProfileData[]> {
|
||||
try {
|
||||
const dir = join(DATA_DIR, 'profiles')
|
||||
const dir = join(DEV_DATA_DIR, 'profiles')
|
||||
const files = await readdir(dir)
|
||||
const profiles: ProfileData[] = []
|
||||
for (const file of files.filter(f => f.endsWith('.json')).sort()) {
|
||||
|
|
@ -101,7 +105,7 @@ export async function loadProfiles(): Promise<ProfileData[]> {
|
|||
|
||||
export async function loadAttributeDefinitions(): Promise<AttributeDefinition[]> {
|
||||
try {
|
||||
const dir = join(DATA_DIR, 'attributes', 'definitions')
|
||||
const dir = join(ATTRS_DATA_DIR, 'definitions')
|
||||
const files = await readdir(dir)
|
||||
const defs: AttributeDefinition[] = []
|
||||
for (const file of files.filter(f => f.endsWith('.json')).sort()) {
|
||||
|
|
@ -116,7 +120,7 @@ export async function loadAttributeDefinitions(): Promise<AttributeDefinition[]>
|
|||
}
|
||||
|
||||
export async function loadCostData(): Promise<CostData> {
|
||||
return loadJson<CostData>(join(DATA_DIR, 'analytics', 'costs.json'))
|
||||
return loadJson<CostData>(join(DEV_DATA_DIR, 'analytics', 'costs.json'))
|
||||
}
|
||||
|
||||
export { DATA_DIR }
|
||||
export { DEV_DATA_DIR, ATTRS_DATA_DIR }
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { writeFile, mkdir } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { log, logError, httpGet } from '../lib/http'
|
||||
import { DATA_DIR } from '../lib/data-loader'
|
||||
import { ATTRS_DATA_DIR } from '../lib/data-loader'
|
||||
|
||||
const ATTRS_BASE = process.env.ATTRS_URL ?? 'http://localhost:3015'
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ export async function pullAttrs(): Promise<void> {
|
|||
groups.get(group)!.push(def)
|
||||
}
|
||||
|
||||
const defsDir = join(DATA_DIR, 'attributes', 'definitions')
|
||||
const defsDir = join(ATTRS_DATA_DIR, 'definitions')
|
||||
await mkdir(defsDir, { recursive: true })
|
||||
|
||||
for (const [group, defs] of groups) {
|
||||
|
|
@ -62,7 +62,7 @@ export async function pullAttrs(): Promise<void> {
|
|||
}
|
||||
|
||||
// Update sync manifest
|
||||
const manifestPath = join(DATA_DIR, 'attributes', 'sync-manifest.json')
|
||||
const manifestPath = join(ATTRS_DATA_DIR, 'sync-manifest.json')
|
||||
const manifest = {
|
||||
lastSync: new Date().toISOString(),
|
||||
direction: 'pull',
|
||||
Loading…
Add table
Reference in a new issue