F000B - Shared Packages Integration
Objective
Integrate MyStoryFlow shared packages into the analyzer-app for consistent functionality across the monorepo.
Package Overview
@mystoryflow/auth
Shared authentication using Supabase SSR.
Integration:
// src/components/providers.tsx
import { AuthProvider } from '@mystoryflow/auth'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<AuthProvider>
{children}
</AuthProvider>
)
}Usage in Components:
import { useAuth, requireAuth } from '@mystoryflow/auth'
export default requireAuth(function ManuscriptsPage() {
const { user, signOut } = useAuth()
return (
<div>
<h1>Welcome, {user.email}</h1>
</div>
)
})@mystoryflow/ui
Shared UI components and design system.
Available Components:
- Button, Input, Select, Textarea
- Card, Modal, Drawer
- Table, DataGrid
- Navigation, Sidebar
- LoadingSpinner, ErrorBoundary
- Toast notifications
Usage:
import {
Button,
Card,
PageHeader,
DataTable
} from '@mystoryflow/ui'
export function ManuscriptsList() {
return (
<div>
<PageHeader
title="My Manuscripts"
action={
<Button href="/manuscripts/new">
Upload Manuscript
</Button>
}
/>
<Card>
<DataTable
columns={columns}
data={manuscripts}
/>
</Card>
</div>
)
}@mystoryflow/analytics
Privacy-first analytics with AI usage tracking.
Setup AI Tracking:
// src/lib/ai-tracker.ts
import { createAITracker } from '@mystoryflow/analytics'
export const aiTracker = createAITracker({
appName: 'analyzer',
trackingEndpoint: process.env.NEXT_PUBLIC_ADMIN_APP_URL + '/api/ai-usage'
})
// Usage in AI services
import { aiTracker } from '@/lib/ai-tracker'
async function analyzeManuscript(content: string) {
const startTime = Date.now()
try {
const result = await openai.chat.completions.create({
model: 'gpt-4-turbo',
messages: [{ role: 'user', content }],
max_tokens: 4000
})
// Track AI usage
await aiTracker.track({
feature: 'manuscript-analysis',
model: 'gpt-4-turbo',
tokens: result.usage?.total_tokens || 0,
duration: Date.now() - startTime,
success: true
})
return result
} catch (error) {
await aiTracker.track({
feature: 'manuscript-analysis',
model: 'gpt-4-turbo',
tokens: 0,
duration: Date.now() - startTime,
success: false,
error: error.message
})
throw error
}
}@mystoryflow/database
Shared database types and utilities.
Extend for Analyzer:
// src/types/database.ts
import { Database as BaseDatabase } from '@mystoryflow/database'
export interface AnalyzerTables {
manuscripts: {
Row: {
id: string
user_id: string
title: string
// ... analyzer specific fields
}
}
// ... other analyzer tables
}
export type Database = BaseDatabase & {
analyzer: AnalyzerTables
}@mystoryflow/shared
Common utilities and constants.
Available Utilities:
- Date formatting
- File size formatting
- URL utilities
- Validation schemas
- Error handling
import {
formatDate,
formatFileSize,
createErrorResponse,
validateEmail
} from '@mystoryflow/shared'
// Use throughout the app
const displayDate = formatDate(manuscript.created_at)
const fileSize = formatFileSize(manuscript.file_size)@mystoryflow/admin
Admin dashboard components and utilities.
Admin Integration for Analyzer:
// apps/web/src/app/(admin)/admin/manuscripts/page.tsx
import {
AdminLayout,
StatsCard,
DataTable,
AnalyticsChart
} from '@mystoryflow/admin'
export default function ManuscriptsAdminPage() {
return (
<AdminLayout>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<StatsCard
title="Total Manuscripts"
value={stats.totalManuscripts}
icon="document"
/>
<StatsCard
title="Analyses Today"
value={stats.analysesToday}
icon="chart"
trend={stats.analysisTrend}
/>
<StatsCard
title="AI Tokens Used"
value={stats.tokensUsed}
icon="cpu"
/>
<StatsCard
title="Success Rate"
value={`${stats.successRate}%`}
icon="check-circle"
/>
</div>
<AnalyticsChart
title="Analysis Trends"
data={analysisData}
type="line"
/>
<DataTable
title="Recent Manuscripts"
columns={manuscriptColumns}
data={manuscripts}
searchable
exportable
/>
</AdminLayout>
)
}Admin API Integration:
// apps/web/src/app/api/admin/manuscripts/route.ts
import { adminService } from '@mystoryflow/admin'
import { requireAdminAuth } from '@mystoryflow/auth/admin'
export async function GET(request: Request) {
// Verify admin access
const { user } = await requireAdminAuth(request)
// Use admin service for data fetching
const stats = await adminService.getManuscriptStats()
const manuscripts = await adminService.getRecentManuscripts()
return Response.json({
stats,
manuscripts
})
}AI Usage Tracking in Admin:
// apps/web/src/app/(admin)/admin/ai-usage/page.tsx
import {
AdminLayout,
MetricsTable,
UsageChart,
ExportButton
} from '@mystoryflow/admin'
import { aiTracker } from '@/lib/ai-tracker'
export default function AIUsageAdminPage() {
const usage = await aiTracker.getAdminMetrics()
return (
<AdminLayout>
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">AI Usage Analytics</h1>
<ExportButton data={usage} filename="ai-usage-report" />
</div>
<UsageChart
data={usage.byModel}
groupBy="model"
metric="tokens"
/>
<MetricsTable
title="Usage by Feature"
data={usage.byFeature}
columns={[
{ key: 'feature', label: 'Feature' },
{ key: 'calls', label: 'API Calls' },
{ key: 'tokens', label: 'Tokens Used' },
{ key: 'cost', label: 'Estimated Cost' }
]}
/>
</AdminLayout>
)
}Reference Data Management:
// apps/web/src/app/(admin)/admin/reference-data/page.tsx
import {
AdminLayout,
FilterPanel,
BulkActions
} from '@mystoryflow/admin'
import { useReferenceData } from '@/lib/reference-data'
export default function ReferenceDataAdminPage() {
const collections = [
'manuscript-genres',
'analysis-statuses',
'consultation-types',
'coach-specialties'
]
return (
<AdminLayout>
<h1 className="text-2xl font-bold mb-6">Reference Data Management</h1>
<FilterPanel
filters={[
{
key: 'collection',
label: 'Collection',
type: 'select',
options: collections.map(c => ({
label: c.replace(/-/g, ' ').toUpperCase(),
value: c
}))
}
]}
values={filterValues}
onChange={handleFilterChange}
onReset={handleReset}
/>
<ReferenceDataEditor
collection={selectedCollection}
onSave={handleSave}
/>
</AdminLayout>
)
}Navigation Integration
Cross-App Navigation
// src/components/app-navigation.tsx
import { Navigation } from '@mystoryflow/ui'
import { useAuth } from '@mystoryflow/auth'
const navigationItems = [
{
label: 'Dashboard',
href: '/dashboard',
icon: 'dashboard'
},
{
label: 'My Manuscripts',
href: '/manuscripts',
icon: 'document'
},
{
label: 'Analysis History',
href: '/analysis',
icon: 'chart'
}
]
const appSwitcher = [
{
label: 'Main App',
href: 'https://app.mystoryflow.com',
icon: 'home'
},
{
label: 'Tools',
href: 'https://tools.mystoryflow.com',
icon: 'tools'
},
{
label: 'Analyzer',
href: 'https://analyzer.mystoryflow.com',
icon: 'analyze',
active: true
}
]
export function AppNavigation() {
const { user } = useAuth()
return (
<Navigation
items={navigationItems}
appSwitcher={appSwitcher}
user={user}
appName="Analyzer"
/>
)
}Styling Integration
Use Shared Tailwind Config
// tailwind.config.ts
import baseConfig from '@mystoryflow/ui/tailwind.config'
export default {
...baseConfig,
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'../../packages/ui/src/**/*.{js,ts,jsx,tsx}'
],
theme: {
extend: {
...baseConfig.theme.extend,
colors: {
...baseConfig.theme.extend.colors,
// Analyzer-specific colors
'analyzer': {
50: '#f0f9ff',
500: '#3b82f6',
900: '#1e3a8a'
}
}
}
}
}Testing Integration
Use Shared Test Utilities
// __tests__/manuscripts.test.ts
import {
createMockUser,
createMockSupabase,
setupTestDatabase
} from '@mystoryflow/shared/test-utils'
describe('Manuscripts', () => {
beforeEach(async () => {
await setupTestDatabase('analyzer')
})
it('should create manuscript', async () => {
const user = createMockUser()
const supabase = createMockSupabase()
// Test implementation
})
})Build Configuration
Update package.json Scripts
{
"scripts": {
"dev": "next dev -p 3005",
"build": "next build",
"test": "jest",
"lint": "eslint . --ext .ts,.tsx",
"type-check": "tsc --noEmit",
"with-env": "dotenv -e ../../.env.local --",
"analyze:bundle": "ANALYZE=true next build"
}
}Verification Checklist
- Auth flows work (sign in/up/out)
- UI components render correctly
- Analytics tracking fires
- AI usage appears in admin dashboard
- Cross-app navigation works
- Shared styles apply correctly
- Database types extend properly
Next Steps
Proceed to F001-PROJECT-SETUP to configure analyzer-specific branding and features.