Regift · Knowledge Article

Architecture & Engineering Overview

Regift is an AI-powered, anonymous marketplace for brand-new, unopened gifts, serving all of New South Wales, Australia. It is live on the App Store and Google Play. This article is a detailed, end-to-end tour of the product: what it does, how the system is put together, the technologies behind it, and how it's deployed to production on Microsoft Azure.

Current as of release 1.0.1 (build 51), September 2026.

Product

What Regift is

Every year, mountains of perfectly good, still-sealed gifts end up forgotten in cupboards. Regift gives them a second life. Users list an unopened gift to sell, exchange, or donate, and other people nearby can browse, make an offer, chat, and arrange a safe exchange — all without ever revealing their real identity.

Three principles shape every design decision:

Anonymous by default

Users are known only by a generated alias and a cartoon avatar. Real names and emails are never shown to other users.

Safe to transact

Optional identity verification, curated safe-meetup spots, in-app reporting/blocking, and held-in-escrow payments.

AI does the busywork

A photo becomes a drafted listing, plain-English searches find the right gifts, and NSW-wide courier delivery covers the times meeting in person isn't ideal.

How it fits together

System architecture

Regift is deliberately a single-service backend: one FastAPI application running on an Azure App Service (Linux, B1 tier), fronting a set of managed Azure services and third-party partners. Two Flutter apps (iOS and Android) and a web admin console are the clients. This keeps the system easy to reason about, cheap to run, and fast to deploy, while the heavy lifting (storage, realtime, push, AI) is offloaded to managed services.

CLIENTSiOS app (Flutter)iPhone · App StoreAndroid app (Flutter)Google PlayAdmin consoleWeb (served by API)BACKEND · Azure App Service (Linux B1)FastAPI single-service app(app.py · Uvicorn worker)• REST API + security middleware• Session & admin auth• Escrow / payout orchestration• Courier booking + tracking poll• Background daemonsAZURE SERVICESTable Storage (NoSQL)Blob Storage (images · SAS)Web PubSub (realtime chat)Notification Hub (APNs/FCM)Azure OpenAI · FoundryEXTERNAL PARTNERSStripe Connectpayments + escrowTransdirectcourier deliveryDiditidentity (KYC)Apple / Googlesign-in + pushGitHub Actions CI/CDpush to main → build → deploy
High-level system architecture — Flutter clients talk to a single FastAPI service on Azure App Service, which orchestrates Azure platform services and third-party partners.

The backend is stateless between requests — all state lives in Azure Storage — so it can restart or scale without losing data. Long-running work (escrow auto-release, courier tracking) runs as background daemon threads inside the same process.

Technology

Technology stack

Apps & frontend

LayerTechnologyRole
Mobile appsFlutter (Dart)Single cross-platform codebase for iOS & Android
Design system“Meadow” — Material 3 + custom widgetsSerif display + Figtree UI, glass cards, floating dock
RealtimeWeb PubSub client + poll fallbackLive chat message delivery
Payments UIStripe SDK (PaymentSheet)Card, Apple Pay & Google Pay checkout
Mapsflutter_map · CARTO basemaps (OpenStreetMap)Browse map & safe spots; tile URL served from backend config
Secure storagePlatform Keychain / KeystoreEncrypted session-token storage on device
Admin consoleServer-rendered HTML + vanilla JSOperations dashboard served by the API

Backend

LayerTechnologyRole
API frameworkFastAPI (Python) + Uvicorn workerREST endpoints, middleware, background tasks
AuthJWT session tokens + OIDC (Apple/Google)Passwordless sign-in, per-request identity checks
ImagesPillow + Blob SAS URLsThumbnailing, share cards, time-limited image links
Background jobsDaemon threads7-day payout auto-release, courier tracking poll
LimitsIn-process per-IP rate limits + per-caller AI quota300 API requests/min per IP; 60 AI calls/hour per caller

Microsoft Azure

LayerTechnologyRole
ComputeApp Service · Basic B1 (Linux)Hosts the FastAPI service
DatabaseTable Storage (NoSQL)Users, gifts, offers, messages, deliveries, more
Object storageBlob StorageGift & verification images, served via SAS
RealtimeWeb PubSubPushes chat messages to connected clients
PushNotification HubFan-out to APNs (iOS) and FCM (Android)
AIAzure OpenAI · Microsoft Foundry (gpt-5-mini)Listing composer, natural-language search, wishlist matching, support assistant
DeliveryGitHub Actions → App ServiceCI/CD on every push to main

