Delivered remotely for a business based in Vienna, Austria. Names withheld by agreement.
Project Overview
Industry: Fashion resale and social commerce — peer-to-peer trading of pre-owned clothing, footwear and accessories.
Type of solution: A consumer-to-consumer marketplace platform: a versioned REST API serving mobile applications, a web administrative back office, and a separate real-time messaging service, with card payments, order management and a social discovery layer.
Business context: Resale is a social activity before it is a commercial one. People browse, follow sellers whose taste they like, save things, ask questions, and negotiate — and only then buy. General classifieds platforms treat each listing as an isolated advert, and social platforms have no commerce underneath them. Neither structures the thing that actually matters in fashion: what size is it, what brand is it, and does it fit me. The platform was built to hold both halves at once — a social discovery experience with a properly structured catalogue and real payments behind it.
General users: Registered users, who are buyers and sellers simultaneously on the same account; unauthenticated visitors, who can browse a deliberately limited part of the catalogue before signing up; and platform administrators managing the taxonomy, moderation, curation, orders and refunds.
General purpose: To make second-hand fashion findable, negotiable and buyable in one place — giving sellers a storefront and an audience, giving buyers structured search and a reason to keep browsing, and putting the transaction on the platform rather than in a private message.
The Business Challenge
Every user is both sides of the market. In resale there is no seller tier to sign up for — the same person lists a jacket in the morning and buys a pair of boots in the afternoon. Roles cannot be assigned to accounts; they have to be resolved per listing, per conversation, per notification.
Fashion sizing is not one taxonomy. Footwear and apparel use different scales. Footwear scales differ between men's and women's. Sellers also think in general sizes. Getting this wrong means a buyer filters for their size and sees items that do not fit them — which is the fastest way to lose a resale user permanently.
Brands and colours are open-ended. No fixed list survives contact with real sellers, who will list brands nobody anticipated. But leaving brand as free text destroys filtering. The platform needed to accept anything a seller types while still producing a usable, curated reference vocabulary.
Haggling is part of the product. Resale prices are negotiated, and the negotiation happens in conversation. Pushing users into a separate formal offer screen breaks the flow; leaving it as unstructured chat means the agreed price never makes it into checkout reliably.
Buyers arrive without search intent. People browse resale the way they browse a market stall. A search box alone produces an empty, discouraging experience. Discovery had to be assembled from behavioural signals and from editorial merchandising.
Trust has to be manufactured. Two strangers are transacting on a used item. Sellers need reputation they can accumulate, buyers need recourse, and the platform needs the ability to intervene when something is wrong.
Money has to move safely, through more than one route. Card payments, saved payment methods, per-shop checkout, stock that must not oversell, shipping addresses that must not silently change after an order, and refunds — all of it needed to work through established payment infrastructure rather than being improvised.
Conversation has to feel instant. Negotiation over a used item is a live exchange. Delivery had to be immediate rather than polled, without asking the application tier to hold long-lived connections.
Our Approach
Model the buyer/seller duality on a single identity. Rather than splitting accounts into roles, one account owns a storefront and also buys, with the platform resolving which side the user is on from the listing in question. Every feed, conversation thread and notification is written against that resolution.
Build the size taxonomy the domain actually requires. Categories carry a footwear flag that determines which size scale applies, with separate gendered footwear scales, an apparel scale and a general scale, resolved per listing at read time. It is more machinery than a single size column, and it is the difference between a filter that works and one users stop trusting.
Let the vocabulary grow from sellers, then curate it. Brands and colours entered by a seller are created as reference records on the spot, so listing never stalls on a missing option — and administrators curate, merge and block from the back office afterwards. Frictionless listing at the front, controlled vocabulary at the back.
Put the offer inside the conversation. Offers are carried as structured data on a chat message, so negotiation happens where it naturally happens. Counter-offers edit that structure, and accepting an offer carries the agreed price directly into the cart — the buyer never re-enters the number, and the conversation itself records how the price was reached.
Assemble discovery from weak signals and editorial judgement. The personalised feed is built from what a user has liked, viewed recently and started conversations about, combined with items the team has hand-picked, alongside a separately curated browse surface toggled per listing from the back office. Merchandising by people, supported by behaviour — not a black-box recommender.
Make the transaction real. Two established payment gateways, gateway-side customer records, saved payment methods, per-shop checkout with stock checked and decremented inside a transaction that rolls back if any line is short, and shipping addresses copied onto the order at purchase time so later profile edits cannot rewrite delivery history.
Give resale its own lifecycle feature. Sellers can relist an item as a fresh listing carrying its images and attributes forward — and everyone who liked the original is notified. Dormant interest becomes a second chance to sell.
Split real-time delivery out. Messaging is delivered by a dedicated service holding the socket connections and coordinating over a shared cache layer, so the API tier stays stateless and request-shaped while chat stays instant.
Open the catalogue before signup. A defined subset of browse endpoints serves unauthenticated clients, because in a marketplace the catalogue is the marketing.
The Solution
Personal storefronts. Every user gets a shop with its own imagery, description, categories, shipping terms and social handles — the unit that followers, reviews and reputation attach to.
Structured fashion catalogue. Categories and subcategories, product types and item types, genders, apparel and footwear size scales, brands, colours and free-text hashtags — the foundation every filter, feed and search runs on.
Listing creation with media handling. Multi-image upload with server-side resizing, thumbnails generated at upload time and both variants written to cloud object storage, alongside price, currency, quantity, shipping charge, size, brand, colour and description.
Faceted browse and search. Filtering by brand, category, product type, size and price range; keyword search scoped across users, shops, listings, brands and colours; and autocomplete suggestions while typing.
Personalised feed and curated browse. A "for you" surface assembled from likes, recently-viewed items, active conversations and editorial picks, plus a separately curated browse surface administrators control per listing.
Social layer. Follow shops, see followers and following, like listings, comment with threaded replies, and review shops.
Buyer–seller messaging. Per-listing conversation threads with attachments, unread counts and immediate delivery through a dedicated real-time service.
In-conversation offers. Offers and counter-offers exchanged as structured messages, with acceptance carrying the agreed price into the cart.
Relist and re-notify. Sellers relist an item as a new listing carrying images and attributes forward, with everyone who liked the original notified.
Cart, checkout and orders. Cart grouped by shop, stock validated and decremented transactionally, orders with a snapshotted delivery address, transaction records against the payment gateway, order history and refund requests.
Payments. Card processing through two established gateways, with gateway-side customer records and saved payment methods for repeat purchase.
Notifications. Push delivery to registered devices for offers, messages, sales and relists, with in-app notification history and a per-user opt-out respected before dispatch.
Reporting and moderation. Buyers and browsers report listings; administrators work a report queue and can block users, shops and reference data.
Administrative back office. Full taxonomy management, user and shop administration, listing curation, order and refund handling, the report queue, search analytics views and CMS page editing.
Key Features
Personal storefronts on a single account Every user sells and buys from one identity, with a shop that accumulates followers, reviews and a browsable inventory.
Fashion-accurate size taxonomy Separate apparel, general and gendered footwear scales, resolved per listing according to the category, so size filtering returns items that actually fit.
Seller-driven vocabulary with administrative curation Brands and colours are created on demand from seller input and curated from the back office, keeping listing frictionless without abandoning structured filtering.
Offers and counter-offers inside the conversation Negotiation is carried as structured data on chat messages, with acceptance flowing the agreed price directly into checkout.
Relist with interest notification Relisting carries images and attributes into a fresh listing and notifies every user who liked the original — turning saved interest into a second sale opportunity.
Behaviour-driven feed with editorial curation A personalised surface built from likes, recent views and active conversations, combined with hand-picked items and an administrator-controlled browse surface.
Per-shop checkout with transactional stock control Carts spanning multiple sellers check out per shop, with availability validated and decremented inside a transaction that rolls back cleanly if any line cannot be fulfilled.
Dual payment gateway integration Two established card gateways integrated behind one order and transaction model, with gateway-side customer records and saved payment methods.
Dedicated real-time messaging service Socket connections and message fan-out handled by a separate service coordinating over a shared cache layer, keeping the API tier stateless.
Moderation and administrative control Listing reports feeding an admin queue, with blocking available across users, shops and every level of the reference taxonomy.
Technical Architecture
API layer. A versioned REST API with controllers partitioned by audience — consumer API, administrative and authentication trees over a shared base controller — with a central response-constant definition standardising status codes and messages across every endpoint. Authentication is bearer-token based, with a defined subset of catalogue endpoints served to unauthenticated clients for pre-signup browsing. The specification is annotated inline on the controllers themselves and generated from the codebase.
Administrative back office. A server-rendered web application on a separate authentication guard with its own middleware and account model, covering taxonomy, users, shops, listings, curation, orders, refunds, reports, search analytics and content.
Real-time layer. A dedicated Node.js service holding socket connections, registering sockets against user records, publishing and subscribing over the shared cache layer, and handling delivery and read acknowledgement — deployed and scaled independently of the API tier.
Data layer. A relational database covering identity, shops, the fashion taxonomy, listings and media, the social graph, conversations and messages, offers, carts, orders, delivery addresses, transactions, notifications and moderation records.
Media pipeline. Images are received by the API, resized server-side into a thumbnail variant, and written with the original to cloud object storage, with listings referencing both.
Notification layer. Push dispatch to registered device tokens for offers, messages, sales and relists, with in-app notification records persisted alongside and user preferences checked before delivery.
Payments layer. Two gateway SDKs behind one order/transaction model, with gateway customer identifiers cached on the user record and payment methods stored gateway-side for repeat purchase.
Delivery pipeline. Release-based deployment driven from continuous integration — build, deploy, migrate, cache clear, dependency install and process restart as discrete automated steps.
Flow: Mobile clients → Token-authenticated REST API → Relational database → Cloud object storage for media → Payment gateways for checkout → Push service for notifications → Dedicated real-time service over shared cache for messaging
Technology Stack
| Category | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel |
| Database | MySQL with Doctrine DBAL |
| API authentication | OAuth2 bearer tokens (Laravel Passport) |
| API documentation | OpenAPI/Swagger generated from in-code annotations |
| Real-time messaging | Dedicated Node.js service on Socket.IO |
| Cache, queue and pub/sub | Redis |
| Background processing | Laravel queues and jobs |
| Media storage | Cloud object storage (AWS S3) via Flysystem |
| Image processing | Intervention Image for server-side resizing and thumbnails |
| Payments | Stripe and Braintree SDKs |
| Push notifications | Firebase Cloud Messaging |
| Transactional email | Framework mailer with Blade email templates |
| Admin front end | Blade templates, Laravel Mix/webpack, Sass, jQuery |
| Cross-origin and rate control | CORS middleware, request throttling, trusted proxy handling |
| Operational tooling | In-app log viewer |
| Testing and standards | PHPUnit, automated code-style configuration |
| Deployment | Capistrano release-based deployment driven from CI |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| One account acting as both buyer and seller across every feature | Roles resolved per listing and per conversation rather than assigned to accounts, with feeds, threads, offers and notifications all written against that resolution so a single identity works cleanly on both sides of a transaction. |
| Fashion sizing spanning apparel, general and gendered footwear scales | A category-level footwear flag determines which scale applies, with separate size tables per scale resolved at read time on every listing — more machinery than a single size field, and the difference between a size filter users trust and one they abandon. |
| Brand and colour vocabulary that no fixed list can anticipate | Reference records created on demand from seller input so listing never stalls, with administrative curation and blocking from the back office afterwards — open at the point of entry, controlled at the point of search. |
| Price negotiation that belongs in conversation, not in a separate workflow | Offers carried as structured payloads on chat messages, with counter-offers editing that structure and acceptance flowing the agreed price directly into the cart, so the negotiation stays natural and the outcome is still machine-readable. |
| Buyers who browse rather than search | A personalised surface assembled from likes, recently-viewed items and active conversations, combined with editorially hand-picked listings and an administrator-controlled browse surface — behavioural signals supported by human merchandising. |
| Carts spanning multiple independent sellers | Checkout scoped per shop, with stock validated and decremented inside a database transaction that rolls back the entire purchase if any line cannot be fulfilled, preventing oversell across concurrent buyers. |
| Two payment gateways with different tokenisation and customer models | Both integrated behind a single order and transaction schema, with gateway customer identifiers cached on the user record and payment methods held gateway-side, so checkout logic and order history stay uniform regardless of route. |
| Shipping history that must not change retrospectively | The delivery address is copied onto the order at purchase time rather than referenced, so later edits to a saved address cannot rewrite where a past order was sent. |
| Instant messaging from a request-shaped application tier | Socket connections and fan-out delegated to a dedicated service coordinating with the API over a shared cache layer, keeping the application tier stateless and independently scalable. |
Security & Reliability
Token-based authentication. OAuth2 bearer tokens issued on verified login, with the consumer API behind an authenticated guard and a deliberately defined subset of catalogue endpoints exposed to guests.
Verified account activation. Registration requires a verification step before the account becomes active, with hashed credentials and an email-based password recovery flow.
Separate administrative authentication. The back office runs on its own guard, its own account model and dedicated middleware, isolated from consumer authentication.
Payments through established gateways. Card processing is executed by two mainstream payment providers through their official SDKs, with customer records and payment methods held gateway-side and gateway transaction identifiers and statuses recorded against every order.
Transactional integrity at checkout. Stock validation, decrement, order creation and payment are wrapped in database transactions that roll back completely if any step fails, so a failed payment cannot leave decremented stock or an orphaned order.
Immutable order history. Delivery addresses are snapshotted onto orders and gateway transaction records are retained, so what was ordered, paid and shipped can be reconstructed after the fact.
Moderation and administrative control. Users can report listings into an administrative queue, and administrators can block users, shops and reference data, remove listings and manage refunds.
Notification consent. Per-user notification preferences are checked before any push dispatch.
Cross-origin and rate controls. Explicit policy over which clients may call the API, request throttling on the API surface, and trusted proxy handling for correct client attribution behind load balancers.
Operational visibility. Application logging with in-app inspection tooling, and release-based deployment with discrete, repeatable steps and the ability to roll back to a previous release.
Scalability & Performance
Pagination throughout. Every list endpoint — catalogue, feed, search, conversations, comments, notifications, orders — is paginated with a configurable page size, so no response grows with the size of the platform.
Eager-loaded listing reads. Listings are retrieved with their images, colours, shop and category relations loaded together, keeping the dominant read path in the product bounded.
Thumbnails generated once. Image variants are produced at upload time rather than on request and served from cloud object storage, so browsing a feed of dozens of listings never touches the application tier for imagery.
Stateless application tier. Bearer-token authentication and externalised media storage keep application instances free of local state, so the API tier scales horizontally behind a load balancer.
Real-time isolated from the API. Socket connections live in a separate service that scales on message volume independently of request volume, coordinating over a shared cache layer.
Cache and queue infrastructure in place. A shared cache layer backs pub/sub between services and is available for queue-backed background work, including notification dispatch.
Push rather than polling. Time-sensitive events — offers, messages, sales, relists — reach users by push notification and socket delivery rather than by clients polling the API.
Repeatable, low-risk releases. Deployment runs as a scripted sequence from continuous integration, keeping releases consistent and reversible as the platform changes.
Business Outcomes
- Anyone can become a seller in minutes, with a storefront that accumulates followers, reviews and inventory rather than a series of disconnected adverts.
- Second-hand fashion became genuinely searchable, with brand, size, colour, category and price filtering built on a taxonomy that reflects how clothing and footwear are actually sized.
- Listing stays frictionless without sacrificing structure, because the reference vocabulary grows from what sellers type and is curated afterwards rather than blocking them up front.
- Negotiation happens naturally and still ends in a clean transaction, with offers exchanged in conversation and the agreed price carried into checkout automatically.
- Browsing has somewhere to go, through a personalised surface built from user behaviour alongside merchandising the team controls directly.
- Unsold stock gets a second life, because relisting carries an item forward and puts it back in front of everyone who previously showed interest.
- The transaction stays on the platform, with card payment through established gateways, per-shop checkout, transactional stock control, order history and refund handling.
- The team can run the marketplace, with taxonomy management, curation, moderation, order and refund administration and search analytics in one back office.
Why it worked
Marketplaces look like CRUD until you build one. The difficulty is never the listing form — it is the hundred places where the domain refuses to be tidy. Clothing sizes do not fit one table. Brand lists are never complete. Buyers do not search, they browse. Prices are negotiated in conversation rather than entered in a field. And the same person is a customer and a supplier in the same session, sometimes on the same screen.
Our team builds for those specifics. We modelled the size taxonomy the way fashion actually works rather than the way it would be convenient to store, because a filter that returns the wrong sizes is worse than no filter. We let sellers create their own brand and colour vocabulary and gave the client the tools to curate it, because friction at the point of listing is what kills supply on a resale platform. We put negotiation inside the conversation and made its outcome flow into checkout, because that is where haggling happens and anywhere else it would be ignored. And we split real-time messaging into its own service so the application tier stayed simple and the chat stayed instant.
Our teams work across Laravel and modern PHP, REST API design for mobile clients, payment gateway integration, real-time messaging architecture, cloud media pipelines, and the administrative tooling that lets a business actually operate a two-sided marketplace once it is live — with the domain judgement to tell the parts that must be modelled faithfully from the parts that can be simplified.
Final Summary
Resale is one of the oldest forms of commerce and one of the least well served by software. The habit is social — people follow sellers, browse without a query, ask questions and negotiate — but the transaction needs structure: real sizes, real brands, real payment, real orders. Most platforms deliver one half and improvise the other.
Our team built a platform that holds both. Every user gets a storefront and a following, and lists items against a taxonomy built for the way clothing and footwear are genuinely sized, with brand and colour vocabulary that grows from sellers and is curated by administrators. Discovery is assembled from what people like, view and talk about, alongside a browse surface the business merchandises directly. Buyers and sellers negotiate through offers carried inside their conversation, and an accepted offer becomes a cart line at the agreed price without anyone retyping a number.
Behind that sits the machinery a real marketplace needs: per-shop checkout with stock validated and decremented transactionally, two established payment gateways behind one order model, delivery addresses snapshotted so shipping history cannot be rewritten, refunds and reporting, push notifications on every time-sensitive event, and a dedicated real-time service keeping conversation instant while the API tier stays stateless. Plus a back office that lets the business run the taxonomy, the curation, the moderation and the orders without a developer. Delivered as a REST API for mobile clients over a Laravel platform — social on the surface, and a properly structured commerce system underneath.