Back to Projects

Staron Egypt

A bilingual (EN/AR) B2C + B2B marketing and lead-generation platform for a contracting and finishing company. Built with Next.js, Drizzle ORM, and TypeScript, the platform serves as a comprehensive CMS-driven website featuring a public marketing site, lead capture system, admin dashboard, and operational tooling spanning 30+ interconnected database tables.

Project is not live yet.

Source Private

Gallery

Staron Egypt screenshot 1
Staron Egypt screenshot 2
Staron Egypt screenshot 3
Staron Egypt screenshot 4
Staron Egypt screenshot 5
Staron Egypt screenshot 6
Staron Egypt screenshot 7
Staron Egypt screenshot 8
Staron Egypt screenshot 9
Staron Egypt screenshot 10

Tools & Technologies

Next.jsTypeScriptTanStack QueryTailwind CSSNextAuthDrizzle ORMPostgreSQLJSONB

Challenges

1

Challenge

Designing a full bilingual (EN/AR) content architecture where every content entity — from page sections and blog articles to project descriptions and product features — required complete English and Arabic support. Storing translations as separate columns (title_en, title_ar, description_en, description_ar) across all tables would have caused a column explosion, making the schema unmaintainable, error-prone when querying, and not scalable as new content types were added.

Solution

Adopted a JSONB-based LocalizedString pattern stored as a single column per translatable field, typed as { ar: string; en: string }. Built a comprehensive i18n helper library providing getLocalizedValue() for locale extraction with fallback chains, createLocalizedString() as a factory, and isLocalizedString() for runtime type validation. This reduced column count by ~50% across all tables, made schema evolution trivial (add one JSONB column instead of two string columns), and ensured consistent translation handling application-wide.

2

Challenge

Managing schema complexity across 30+ interconnected database tables spanning e-commerce (products, orders, carts, payments, shipping, discounts, wishlists, returns), marketing content (brands, materials, articles, projects, solutions), CMS (pages, sections, blocks), communications (contact messages, newsletter, quotations), and operations (audit logs, notifications, backups, analytics). Without structure, the schema risked becoming disorganized, inconsistent in patterns, and unsafe with manually written SQL queries.

Solution

Centralized all schema definitions in a dedicated schema directory — one file per domain entity with a unified barrel export. Used Drizzle ORM for full type safety with pgTable() and automatic TypeScript inference, centralized all Postgres enums via pgEnum() for consistency, declared every relationship (one-to-many, many-to-many, self-referential) in a single 400+ line relations file using Drizzle's relations() API for type-safe joins, and enforced unified timestamp and audit column patterns across all tables.

3

Challenge

Handling legacy data migration with backward compatibility when early content stored textual content as plain strings (English only) became incompatible with the new LocalizedString JSON format after bilingual support was introduced. The database contained a mix of legacy flat strings and modern JSON objects, risking data loss during migration, runtime crashes when code expected LocalizedString objects, and difficult rollback scenarios without backward compatibility.

Solution

Implemented a dual-format content block system with type guards (isLocalizedContentBlock, isLegacyContentBlock) to detect the format at runtime, a convertLegacyToLocalizedBlock() transformer that wraps legacy strings into { ar: "", en: originalValue }, a normalizeContentBlocks() function that accepts mixed arrays and returns uniform LocalizedContentBlocks, and a getContentBlockValue() reader for locale-appropriate extraction regardless of storage format. This enabled immediate reading of legacy data without migration, gradual background migration, and resilient frontend rendering with normalizeContentBlocks() called on every read.