External partners

LayerTechnologyRole
PaymentsStripe ConnectBuyer checkout, seller payouts, escrow-style holds
DeliveryTransdirectMulti-courier quotes, auto-booking & shipping labels
Identity (KYC)DiditOptional identity verification — result only
Sign-inApple Developer · Google CloudSign in with Apple & Google, push credentials
DistributionApp Store Connect · Google Play ConsoleReleases scripted via the App Store Connect & Android Publisher APIs

Capabilities

Feature catalogue

Discovery & browse

A pinned search bar that understands plain-English requests, quick filters (nearby, under $50, delivery, free/donations, verified), category & price filters, and a square-card grid. Cards show distance in km when location is available, plus verified and delivery badges.

Listings

Sell, exchange, or donate. Multi-photo galleries (pick several at once), condition, original price, tags, and a suburb chosen from a NSW picker — changeable after posting. The AI “write it for me” composer drafts the title, description, category, condition and a suggested price from a photo.

Offers & trading

Every purchase starts as an offer. Sellers accept or decline; accepting marks the listing pending. One live offer per gift per buyer, with clear status on the listing.

Anonymous chat

Realtime messaging with image attachments, listing context headers, and role-aware draft messages. Status pills tell the buyer where the listing stands.

Trust & safety

Optional identity verification with a visible badge, curated safe public meetup spots (police stations, parks, libraries), reporting, blocking, and a dispute workflow.

Payments & delivery

Buy with in-person handover or courier delivery. Card, Apple Pay and Google Pay checkout, funds held in escrow, and a self-ship option where the seller posts it themselves.

Wishlists & alerts

Heart listings to save them, and set keyword alerts. New listings are matched against everyone's wishlists using AI semantic matching and pushed to interested users.

Notifications & purchases

A 90-day in-app notification centre, a My Purchases screen with a delivery tracker graphic and audit history, and pending-action badges that surface what needs attention.

Impact & badges

A personal “impact” tracker of gifts rehomed, plus collectible badges (first regift, generous donor, verified, doorstep delivery, and more).

Referrals & sharing

Refer-a-friend and per-listing share links that render a rich preview card for social apps and messengers.

Persistence

Data & storage model

Regift uses Azure Table Storage, a wide-column NoSQL store, rather than a relational database. Each concern gets its own table — users, gifts, offers, messages, deliveries, reports, disputes, notifications, wishlists, saved searches, and more. Tables are created automatically on first use, so a fresh environment bootstraps itself with no migration step.

Partition and row keys are chosen so common reads are single- partition and cheap — for example, notifications are partitioned by user with an inverted-timestamp row key so the newest appear first. Images live in Blob Storage and are served through short-lived signed (SAS) URLs rather than being made public.

Why NoSQL here

