Files
lunarfront-app/packages/backend/src/main.ts
Ryan Moon 1132e0999b Add products, inventory units, stock receipts, and price history
- product table (catalog definition, no cost column — cost tracked
  per receipt/unit)
- inventory_unit table (serialized items with serial number,
  condition, status)
- stock_receipt table (FIFO cost tracking — records every stock
  receive event with cost_per_unit, supplier, date)
- price_history table (logs every retail price change for margin
  analysis over time)
- product_supplier join table (many-to-many, tracks supplier SKU
  and preferred supplier)
- Full CRUD routes + search (name, SKU, UPC, brand)
- Inventory unit routes nested under products
- Price changes auto-logged on product update
- 33 tests passing
2026-03-27 18:22:39 -05:00

64 lines
1.9 KiB
TypeScript

import Fastify from 'fastify'
import { databasePlugin } from './plugins/database.js'
import { redisPlugin } from './plugins/redis.js'
import { corsPlugin } from './plugins/cors.js'
import { errorHandlerPlugin } from './plugins/error-handler.js'
import { authPlugin } from './plugins/auth.js'
import { devAuthPlugin } from './plugins/dev-auth.js'
import { healthRoutes } from './routes/v1/health.js'
import { authRoutes } from './routes/v1/auth.js'
import { accountRoutes } from './routes/v1/accounts.js'
import { inventoryRoutes } from './routes/v1/inventory.js'
import { productRoutes } from './routes/v1/products.js'
export async function buildApp() {
const app = Fastify({
logger: {
level: process.env.LOG_LEVEL ?? 'info',
...(process.env.NODE_ENV === 'development' ? { transport: { target: 'pino-pretty' } } : {}),
},
genReqId: () => crypto.randomUUID(),
})
// Plugins
await app.register(corsPlugin)
await app.register(errorHandlerPlugin)
await app.register(databasePlugin)
await app.register(redisPlugin)
// Auth — use JWT if secret is set, otherwise dev bypass
if (process.env.JWT_SECRET) {
await app.register(authPlugin)
} else {
await app.register(devAuthPlugin)
}
// Routes
await app.register(healthRoutes, { prefix: '/v1' })
await app.register(authRoutes, { prefix: '/v1' })
await app.register(accountRoutes, { prefix: '/v1' })
await app.register(inventoryRoutes, { prefix: '/v1' })
await app.register(productRoutes, { prefix: '/v1' })
return app
}
async function start() {
const app = await buildApp()
const port = parseInt(process.env.PORT ?? '8000', 10)
const host = process.env.HOST ?? '0.0.0.0'
try {
await app.listen({ port, host })
} catch (err) {
app.log.error(err)
process.exit(1)
}
}
// Only auto-start when not imported by tests
if (process.env.NODE_ENV !== 'test') {
start()
}