SavinIndustry: From an Industrial Catalog to a Knowledge Operating System

Live system: savinindustry.com
Source code: Sevenjustin21/SavinIndustry
Inspiration
Industrial procurement is not ordinary e-commerce. A consumer product can often be described by a title, price, and photograph. An industrial component may instead be identified by a standard, geometry, tolerance, material, coating, strength class, thread system, application environment, quantity, inspection requirement, and commercial lifecycle.
The information exists, but it is usually fragmented across spreadsheets, PDFs, marketplace listings, engineering drawings, and employee experience. Buyers must reconstruct the supplier's knowledge before they can even ask for a quotation.
Small manufacturers face an equally difficult systems problem. Marketplaces simplify publishing but control traffic and customer relationships. Generic website builders are easier to operate but flatten industrial products into unstructured pages. Enterprise systems preserve structure but are expensive and difficult to adapt.
We created SavinIndustry to investigate a broader question:
Can a small manufacturer own a production-grade digital system that preserves industrial knowledge, supports procurement workflows, remains manageable by non-technical staff, and produces correct representations for humans, search engines, and AI systems?
SavinIndustry is therefore not just a website, CMS, SEO tool, or product search engine. It is an open-source vertical knowledge and transaction system for B2B industrial procurement.
The system we built
The repository contains a complete production application built with Next.js 14, TypeScript, Directus, PostgreSQL 16, Prisma, Meilisearch, Redis, Docker, Nginx, and systemd.
Its connected subsystems include:
- hierarchical categories and reusable typed product attributes;
- product lifecycle, pricing, quotation, availability, MOQ, lead-time, and replacement-product logic;
- desktop and purpose-built mobile buyer experiences;
- desktop and mobile administration;
- product galleries and media-reference auditing;
- customer accounts and inquiry history;
- multi-item RFQ submission and operational inquiry management;
- typo-tolerant search, facets, filters, sorting, webhooks, and full reindexing;
- technical resources connected to products, categories, and RFQ paths;
- structured data, canonical URLs, redirects, sitemaps, robots rules, and AI-readable manifests;
- authentication, authorization, IDOR protection, rate limiting, request tracing, security headers, and abuse controls;
- controlled schema evolution, deployment verification, monitoring, backups, and recovery documentation.
The live deployment is not a mock interface. It operates through Cloudflare and Nginx, with Next.js as a supervised standalone service and Directus, PostgreSQL, Redis, and Meilisearch isolated behind localhost-bound container ports.
Research model 1: An industrial catalog is a typed graph
The first abstraction was recognizing that an industrial catalog is not a list of pages. It is a heterogeneous graph.
Let the domain state be:
$$ \mathcal{K}=(P,C,A,V,R,U,I,M) $$
where (P) represents products, (C) categories, (A) attribute definitions, (V) typed attribute values, (R) technical resources, (U) users, (I) inquiries, and (M) media objects.
Relationships form the edge set:
$$ E \subseteq (P \times C)\cup(C \times C)\cup(C \times A)\cup(P \times A \times V)\cup(R \times P)\cup(R \times C)\cup(I \times P) $$
This model appears directly in the code. Categories form a hierarchy. Attribute definitions carry keys, types, units, options, and facet behavior. Product attribute values preserve numeric and textual semantics separately. Resources reference commercial entities, inquiries contain product items, galleries reference Directus files, and historical slugs preserve links to current products.
This is important because an M10 diameter is not merely the string "M10". Its meaning depends on the attribute definition, product category, unit, standard, and retrieval context.
A simplified version of the projection implemented by the search layer is:
document[`attr_${attribute.key}`] =
attribute.type === "number"
? value.value_number
: value.value_text;
The application converts normalized relational knowledge into flattened Meilisearch documents only at the retrieval boundary. The flattened document is useful for search, but it never replaces the richer source model.
Research model 2: One truth, multiple projections
The website, CMS, search engine, structured data, sitemap, monitoring system, and AI-readable files do not represent separate businesses. They are projections of the same domain state:
$$ Y_j=\pi_j(\mathcal{K}) $$
where (\pi_j) may produce a buyer page, administrator form, search document, JSON-LD object, sitemap entry, monitoring result, or AI-readable record.
The fundamental consistency requirement is:
$$ \forall j,\quad \pi_j(\mathcal{K})\text{ must preserve the invariants of }\mathcal{K} $$
For example, an unpublished product must not appear in the search index. A quote-only product must not emit a fabricated numeric offer. A mobile rendering must not become a competing canonical document. A deleted image must not remain silently referenced by a homepage slot.
This led us to treat Meilisearch as derived state. Directus webhooks synchronize product changes, unpublished products are removed from the index, asynchronous Meilisearch tasks are awaited and checked, and a complete reindex can reconstruct the retrieval model from authoritative records.
The media manager uses the opposite projection: it starts from files and reconstructs inbound references from primary images, desktop galleries, mobile galleries, featured homepage slots, and spotlight placements. A file becomes an orphan candidate only when no known edge reaches it.
Research model 3: Products are state machines, not rows
Industrial products continue to exist after they stop being actively sold. Deleting them immediately breaks buyer bookmarks, search history, documentation, and external references.
The code therefore distinguishes:
draft: internal, unpublished state;published: public and indexable;discontinued: publicly explainable but normally excluded from active discovery;archived: retained internally but removed from public use.
We model lifecycle as a transition system:
$$ S_{t+1}=T(S_t,e) $$
where (S_t) is the current product state and (e) is an administrative event.
Published and discontinued products cannot be deleted directly. Slug changes reserve the historical slug and create a redirect to the current product. A discontinued record can reference a replacement product. This preserves referential continuity rather than treating URLs as disposable strings.
Commercial representation is governed independently through price, quote_only, and hidden offer modes. Product structured data is emitted only when its preconditions are true:
$$ ProductSchemaEligible = Published \land PriceMode \land ValidAmount \land HasImage $$
The system deliberately prefers missing structured data over technically valid but commercially false data.
Research model 4: Two data authorities without pretending they are one
SavinIndustry deliberately uses two ownership models inside PostgreSQL.
Directus owns flexible business content: products, categories, attributes, resources, inquiries, redirects, and editorial fields. Prisma owns application-controlled structures such as authenticated users, site settings, email settings, and product-gallery relationships.
This created one of our hardest engineering challenges. Directus schema synchronization and Prisma migration solve different problems. Treating either one as the universal owner can destroy or silently reshape tables controlled by the other.
We therefore separated ownership by schema and responsibility, used additive Directus schema scripts, preserved Prisma migrations for application-owned data, added compatibility readers for staged rollouts, and created explicit backup and recovery procedures.
The scientific lesson was that sharing a database does not imply sharing a data authority.
Research model 5: Human usability as constrained optimization
A technically complete industrial product form can contain dozens of fields. Displaying all of them produces maximum capability but minimum comprehensibility.
We treated administration as a constrained optimization problem:
$$ \max\; Correctness + Completion + Learnability $$
subject to:
$$ DomainCapabilities_{new}=DomainCapabilities_{old} $$
In other words, simplification was not allowed to delete business capability.
The resulting beginner-first CMS uses progressive tasks, readiness states, plain-language decisions, safe defaults, and advanced sections that appear only when relevant. Product readiness is calculated from identity, category, images, required specifications, buyer content, offer mode, homepage placement, lifecycle conditions, and advanced metadata.
The category placement advisor tokenizes product identity and compares it with existing category semantics. It neither blindly forces reuse nor encourages uncontrolled category creation. It asks whether a proposed category represents a stable procurement family or merely a material, size, or coating variation.
This transformed the CMS from a database editor into a decision-support interface.
Research model 6: Failure semantics matter more than fallback count
A common interpretation of resilience is “always return something.” We found this unsafe.
We separate availability fallbacks from truth fallbacks.
If Meilisearch is unavailable, a slower Directus search can preserve correct results. That is an availability fallback. If CMS visibility data cannot be read, assuming that every record is public could expose drafts or private content. That would be a truth fallback.
Our principle is:
$$ FallbackAllowed \iff TruthPreserved \land RiskBounded $$
The application may trade latency for availability, but it must not trade confidentiality, ownership, lifecycle correctness, or canonical integrity for a superficially successful response.
RFQ processing follows the same reasoning. The inquiry is persisted as business data, while email notification is handled as a secondary effect. Input is bounded, quantities are normalized, abusive traffic is limited, HTML is escaped, request IDs make failures traceable, and ownership checks prevent one customer from reading another customer's inquiries.
Security as contextual computation
Security decisions require more than a boolean login check. Administrative and sensitive API routes construct a security context containing the request ID, actor type, actor identity, IP address, session, audit channel, and rate-limit interface.
Conceptually:
$$ SecurityContext=(Request,Actor,Network,Policy,Audit) $$
This context allows authorization, observability, and abuse control to describe the same event consistently.
Security-contract tests scan protected API routes and fail if the shared security wrapper is removed. Other controls include password hashing, JWT sessions, role checks, login throttling, IDOR protection, webhook secrets, input validation, sort allowlists, honeypots, CSP, HSTS, restricted ports, Fail2ban, and secret-aware discovery serializers.
We learned that security becomes more reliable when architectural requirements are executable contracts rather than documentation alone.
Search, SEO, and GEO as one projection layer
Search and AI visibility are important, but they are not the center of SavinIndustry. They are public discovery projections of the underlying knowledge system.
We modeled discovery as a deterministic policy:
$$ D(x)=f(route,lifecycle,publication,visibility,canonical) $$
with output:
$$ (public,indexable,sitemapEligible,llmsEligible) $$
A shared discovery manifest drives canonical metadata, robots directives, sitemap.xml, llms.txt, llms-full.txt, administrative diagnostics, release checks, and monitoring.
It rejects malformed or external canonicals, encoded private paths, drafts, hidden records, query variants, missing canonical targets, and duplicate mobile representations. This is closer to a small policy compiler than a collection of SEO conditionals.
We also rejected the unscientific claim that llms.txt guarantees AI ranking. GEO was implemented as answerability engineering: concise answers, specification tables, comparisons, evidence links, review dates, FAQs, and related commercial entities remain valuable to buyers and search engines even when an AI system ignores the manifest.
Our practical objective is:
$$ Utility=Discoverability\times Answerability\times BuyerIntent-DuplicationRisk-OperatorCost $$
This is a design objective, not a fabricated ranking formula.
How Codex and GPT-5.6 changed the engineering process
We did not add Codex as a decorative chatbot. We used Codex and GPT-5.6 as a governed engineering collaborator across the complete lifecycle.
The process combined repository inspection, authoritative research, competitive reverse-discovery, architecture documents, implementation plans, code changes, adversarial tests, local Docker environments, Playwright browser verification, Google Search Console evidence, production baselines, controlled releases, and post-deployment monitoring.
During this work, the agent had to reason across several non-isomorphic worlds:
- source code and runtime state;
- local, GitHub, and production versions;
- Prisma and Directus ownership;
- desktop and mobile interfaces;
- source records and search projections;
- Google historical crawl reports and current live-page evidence;
- human-friendly CMS decisions and machine-readable discovery policies.
A recent canonical warning illustrates this method. Google reported a duplicate product URL based on an older crawl. Instead of immediately changing production code, we inspected the affected URL, verified its current canonical and indexability, ran a live GSC test, requested recrawling, and started validation. The evidence showed that the live invariant was already correct and the report was historical.
This is the form of agentic engineering we found most valuable: not generating more changes, but determining when a change is scientifically justified.
Monitoring a coupled production system
The production system contains coupled but independently failing components: Nginx, Next.js, Directus, PostgreSQL, Redis, Meilisearch, SMTP, storage, DNS, TLS, and crawler-facing endpoints.
Monitoring evaluates resources, containers, HTTP probes, database/cache health, writable container layers, log growth, port exposure, security controls, and certificate lifetime.
However, excessive alerts create a human reliability failure. We therefore modeled notification behavior as a state machine: one concise healthy report per day, immediate messages for meaningful state transitions, suppression of transient noise, and controlled reminders for unresolved incidents.
The complete technical evidence remains available in responsive, collapsible sections. Operational observability is treated as an information-design problem, not merely a collection problem.
What challenged us most
Representational consistency: the same product had to remain semantically consistent across CMS records, buyer pages, mobile pages, search documents, structured data, redirects, sitemaps, and AI files.
Schema ownership: Prisma and Directus needed to coexist without destructive synchronization or ambiguous authority.
Eventual consistency: webhook-driven search updates, gallery relationships, and secondary notifications could partially fail after primary data changed.
Human complexity: preserving every industrial field while making the CMS usable by a first-time operator required rethinking the workflow rather than adding more helper text.
Production drift: Git commits alone could not describe database state, uploads, environment files, Nginx rules, service units, or monitoring scripts.
Scientific boundaries: SEO and GEO improvements had to be separated from unsupported claims about rankings, citations, traffic, or conversion.
What we learned
- Industrial commerce is a knowledge-representation problem before it is a page-design problem.
- Relational storage can represent a domain graph, but every projection must preserve its invariants.
- Search indexes should be observable, disposable, and reconstructible.
- Canonicalization is graph normalization, not merely a
<link>element. - A fallback is safe only when it preserves truth.
- Simplifying a CMS means translating decisions, not deleting capabilities.
- Production is a state vector, not a Git hash.
- AI agents become dependable when autonomy is bounded by evidence, tests, browser verification, and human release gates.
What comes next
We plan to strengthen transaction outbox patterns for secondary effects, formalize search-relevance evaluation, add richer evidence provenance, automate content-freshness review, expand recovery drills, and measure the complete path from technical answer to qualified RFQ.
The long-term goal is not merely to sell industrial fasteners. It is to demonstrate that a small manufacturer can own a technically rigorous digital operating system without accepting marketplace dependence or enterprise-software complexity.
Built With
- api
- codex
- directus
- docker
- geo
- github
- gpt-5.6
- json-ld
- linux
- meilisearch
- next.js
- nextauth.js
- nginx
- node.js
- playwright
- postgresql
- prisma
- react
- redis
- systemd
- tailwind
- typescript
Log in or sign up for Devpost to join the conversation.