Omie Holley
← All case studies

Being the Entire Product Team Across Two Fashion-Tech Businesses

Led architecture for a bespoke manufacturer and its digital tech-pack partner. I separated their shared AWS environment, decomposed one overloaded database into Tech Packs, WMS, and per-facility WES systems, and rebuilt the tech-pack application.

Role
System Architect / Full-Stack Engineer (Lead)
Where
Fashion technical-design startup & partnered bespoke manufacturer
  • TypeScript
  • Remix (React)
  • Vue (legacy)
  • PostgreSQL
  • MySQL
  • Prisma
  • AWS CDK
  • CodePipeline / CodeBuild
  • ECS Fargate
  • AWS Lambda
  • AWS DMS
  • TailwindCSS
  • Figma

Context

I joined through a former manager who asked me to lead systems architecture for two partnered companies: a bespoke manufacturer building a franchise-able production model, and a fashion technical-design startup building digital tech packs. A tech pack is the structured specification a factory uses to turn a design into a manufactured garment. Because the businesses shared operational systems, the architecture had to support both while establishing clear ownership boundaries.

There was no PM or designer. I owned product discovery, UI design, and engineering: I interviewed working fashion designers, defined personas and roadmaps, designed in Figma, and implemented the product across the stack.

What I Walked Into

Both businesses ran in one default VPC with no environment or company boundary. Databases were on public subnets. Hundreds of reused security groups had no naming convention or documented ownership, so it was unclear which rules were deprecated and which were required by active workloads. Deployments were also manual: build a JAR from the CLI, copy it to a server over SSH, and manually validate the release for hours.

flowchart TB
    subgraph Before ["Deployments: before"]
        direction LR
        A["Build JAR via CLI"] --> B["SSH file transfer<br/>to server"] --> C["Hours of manual<br/>validation"]
    end
    subgraph After ["Deployments: after"]
        direction LR
        M["Merge to main /<br/>dev / test branch"] --> P["CodePipeline<br/>triggers CodeBuild"] --> I["Docker image<br/>built & tagged"] --> F["ECS Fargate task<br/>deploys image"] --> H["Health checks pass"] --> T["Load balancer swaps<br/>to new target group"]
    end
    Before ~~~ After

Re-architecting the Cloud

I rebuilt the AWS footprint with CDK infrastructure as code. Each application received a repeatable deployment definition rather than a set of manually managed resources:

  • Segmented VPCs: production, test, and development replaced the single default VPC.
  • Per-application CI/CD: CDK provisioned CodeBuild, CodePipeline, ECR, ECS on Fargate, and an application load balancer for each app.
  • Scoped security groups: each application received CDK-owned, named rules instead of relying on the reused pool of unnamed groups.
  • Per-facility Lambda overrides: versioned functions let each warehouse facility customize execution behavior without forking the platform
  • Private database placement: databases were moved off public subnets as part of the security remediation.
flowchart TB
    subgraph CDK ["Per application: provisioned by CDK"]
        CB["CodeBuild"] --> CP["CodePipeline"]
    end
    CDK --> PROD & TEST & DEV
    subgraph PROD ["Production VPC"]
        SG["Scoped security group"] --> ECS["ECR → ECS Fargate → ALB"]
        L["Per-facility Lambda<br/>overrides (versioned)"]
    end
    TEST["Test VPC"]
    DEV["Development VPC"]

Untangling the Data

The data model was the harder problem. One schema served both businesses, and key entities had no single source of truth. Some tables were shared across companies. The manufacturer was opening a second facility, but digital tech-pack data needed to remain global rather than being duplicated per facility. I needed to split a live database according to data ownership: facility-scoped execution data could scale horizontally, while tech-pack data remained centralized.

I normalized the data model to 3NF and migrated it live with AWS DMS, with zero data loss. The resulting system had three databases with explicit responsibilities:

  1. Digital Tech Packs (PostgreSQL): the startup's product and global source of truth.
  2. WMS (MySQL): orders and multi-warehouse management, shared across facilities.
  3. WES (MySQL, per facility): warehouse execution, one database per facility so new facilities scale by stamping out another instance

The order-processing integration connected the systems without collapsing their boundaries. Cron jobs read incoming orders, retrieve the associated tech pack, build a facility-specific order detail, and dispatch it to that facility's WES. The WES queues work for industrial fabric-cutting and printing machines and coordinates autonomous bots that move fabric bins across the floor.

flowchart LR
    O["3rd-party<br/>ordering sites"] -->|cron jobs| WMSA["WMS application"]
    WMSA --> WMSD[("MySQL WMS<br/>orders & multi-warehouse")]
    TP[("PostgreSQL<br/>Digital Tech Packs<br/>(global source of truth)")] -->|"pull tech pack<br/>per order"| CRON["Cron: build facility-specific<br/>order detail"]
    WMSD --> CRON
    CRON --> WES1[("MySQL WES<br/>Facility 1")]
    CRON --> WES2[("MySQL WES<br/>Facility 2")]
    WES1 --> M1["Cutting & printing machine queues<br/>· autonomous fabric-bin bots"]

Rebuilding the Tech-Pack Product

The startup's production app was a Vue application with long screen loads and a fragmented sub-application workflow. To add fabrics to a tech pack, users had to close the tech pack, open a separate application, add fabrics, return, refresh, and import them. Validation was limited, leaving manufacturing-relevant user errors uncaught.

I rebuilt it as a Remix full-stack application. Server-side calculations and validation rejected user errors before data reached production. I moved fabric management into the tech-pack workflow, eliminating the cross-application import loop, and improved load times. Working designers used the product throughout development, which kept feedback cycles to days. I built more than 95% of the application myself, from Figma mockups to production code.

Outcome

  • Established separate infrastructure, deployment, and data-ownership boundaries for two partnered businesses
  • Created a franchise-able facility model: opening a warehouse means provisioning a WES instance and its Lambda overrides instead of untangling shared tables
  • Replaced manual SSH releases with health-checked ECS Fargate pipeline cutovers
  • Converted an undocumented environment into documented, CDK-managed infrastructure
  • Replaced fragmented sub-app workflows with one faster, validated tech-pack flow