Zip Code Platform
Platform for centralizing Romanian postal codes: background Excel import, address normalization, lookup by city, street, and number, API validation, and access-key administration.

Core stack
The challenge
The challenge was turning an Excel dataset with cities, counties, streets, and variable expressions for building numbers into a lookup service that could tolerate spelling differences without blocking the application during import. At the same time, API access had to be separated by manageable keys, and the operator needed visibility into the import and the uploaded data.
The solution
The solution separates the import from the web request through a Laravel Job and processes the file in chunks of 500 rows with PhpSpreadsheet. A dedicated service parses counties, Bucharest sectors, and number ranges, then performs bulk inserts after checking for duplicates. Progress is published to the cache and tracked from the admin panel via polling. The API normalizes the address before lookup, uses several fallback levels, and is protected by the API-key middleware with activation and expiration, while the Blade panel provides administration of the dataset, users, and keys.
Notable complexity
Zip Code Platform is a Laravel application built to turn an operational postal-code file into a queryable database and a reusable API for e-commerce applications or other systems that need address validation and completion. The repository includes a simple public surface, user accounts, an administration panel, and a key-protected API.
The data flow starts in the admin panel, where an Excel .xlsx/.xls file can be uploaded. The controller saves it locally, determines the row count, and dispatches a Laravel Job onto the database-configured queue. The import reads the file in windows of 500 rows and limits the processed columns to postal code, city/county, and street. For each row, the city and county are separated, Bucharest sectors are interpreted, and number expressions are turned into ranges or individual values. Writes happen in batches, after checking for already-existing combinations. Progress is kept temporarily in the Laravel Cache and the admin interface polls it periodically without keeping the upload request open for the entire processing duration.
The API exposes four dedicated operations: postal code lookup from an address, the list of cities, validating a postal code, and normalizing an address. The lookup normalizes diacritics and county abbreviations, tries variants of the street name, and applies a sequence of fallbacks: match with number, match on street, fuzzy match, and finally city + county. Access is filtered by an API-key middleware that checks existence, active status, and expiration date.
The administrative panel covers three main areas: postal codes, users, and API keys. The tables support filtering, sorting, and pagination, and the administrator can generate keys for a user, set an expiration date, and activate or deactivate them. The authenticated user has their own dashboard for account data and associated keys. The UI is server-rendered with Blade and Tailwind, with Alpine.js for navigation/modal interactions and plain JavaScript for polling the import progress.
The code also contains the beginning of a commercial flow with Stripe Checkout, a webhook that would generate a temporary key after checkout, and a download route for a plugin. These areas are not complete in the analyzed snapshot: the Stripe configuration is missing from services.php, the webhook is placed in the authenticated web group, the payment form does not call the processing route, payments are not persisted by this flow, and the plugin archive does not exist in the repository. For this reason they are treated as a product direction, not as a delivered result.
For production, the important next steps are hardening the API and the import: explicit request validation, per-key rate limiting, hashed key storage with one-time display, fully parameterized fuzzy fallback, unique/upsert constraints for concurrent deduplication, indexes aligned with the actual queries, and explicit retry/cleanup for the import job. The repository contains no CI/CD workflows, Docker, or reproducible deployment configuration; however, the standard Laravel /up endpoint and local scripts for build, test, and the queue worker are present.
Key results
- Laravel 12 application with public, authenticated user, admin, and API surfaces
- Background .xlsx/.xls Excel import executed via a Laravel Job and database-configured queue
- Incremental file processing in windows of 500 rows and bulk insertion of normalized data
- Parsing for Romanian counties, Bucharest sectors, and street number ranges
- Import progress kept in cache and tracked from the admin interface via polling
- API with endpoints for search, cities, validate, and normalize
- API authentication via keys with active status and optional expiration date
- Postal code lookup with address matching and fallbacks on street, fuzzy terms, and city
- Administration with filtering, sorting, and pagination for postal codes and users
- API key administration: per-user generation, optional expiration, and activation/deactivation
- Standard Laravel health-check endpoint at /up
Related projects
- GrileAMGA training ecosystem for nursing assistants: courses, multiple-choice questions, exam simulations, statistics, and tests distributed by teachers, across web, iOS, and Android, with subscriptions, AI, and editorial administration.
- Risa TimeA digital ecosystem for picking up a customer's car, transporting it to a partner car wash, and returning it safely, coordinated through separate customer and driver apps, an operations panel, and real-time tracking.
- MixboxA multi-vendor marketplace for local products, with a single cart spanning multiple stores, separate apps for customer, merchant, and courier, flexible payments, and an advanced system for importing and managing supplier catalogs.
Want something similar?
Start with the estimate wizard — answer a few questions and get a realistic price range and timeline.