The access patterns are key-based and denormalised (fetch a user's listings, a gift's offers, a conversation's messages). Table Storage is inexpensive, auto-scaling, and needs no schema management.

Anonymity in the data

Real identity fields are stored but never exposed on public endpoints. Clients see only the alias, avatar, rating, and verification status.

Trust

Identity, anonymity & security

Sign-in is passwordless: Sign in with Apple and Google sign-in only. Provider identity tokens are validated on the server, and a signed session token is issued for subsequent requests. Session tokens are stored in the device's hardware-backed Keychain / Keystore, not in plain storage.

A security middleware runs ahead of every API request: it authenticates the caller and enforces that a signed-in user can only act on their own resources. Sensitive operations verify resource ownership (only a seller edits or deletes their listing; only a conversation participant reads its messages). Public endpoints are limited to anonymous browsing data and never leak personal contact details.

Optional KYC (Didit)

Users can verify they're a real person through Didit. Regift only ever receives the yes/no result — identity documents never touch our servers — and displays a verified badge without revealing who the person is.

Defence in depth

Server-side output escaping in the admin console, sanitised database queries, credentialed-CORS disabled, redacted logs, and secrets held only in environment configuration — never in source.

Fail closed, limit abuse

Apple and Google token audience and issuer checks refuse sign-in when misconfigured rather than letting it through. Per-IP rate limits read the client from the right-most forwarded hop, AI calls have a per-caller hourly quota, and listings, chat and comments pass a rule-based moderation filter.

Quiet production logs

Logging defaults to INFO with the Azure SDK pinned to warnings, and each request is logged as one line with its path only — query strings carry addresses and search terms, so they stay out.

Money

Payments & escrow

Payments run on Stripe Connect. Sellers complete a one-time payout onboarding (their bank details go directly to Stripe, never to Regift). When a buyer pays, the charge lands in the Regift platform account — this is the escrow hold. The seller's share is only transferred to them once the exchange completes.

Offerbuyer requestsAcceptedlisting pendingPaidheld on platformDeliveredcourier / handoverConfirmedbuyer receivesReleasedseller paidseller acceptsbuyer paysshipNo confirmation in 7 days → auto-release sweep pays the seller · Pre-release admin refund fully reverses the charge
Escrow lifecycle — the buyer's card is charged to the Regift platform account (money held), and the seller is only paid out when the buyer confirms receipt, or automatically after 7 days.

Release happens when the buyer taps “I received it”, or automatically after a 7-day safety window if they never do. Before release, a full refund is always possible; after release it's handled manually. Checkout supports card, Apple Pay, and Google Pay, and item prices and postage are always taken from the server-side listing — never trusted from the client.

Stripe runs in live mode. The checkout response names the publishable key of the account that created the PaymentIntent, and the app builds its payment sheet with that key, so a key rotation needs no app release. Connect account IDs are mode-scoped: a stored account that no longer resolves under the current key is detected and cleared, so the seller is asked to onboard again instead of a buyer paying for a transfer that could never land. At start-up the server flags secret and publishable keys that belong to different modes.

Logistics

Courier delivery

For exchanges that shouldn't happen in person, Regift integrates Transdirect, a multi-courier aggregator. When a seller submits their pickup address, the backend requests quotes across couriers, auto-books the cheapest option, and stores the pickup window and estimated delivery date. The seller prints the generated shipping label and leaves the box out; the buyer sees live status and an ETA.

BuyerSellerRegift APITransdirectbuy with delivery (offer)accept offerpay (card / wallet)hold funds (escrow)submit pickup addressquote courierscheapest quote + labelconfirm bookingprint label · box readyETA + trackingconfirm receivedpayout released
Delivery sequence — the buyer pays, the backend auto-books the cheapest Transdirect courier, and both sides are kept informed through to confirmed receipt.

Coverage spans all of New South Wales, validated by postcode on both the listing and the drop-off address rather than by distance from Sydney. A configurable cost guard holds a booking for manual review if the courier quote would exceed the postage the buyer paid by more than 10%, and a background poller advances delivery status from the courier's tracking feed. A free self-ship mode lets sellers post items themselves at no cost to the buyer.

Transdirect runs in live mode, booking and confirming the cheapest real courier. A demo mode books Transdirect's test courier instead; the two are switched by a single setting, which the admin console reports back as the running server sees it.

Intelligence

AI features

AI is how Regift takes the effort out of a marketplace: the slow parts — writing a listing, finding the right gift, answering “how does this work?” — are done by models running on Azure OpenAI (gpt-5-mini, deployed through Microsoft Foundry). Four features ship in the apps today:

“Write it for me” listing composer

From a single gift photo, a vision-capable model drafts the title, description, category and subcategory, condition, and a suggested price. The form fills in with a staggered reveal, and the seller edits anything before posting.

Natural-language search

Two stages. A query like “a gift for my 6-year-old” is interpreted into keywords and categories that widen the app's own filter, so toys appear without the word “toy”. Smart search then has the model pick matching items from a compact catalogue of up to 120 recent live listings. Both results are cached.

Semantic wishlist alerts

Each new listing is checked against users' saved alert keywords by meaning, not spelling — “lego” matches a Duplo set, “something for a gamer” matches a headset — asynchronously, with a push alert on a match and plain keyword matching as the fallback.

Boxy, the support assistant

In-app help runs on a Foundry prompt agent whose live definition is fetched and executed through the Responses API, grounded in a shared Regift knowledge base. Conversations chain across turns, answers needing a person trigger an email escalation to the team, and Azure OpenAI directly is the fallback if Foundry is unavailable.

Guardrails keep it predictable and affordable: every model-backed call counts against a per-caller quota of 60 per hour, and over the limit a feature degrades gracefully (search falls back to local filtering) rather than failing. The support assistant refuses off-topic and prompt-extraction attempts with a canned reply, and App Review's demo listings are kept out of the search catalogue.

Engagement

Realtime & notifications

Chat is delivered in realtime through Azure Web PubSub, with a polling fallback so messages still arrive if the socket drops. Every notable event — new message, offer update, delivery status change, wishlist match — is delivered two ways: a push notification and a persistent entry in the in-app notification centre (retained ~90 days), so users who declined push permission still miss nothing.

Push fan-out uses Azure Notification Hub, which routes to APNs for iOS and Firebase Cloud Messaging for Android from a single backend call. Device registrations are stored per platform so a user's iPhone and Android tablet can both receive alerts. Tapping a notification deep-links to the exact conversation, offer, purchase, or listing it refers to. Deleting an account removes its device registrations on both platforms, and orphaned registrations are pruned so device counts don't drift.

Operations

Admin console

A dedicated, authenticated web console — served by the same API — gives operators everything they need to run the marketplace: a deliveries queue (with one-click courier info and status controls), a disputes workflow with permanent history, moderation tools (verify/block users, mark listings inactive with a reason, resolve reports), a funds held / released indicator on every paid order, a waitlist for out-of-area demand, and feature toggles. It also reports whether Stripe and Transdirect are in live or test mode as the running server sees them, and includes scoped tools that remove App Review demo data (with a dry run first) or a single account.

Production

Infrastructure & deployment

Regift runs entirely on a single Microsoft Azure subscription. The production environment was stood up as follows:

  1. Create the Azure account and a Resource Group to hold everything.
  2. Provision an App Service on the Basic B1 (Linux) plan to host the API.
  3. Add a Storage Account (Table + Blob), Web PubSub, and a Notification Hub.
  4. Create an Azure OpenAI resource and deploy the gpt-5-mini model via Microsoft Foundry.
  5. Configure all secrets and connection strings as environment variables in the Web App settings.
  6. Wire GitHub Actions to the Web App from both sides so every push to main builds and deploys automatically.
  7. Set the Web App startup command: uvicorn.workers.UvicornWorker --timeout 120 app:app.
  8. NoSQL tables auto-create on first use — no manual schema setup.
  9. Populate the Notification Hub with APNs and FCM credentials: the Apple .p8 key (header/footer stripped, pasted as the token) and the Firebase service credentials.
1git push → main2GitHub Actions build3Deploy to App Service (B1)4Uvicorn worker starts app5Read env vars / secrets6Tables auto-create on demand7Live · health check 200
Deployment pipeline — a push to main triggers GitHub Actions, which builds and ships the FastAPI service to Azure App Service; NoSQL tables self-create on first use.

External integrations are provisioned alongside: Apple Developer (certificates, identifiers & keys) and App Store Connect for iOS; Firebase, Google Cloud and Google Play Console for Android; Didit for KYC; Stripe Connect for payments; and Transdirect for delivery. Each is wired in through environment configuration, so the same codebase runs in test or live mode by changing settings alone.

Shipping

Releases & App Review

Both stores are released by script rather than by hand. iOS builds are uploaded to App Store Connect, and the version's metadata, review notes, build selection and submission go through the App Store Connect API. Android bundles, their R8 mapping file, the store listing text and release notes are committed in a single Android Publisher API edit that is discarded if any step fails, so a half-applied release never reaches the store.

In 1.0.1 (build 51)

“Swap” is renamed “Exchange” everywhere users read it (the stored value is unchanged, so earlier builds keep working); several photos can be picked at once; a listing's suburb can be changed after posting, with the server enforcing a NSW postcode; and returning users keep the name they were given instead of being asked again.

One switch for App Review

A single setting, REVIEWER_LOGIN_BUILD, shows the reviewer sign-in only on the build under review, opens the demo login, and restores the demo data if a reviewer deletes the account. Demo listings are visible only to the review accounts — the browse cache is keyed by audience so they never leak — and the switch is cleared once the build is approved.

Configuration, not code

Live or test payments, live or demo courier booking, the map tile provider and key, the reviewer build and log verbosity are all environment settings, so most operational changes need neither a deploy nor an app release.

One QR code, both stores

Printed material points to vexbit.au/regift, which sends iPhones and iPads to the App Store and Android phones to Google Play, and shows both buttons anywhere else.

About this article

Regift is built and operated by Vexbit, a Sydney-based AI product studio. For product help, see the Support page; for data handling, see our Privacy Policy.