Delivered remotely for a business based in Atlanta, United States. Names withheld by agreement.
Project Overview
Industry: Local business directory and community media.
Type of solution: A REST API and administrative platform with a native iOS application, combining a searchable business directory, a subscription listing model, an editorial blog and issue-based digital publications.
Business context: A directory's value to a consumer is proportional to how complete it is, and its value to a business is proportional to how many consumers use it. Neither condition is true at launch. Most directories try to solve this with sales effort, recruiting businesses one at a time into a product that cannot yet demonstrate an audience. That is slow, expensive, and frequently fails before the flywheel starts turning.
General users: Consumers browsing and reviewing local businesses and reading published content; business owners creating or claiming and then managing their listings; and the operator's administrative and editorial team.
General purpose: To make local businesses discoverable, to give business owners a controllable presence with paid enhancement options, and to sustain consumer engagement through regular editorial and published content.
The Business Challenge
The directory cold-start problem. An empty directory is worthless to consumers, and a directory with no consumers is worthless to businesses. Something has to break the deadlock before either side has a reason to participate.
Businesses will not do the data entry. Asking a business owner to register, complete a profile, upload images and enter opening hours before they have seen any benefit is a conversion path with a very low completion rate.
Consumers need a reason to return. Directory use is episodic — people visit when they need something specific. Between those moments there is no reason to open the app, and an app that is not opened is eventually deleted.
Listing data is inherently messy. Opening hours vary by day, include multiple periods, and have exceptions. Addresses arrive inconsistently. Categories overlap. All of it has to be structured enough to search and display reliably.
Monetisation must not gate discovery. If only paying businesses appear, the directory is incomplete and consumers lose trust in it. Paid tiers have to enhance visibility rather than control existence.
Two products, one platform. A directory and a digital publication have almost nothing in common technically, but they had to share users, navigation, administration and a single mobile application.
Listing ownership is a trust boundary. If listings can be claimed, then who gets to claim them is the most security-sensitive question in the product.
Our Approach
Design for pre-population from the start. We made the unclaimed listing a first-class concept rather than a workaround. A listing exists as a record in its own right, with or without an owner, and carries an explicit unclaimed state. The directory can therefore be populated ahead of demand and become useful to consumers immediately, with business owners taking ownership afterwards through a dedicated claim flow.
Give consumers a non-directory reason to open the app. Editorial content and issue-based digital editions were built into the same product, so the platform has recurring content value between the occasional moments when someone actually needs to find a business.
Model listing data properly, and iterate when the model is wrong. Opening hours went through successive representations before settling on a structured JSON format capable of expressing real-world schedules. Changing a data representation in a live product is unglamorous work that most teams avoid — and avoiding it is how directories end up with unsearchable, unreliable listing data.
Make subscription tiers data, not code. Plans and their feature details are stored as records, so what a tier includes can be changed by the operator without a development cycle — which matters, because directory pricing and packaging get revised frequently in the first years.
Cache what is read constantly and changes rarely. Categories, plans and content pages are read on almost every request and change occasionally, so model-level caching was applied to keep those reads off the database.
Build the mobile app modularly. The native client was structured with a clear separation between an application core — configuration, base classes, utilities, localisation, logging, deep link handling — and self-contained feature modules, so the app remains maintainable as features accumulate.
Support sharing and deep linking. A dedicated URL handling module means a listing or article shared externally opens in the right place in the app, which is essential for a product whose growth depends on content being passed around.
The Solution
Rich business listings. Each listing carries the business name, contact details, website, full address with geographic coordinates, category, profile and banner imagery, a photo gallery, descriptive text, structured opening hours and social media links — enough for a consumer to decide whether to visit without leaving the app.
Claimable listings. Listings can exist before their owners do. A business owner claims their listing through a dedicated flow and thereafter controls its content, which removes the registration barrier that would otherwise block directory growth.
Hierarchical categorisation. A two-level category structure with descriptive content per category supports both browsing and discovery, giving consumers a navigable path into the directory rather than only a search box.
Location-based discovery. Coordinates on each listing power map display and proximity-based browsing, so the directory answers the question consumers actually have — what is near me.
Reviews and ratings. Consumers rate and review businesses, adding the social proof that makes a directory credible and giving business owners a reason to maintain their presence.
Subscription listing tiers. Plans with monthly and annual pricing and per-plan feature detail determine listing prominence and capability, with an upgrade path and payment capture in the mobile app. Discovery is never gated — paid tiers enhance rather than enable.
Promotional mechanics. Listings can offer coupon codes and accept quote requests, giving businesses a measurable reason to maintain and pay for their presence.
Digital editions. Issue-based digital publications are delivered in the app, giving consumers a recurring content reason to return that is independent of whether they currently need a business.
Editorial blog. Categorised articles with an in-app reader, supporting community content and search discoverability.
Support centre. Structured question-and-answer content, reducing support load from a user base spanning consumers and business owners with very different questions.
Administrative platform. Full management of listings, categories, plans, editorial content, digital editions, support material, CMS pages and users, with server-side data grids for working at directory scale.
Key Features
Claimable unclaimed listings Listings exist independently of their owners and carry an explicit unclaimed state, so the directory can be populated ahead of demand and businesses can take ownership later through a dedicated claim flow.
Structured opening hours Opening hours stored in a structured format capable of expressing real-world schedules — variable days, multiple periods and exceptions — rather than as free text that cannot be searched or reliably displayed.
Two-level category hierarchy Parent and child categories with descriptive content, supporting browsing, discovery and category-level content.
Location-based discovery with mapping Geographic coordinates on every listing driving map display and proximity browsing.
Reviews and ratings Consumer ratings and written reviews providing the social proof that makes a directory trustworthy.
Data-driven subscription tiers Plans and their features stored as records with monthly and annual pricing, so packaging can change without a release, with an in-app upgrade and payment path.
Coupons and quote requests Promotional mechanics attached to listings, giving businesses measurable return from their presence.
Issue-based digital editions Digital publication delivery inside the app, creating recurring engagement independent of directory need.
Editorial blog with categories Categorised articles with an in-app reader supporting community content and discovery.
Deep linking into listings and articles A dedicated URL handling layer so shared content opens in the right place in the app, supporting organic growth through sharing.
Technical Architecture
Mobile client. A native iOS application separated into an application core — configuration, base view controllers, utilities, localisation, logging and URL handling — and self-contained feature modules each owning its own interface, views and models. Networking, remote image loading and caching, map display, media capture with cropping and gallery browsing are handled through dedicated components.
API layer. A token-authenticated JSON API serving the mobile client, with cross-origin controls and a controller tree kept separate from administrative code.
Administrative platform. A server-rendered back office with server-side processed data grids covering listings, categories, plans, editorial content, digital editions, support material, CMS pages and users.
Application layer. Controllers partitioned by audience over shared base classes, with domain models covering businesses, categories and their hierarchy, plans and plan details, editorial content, digital editions, support content and platform settings.
Data layer. A relational database with structured storage for complex listing attributes, incremental non-destructive schema evolution, and model-level caching applied to high-read catalogue entities.
Media handling. Image upload with server-side processing, supporting profile imagery, banners and galleries per listing.
Supporting services. Mapping for location display, payment handling for subscription upgrades, and email delivery for verification and notification.
Flow: iOS app → Token-authenticated API → Controllers & domain models → Relational database (cached catalogue reads) → Image processing & storage → Map, payment and email services → Administrative back office
Technology Stack
| Category | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel |
| Database | MySQL with Doctrine DBAL |
| API authentication | Laravel Passport (OAuth2) and Sanctum |
| Query caching | Model-level caching layer |
| Administrative grids | Yajra DataTables (server-side processing) |
| Image processing | Intervention Image |
| Admin forms | Laravel Collective HTML |
| Diagnostics | Log viewer |
| Mobile platform | Native iOS (Swift), modular application architecture |
| Mobile networking | Alamofire with remote image loading and caching |
| Mapping | Google Maps |
| Media capture | Multi-select image picker with crop view controller |
| Media viewing | Photo browser with gallery support |
| Ratings | Star rating component |
| Mobile UI | Collapsible table views, rich interactive labels, progress indicators, keyboard management, custom collection layouts |
| Connectivity | Reachability handling |
| Localisation | Built-in localisation support |
| Testing | PHPUnit, Faker factories, Mockery |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| Directory cold start — no listings means no consumers, no consumers means no listings | The unclaimed listing built as a first-class concept: listings exist as records independent of owners, with an explicit unclaimed state and a dedicated claim flow, so the directory can be useful before businesses engage. |
| Business owners unwilling to complete registration before seeing value | Claiming an existing, already-populated listing replaces creating one from scratch, converting a lengthy onboarding into a verification step. |
| Consumers having no reason to open a directory between needs | Editorial content and issue-based digital editions built into the same product, creating recurring engagement independent of directory use. |
| Opening hours that free text cannot express and search cannot use | The representation was iterated deliberately — through successive schema changes in a live product — to a structured format capable of expressing variable days, multiple periods and exceptions. |
| Subscription packaging changing faster than release cycles | Plans and their feature details stored as data rather than encoded in application logic, so the operator can change what a tier includes without a deployment. |
| Catalogue data read on nearly every request | Model-level query caching applied to categories, plans and content pages — high-read, low-change entities — reducing database load on the busiest paths. |
| A native app accumulating features without becoming unmaintainable | A modular structure separating application core concerns from self-contained feature modules, each owning its own interface, views and models. |
| Shared content needing to open in the right place | A dedicated URL handling module supporting deep links into listings and articles, so content shared externally converts into app engagement. |
| Media-heavy listings uploaded from mobile devices | Client-side image selection and cropping before upload, with server-side processing and remote image caching in the app for consistent, efficient presentation. |
Security & Reliability
Authentication. Token-based OAuth2 authentication with email verification and password recovery for consumer and business accounts.
Listing ownership control. Claiming an existing listing runs through an explicit flow rather than being an automatic association, so control of a business's public presence is a deliberate, verifiable transition.
Surface separation. Consumer API endpoints and administrative functionality are held in separate controller trees, so administrative capability is not reachable from the public API.
Cross-origin controls. Explicit policy over which clients may call the API.
Non-destructive data evolution. Schema changes were applied incrementally with additive migrations, preserving existing listing and content data throughout the product's evolution.
Content moderation capability. Administrative control over listings, reviews and editorial content allows inaccurate or inappropriate material to be managed.
Operational visibility. Administrative dashboards and log inspection tooling support day-to-day operation and issue investigation.
Connectivity resilience. The mobile client detects connectivity state so behaviour on poor networks is predictable rather than silently failing.
Scalability & Performance
Cached catalogue reads. Categories, plans and content pages are cached at the model layer, keeping the most frequent reads off the database.
Server-side administrative grids. Administrative listings page, sort and filter at the database level, so the back office remains usable as the directory grows.
Paginated consumer endpoints. Listing and content endpoints return bounded result sets rather than growing with the directory.
Efficient media handling. Images are cropped and sized on the device before upload, processed server-side once, and cached on the client for repeat viewing.
Stateless API tier. Token authentication keeps application instances free of session state, supporting horizontal scaling.
Modular client architecture. Feature isolation in the mobile app means new sections can be added without increasing the cost of the existing ones.
Business Outcomes
- The directory could launch useful, because listings existed before businesses engaged rather than after.
- Business onboarding became a claim rather than a registration, converting a high-abandonment data entry task into a short verification step.
- Consumers have a reason to return between needs, through editorial content and regular digital editions.
- Listing data is structured and searchable, particularly opening hours, which most directories leave as unusable free text.
- Discovery is never gated by payment, preserving directory completeness and consumer trust while paid tiers add prominence and capability.
- Packaging can change without engineering, because plans and their features are data.
- Businesses can measure their return, through coupons and quote requests attached to their listing.
- Shared content converts to engagement, because deep links open directly to the listing or article that was shared.
- The operator runs the platform independently, with full administrative control over listings, categories, plans, content and users.
Why it worked
Directory products fail in the first six months, and they fail for a structural reason rather than a technical one: they launch empty and ask businesses to fill them. The engineering answer — making listings exist independently of owners, with claiming as a separate flow — has to be designed in at the data model level. Retrofitted later, it is a rewrite.
Our team designs for the launch condition, not just the mature one. We build the mechanics that let a two-sided product be useful before either side has arrived. We model messy real-world data properly, and we change the model when it turns out to be wrong rather than leaving unsearchable data in place for years. We make commercial packaging data rather than code, because pricing changes far more often than software gets rewritten. And we structure native applications modularly, so the tenth feature costs roughly what the third one did.
Our teams work across Laravel and modern PHP, token-secured API design, native iOS development, mapping and location data, media pipelines and subscription commerce — with the product judgement to know which of those decisions will still be constraining the business in three years.
Final Summary
A local business directory has an awkward launch condition. Consumers judge it by completeness, businesses judge it by audience, and on day one it has neither. Most directories try to sell their way out of that, recruiting businesses individually into a product that cannot yet demonstrate value — which is slow, expensive, and frequently fatal.
Our team built a platform designed around the launch condition. Listings exist as records in their own right, complete with imagery, structured opening hours, categorisation and location, whether or not their owner has ever heard of the platform. Business owners claim their listing rather than creating it, turning a high-abandonment registration into a short verification. Meanwhile, editorial content and issue-based digital editions give consumers a recurring reason to open the app that has nothing to do with whether they currently need a plumber — which is what keeps a directory installed between the occasional moments it is genuinely needed.
On top of that sits a subscription model where tiers and their features are configurable data rather than code, promotional mechanics that let businesses measure their return, reviews that build consumer trust, and a full administrative platform for running listings, content and publications. The engineering choices — structured listing data, cached catalogue reads, deep-link handling, a modular native client — are the ones that determine whether a directory is still maintainable and still fast once it holds the volume of content that finally makes it valuable.