Skip to main content
2026Full-Stack Platform

Inventory Lifecycle Engine

Hosted inventory platform with OIDC auth, tenant-scoped APIs, read-only demo controls, and containerized delivery.

Inventory Lifecycle Engine is a React/Vite, FastAPI, PostgreSQL, Keycloak, and Alembic platform for products, locations, stock batches, expiration windows, quarantined stock, and depleted inventory across organizations.

ReactTypeScriptViteFastAPIPostgreSQLNeonSQLAlchemyAlembicKeycloakOIDC/PKCEDocker ComposeRender
Inventory dashboardInventory product workflowInventory notification workflow

Evidence

Case Study Highlights

Hosted

Vercel frontend, Render API/IAM, Neon PostgreSQL

4

CI workflow types

OIDC

Authorization Code + PKCE

403

read-only demo blocks mutating API methods

Context

Problem and ownership

The original inventory tracker was a single-user PyQt and SQLite application. The current implementation keeps the inventory domain but moves the system to a browser client, token-secured API, PostgreSQL persistence, organization membership model, batch lifecycle views, and a hosted read-only demo.

My role

Designed the backend API, tenant-aware data model, OIDC integration, read-only demo safeguards, deployment topology, and legacy import path.

Constraints

What shaped the solution

  • The legacy domain needed to be preserved instead of discarded.
  • Authentication and tenant boundaries needed to use OIDC claims, Keycloak-issued tokens, and service-layer authorization instead of client-only checks.
  • The public demo needed real data and login while preventing writes through both viewer role assignment and API middleware.
  • Local startup needed to preserve the full topology: web, API, database, Keycloak, migrations, demo seed, and test services.
  • Database schema changes and legacy imports needed repeatable Alembic and CLI paths instead of ad hoc table creation.

Architecture

System design and request flow

The deployed system separates browser delivery, API execution, identity, and persistence. Vercel serves the React/Vite client; Render runs the FastAPI API and Keycloak containers; Neon hosts PostgreSQL. The browser authenticates through Keycloak with Authorization Code + PKCE, then sends a bearer token to the API, which validates issuer, audience, expiry, and JWKS signature before reading organization-scoped inventory data.

Request and Data Flow

  1. 1User browser
  2. 2Vercel React/Vite web client
  3. 3Render Keycloak OIDC login
  4. 4Render FastAPI service layer
  5. 5Neon PostgreSQL persistence
  6. 6Alembic migrations and demo seed path
  7. 7Docker Compose local runtime

Core Components

  • Frontend uses React Router, TanStack Query, React Hook Form, Zod, and generated API types for inventory workflows.
  • Backend exposes versioned FastAPI routes for organizations, products, locations, batches, and current-user identity.
  • Service-layer authorization enforces viewer, inventory_manager, admin, and owner role thresholds before tenant data is read or mutated.
  • Database models cover organizations, OIDC users, memberships, products, locations, batches, and audit events.
  • Docker Compose models local DB, Keycloak, migrations, API, web, demo seed, and test services.

Technical decisions

Key choices and why they mattered

Used Keycloak instead of custom authentication

Keycloak provides OIDC token issuance, JWKS discovery, realm/client configuration, and local parity with the hosted identity container.

Used Authorization Code with PKCE

The browser client authenticates without a client secret, then the API validates the bearer token server-side before resolving the user and memberships.

Enforced the public demo as read-only at the API boundary

The demo account is assigned a viewer role, and DEMO_READ_ONLY middleware rejects POST, PUT, PATCH, and DELETE requests under the versioned API prefix with 403.

Moved from SQLite to PostgreSQL with Alembic

The production schema uses SQLAlchemy models and versioned Alembic migrations; legacy SQLite data moves through an idempotent importer with dry-run and duplicate-prevention paths.

Trade-offs

What the design optimizes for and gives up

  • Keycloak adds runtime and deployment complexity, but it keeps authentication standards-based and avoids handwritten login/session code.
  • The hosted demo is read-only, so reviewers can inspect real workflows without risking persistent data mutation.
  • Vercel, Render, and Neon split deployment concerns, but require explicit CORS, OIDC redirect, database, and startup configuration.
  • Docker Compose is heavier than a single process, but it preserves the service boundaries used by the hosted system.

Production readiness

Reliability, security, and delivery evidence

  • Backend, frontend, integration, and Docker build workflows validate API tests, frontend builds, compose integration, and image builds.
  • OpenAPI contract coverage asserts that versioned inventory routes and documented response schemas are present.
  • Backend Dockerfile uses builder, runtime, test, and production targets; frontend Dockerfile builds with Node 22 and serves the Vite output through Nginx.
  • Render config runs the API as a Docker web service, applies Alembic migrations, seeds demo data, and exposes health checks.
  • Health and readiness endpoints separate process liveness from database availability.

Results

What changed because of the work

  • Converted a single-user desktop workflow into a hosted multi-service platform with web, API, identity, and database boundaries.
  • Added organization-scoped products, locations, batches, memberships, roles, and audit events.
  • Exposed a public read-only demo and live FastAPI documentation without making the demo database writable.
  • Kept local development reproducible through Docker Compose and explicit migration/seed commands.

Next improvements

Where I would take it next

  • Add UI coverage for role-gated controls so viewer, inventory_manager, admin, and owner behavior is tested from the browser layer.
  • Expose audit event search and export workflows for operational review.
  • Add latency and cold-start measurements for Render-hosted API and Keycloak containers.