Skip to content
Softworks
Softworks
hi@softworks.studio
Instagram LinkedIn
SalonyA product wholly owned by Softworks

The whole visit.
Working as one.

From the look a customer saves to the people, schedules and decisions behind the reception desk. We designed and built Salony to keep the whole visit connected.

Inside the story20 min read
Salony / The reception deskA Softworks product
Actual Salony staff calendar with demonstration data
Actual Salony operations overview with demonstration data
Real screens · Concept reception hardware
Demo screens · Reception hardware is a future concept
Relationship
Softworks-owned product
For
Customers & salon teams
Surfaces
Mobile, web & operations
Context
Egypt · Arabic & English
01 / The shared visit

A good visit starts before the chair.

The customer imagines a look. The salon manages a day. One visit brings both together.

Original concept illustration connecting a salon chair, appointment tiles and a reference look

An engineering case study by the Softworks team

Salony brings salon discovery, style inspiration, appointment booking and daily salon operations into one product. Our team at Softworks built the customer experience around the decisions people make before a visit, then connected those decisions to the schedules, staff, services and resources a salon actually manages.

The resulting platform spans a React Native customer app, a bilingual Next.js website and operational dashboards. Its complexity sits between those surfaces: the same appointment must make sense to a customer choosing a time, a receptionist managing the day and a professional preparing for a particular look.

Salony website hero in English and dark mode

Existing website capture, 17 October 2026. The embedded app preview uses demonstration records. Screenshot details.

ProjectSalony
Product teamSoftworks
Market and contextEgypt; Arabic and English; Egyptian-pound presentation; Cairo business time
Product modelCustomer marketplace connected to salon operations
SurfacesPublic website, customer mobile app, salon dashboard, platform administration
Engineering scopeProduct architecture, interaction design, application development, integrations and verification
Case-study basisCurrent source, reachable commit history and dated delivery evidence, reviewed 18 October 2026

Reading guide. The example customer situations below are illustrative scenarios based on implemented behavior. Documented defects are identified separately. Product screenshots contain demo or provider content; figures in them are not adoption, revenue or performance results. Internal security and operational access details are outside this public case study.

The product brief

A salon visit begins well before someone sits in a chair. A customer may have a reference photo, an occasion, a preferred professional, a limited budget and a small window in the day. A salon has a different view of the same visit: service duration, staff availability, suitable equipment, queue pressure and preparation requirements.

We designed Salony around this shared visit. Discovery helps a person decide where to go. Booking turns that preference into an explicit request. The operational workspace gives the salon enough context to respond and prepare. The product needs continuity across all three stages.

That continuity influenced our scope. Public pages explain the product and help people discover salons or inspiration. The customer app carries the booking and payment journey. Salon teams manage their working data through the web dashboard. Each surface has a clear job, while the underlying business concepts stay consistent.

This is a B2B2C product with substantial operational software behind the customer experience. We treated the salon's calendar, service catalogue and portfolio as part of the marketplace experience, because those records determine what the customer can reasonably expect.

One visit, several perspectives

Consider a customer preparing for an event. They browse hairstyle references, compare nearby salons, inspect services and select a professional. They attach a reference and a note about the desired length. The salon then needs the time, service, professional and preparation context together.

The customer should not have to reconstruct that conversation through disconnected messages. The receptionist should not have to interpret an inspiration image as a booked treatment. The professional should understand that the picture expresses a preference, with the final result agreed during consultation.

We built a sequence that preserves these distinctions:

  1. Explore: browse salons, services and attributed inspiration.
  2. Choose: identify a branch, service combination and professional.
  3. Check: present the relevant availability and booking policy.
  4. Prepare: attach optional reference looks and visit notes.
  5. Submit: create the booking request and follow the relevant payment path.
  6. Follow: display the actual appointment and payment states.
  7. Operate: give the salon a working view of the visit and its next action.

Current customer Home in dark mode

React Native screen rendered through the existing web export, with fictional salons. This capture is not a physical-device certification.

02 / The architecture

One product. Several points of view.

Different surfaces. Shared rules.Select a layer to inspect its responsibility
01 Three surfaces, one visit
Shared product rules
Records, media and events
02 Retained context, explicit responsibilities

Shared product API & domain services

Scheduling and appointment lifecycle, reference snapshots, portfolio publishing, payment and communication workflows.

Cloudflare Workers + OpenNext host the current application; MongoDB remains the database.

The tools behind the experienceSOFTWORKS / SALONY
01

The interfaces

Native booking. Web operations.

React NativeExpoNext.jsTailwind CSS
02

The shared rules

Typed contracts. Validated input.

TypeScriptZod
03

The retained context

Visit records. Image processing.

MongoDBMongooseSharp
04

The delivery layer

Cloudflare Workers + OpenNext. Vitest + Playwright.

CloudflareVitest

Media & inspirationAWS S3 PexelsOwned media and attributed imagery, with distinct responsibilities.

Architecture shaped around the product

We use an npm-workspaces monorepo for the mobile and web applications. The customer app uses React Native and Expo with React Navigation. The web application uses Next.js for public pages, dashboards and the server-facing API layer. MongoDB and Mongoose hold the operational records, with AWS S3 supporting media storage.

Domain services sit between interface actions and persisted records. Scheduling, booking policy, portfolio publishing, style discovery and payment status each have dedicated responsibilities. This lets a screen ask a product-level question without reproducing its rules independently.

Diagram source and relationships
salony-architecture.mmd
flowchart TB
  A[Customer mobile app] --> D[Shared product API and domain services]
  B[Public website] --> D
  C[Salon operations dashboard] --> D
  D --> E[Scheduling and appointment lifecycle]
  D --> F[Style references and portfolio publishing]
  D --> G[Payment and communication workflows]
  E --> H[(MongoDB and Mongoose)]
  F --> H
  G --> H
  F --> I[Media storage and inspiration provider]
  G --> J[External service adapters]

Conceptual architecture from the supplied article.

Conceptual product architecture. Internal access controls, deployment configuration and private interfaces are deliberately omitted.

The current web deployment uses OpenNext on Cloudflare Workers. A Durable Object hosts the Next server to keep its existing Mongoose connection context consistent. MongoDB remains the database. This is a concrete runtime adaptation with trade-offs; it is not evidence of a globally replicated booking engine or unlimited throughput.

The implemented technology stack

LayerTechnology in the reviewed sourceWhy it matters to this product
Mobile frameworkExpo ~57.0.30, React Native 0.86.3A shared customer application with native integration points
UI runtimeReact 19.2.3A common component model across applications
NavigationReact Navigation 6Explicit mobile journeys and return paths
Web applicationNext.js 16.3.8Public content, interactive dashboards and application APIs
LanguagesTypeScript; web 5.9.3, mobile ~6.0.3Typed contracts and application-specific checking
Operational dataMongoDB, Mongoose ^8.24.1Explicit document models for salons, branches and visits
Web presentationTailwind CSS, CSS modules, existing component foundationsShared visual rules with surface-specific layouts
FormsReact Hook Form and ZodForm state and structured input contracts
Localizationi18next/react-i18next on mobile; bilingual web contentArabic/English presentation and RTL behavior
MediaAWS S3, Sharp, attributed Pexels integrationSalon media and a separate inspiration-photo pipeline
MapsLeaflet on web surfaces; MapLibre-based mobile map documentPlatform-specific map presentation and fallbacks
Charts and movementRecharts, Motion, GSAP where usedOperational visualization and deliberate interaction
HostingCloudflare Workers and OpenNext 1.20.11Deployment of the existing Next application
VerificationVitest, Playwright, TypeScript checks, dated native build evidenceDifferent levels of confidence for different behaviors

Versions describe the checked workspace. They are not a recommendation to upgrade another project to the same versions. Likewise, a library in the stack does not imply that every possible feature of that library is used.

03 / Time & capacity

An empty slot is a system decision.

Explore the capacity modelIllustrative model, not live availability
One interval. Three conditions.30 MIN
10:0010:3011:0011:30
Branch hours
Available
Professional
Available
Required chair
Available

A time the salon can actually offer.

The service, professional and chair are available for the whole interval. Submission still checks the current state.

Engineering challenge 01: availability depends on more than opening hours

Illustrative scenario: a branch opens at 10:00. One professional starts at 11:00, a second is occupied, and the service needs a suitable chair. The branch is open, but the requested appointment cannot necessarily begin at 10:00.

An opening-hours check alone cannot answer the booking question. We calculate candidate slots using the selected services, service duration, staff capability and schedule, overrides, blocks, existing appointments and relevant chair capacity. The calculation also considers a near-term buffer rather than treating every minute after the current clock time as bookable.

Staff-specific duration matters. Two professionals may deliver the same service at different speeds. Combining services also changes the time the visit occupies. Those details affect which starting times are sensible and which resources remain available afterward.

The public availability label is derived from slot results. If the calculation cannot provide a trustworthy answer, the interface can say availability is unavailable. A “busy” state and an unavailable answer communicate different things; we preserve that difference.

The current business timezone is centralized around Africa/Cairo. Scheduling helpers format and construct business dates using that zone rather than a fixed offset. This makes the time basis explicit across the product. International per-branch timezone behavior would require additional work and validation.

Engineering outcome: discovery and booking use a richer model of salon capacity. The implementation supports more meaningful availability than an open/closed flag; no claim of eliminating every operational delay follows from that model.

Engineering challenge 02: a visible slot can change before submission

Illustrative scenario: two people view the same appointment time, then submit seconds apart. Both screens were valid when loaded. The system must decide against the current state when each request arrives.

The booking service rechecks availability during creation and uses appointment reservation records for the time being occupied. Reservation acquisition can fail if another operation has already claimed that capacity. The customer receives a meaningful “no longer available” outcome instead of an optimistic success message that the salon cannot honor.

Rescheduling adds another problem. Releasing the old time before obtaining the new one can leave a person without either appointment. The reservation-move flow therefore preserves the old reservation while attempting the target interval, reuses overlapping time where appropriate, and completes the move only after the required steps succeed.

This is a lifecycle concern, not a visual flourish. The design of retries, partial progress and cleanup determines whether the schedule stays understandable after a failed operation. Tests and implementation comments document these cases; a page animation cannot compensate for an inconsistent appointment record.

The product consequence is equally important: confirmation belongs after the authoritative operation. A button press expresses intent. It does not itself establish a reservation.

04 / Payment & progress

Every state should mean something.

One visit. Two state tracks.Concept objects · illustrative transfer
Payment stateAwaiting verification
Appointment stateAwaiting branch approval
Payment verification ≠ branch approval

Submitting a transfer reference supplies evidence for review. It does not establish payment acceptance or branch approval.

Engineering challenge 03: payment progress and appointment progress are different

Illustrative scenario: a customer has submitted a transfer reference, but the payment still needs review. Separately, the branch may still need to approve the visit. Treating both as one “success” state would give the customer the wrong expectation.

We model payment and appointment progress separately. A booking can be awaiting payment verification, awaiting branch approval, confirmed, checked in, in service or completed, with other states for the appropriate exception paths. Payment interfaces explain the financial step relevant to the selected method.

The source includes a card-provider integration and transfer-review workflows. A provider checkout returning control to the app is one event in that journey. The application must still represent the established result and any pending work. This is why a generic celebration cannot replace the status view.

The same discipline applies to pricing. Service prices, platform-added amounts, payment handling, promotional adjustments and loyalty effects are different concepts. They need explicit calculation rules and readable presentation.

At the review date, the current fee helpers calculate zero Salony commission and zero added payment-handling fees. Marketing pages describe launch terms and future commercial plans separately. We do not treat future prices in copy as proof that billing has been activated.

Our case-study screenshots exclude older fixture captures that show superseded fee examples. The code and the published narrative must describe the same product state.

05 / The reference look

Keep the context. Even when things change.

The chosen look, with its context intact.An illustrated reference snapshot
01 / THE SELECTION

Inspiration

The image, its source and its attribution.

02 / THE VISIT SNAPSHOT

Retained context

A reference record attached to the visit.

Visit referenceREF / 01
Image & attribution
Preserved
Customer note
Keep the shape and length.

A note-only edit keeps the saved image and attribution without resolving the provider again. Removal is a separate, explicit choice.

Engineering challenge 04: carrying a reference look into a real appointment

Illustrative scenario: a customer saves a hairstyle, attaches it to a booking and later edits the note. In the meantime, the external photo service becomes unavailable or the catalogue changes.

Saving only a live catalogue pointer would make the old booking depend on the catalogue's future state. We resolve a selected look into a booking snapshot containing its image, title, category, available source credit and the customer's note. The supported flow accepts up to three reference looks, with a bounded note for each.

Existing snapshots are reused when notes change. A later provider outage does not require the customer to choose the same image again just to revise “shorter fringe” to “keep more length.” Conversely, a new reference that is no longer available can be refused with a useful recovery path.

The data contract also distinguishes leaving references unchanged from explicitly removing them. That distinction sounds small, but it prevents an unrelated edit from silently clearing useful preparation information.

Reference look and customer note in the booking flow

Existing October 13 fixture capture. The reference includes a photographer credit. The image expresses a preference; the final treatment is agreed with the professional.

The underlying principle is temporal stability: a record of a past decision should retain the context of that decision. The external catalogue can continue evolving without rewriting what the customer originally communicated.

reference-edit.example.ts
// Illustrative contract, not extracted production source.
type ReferenceSnapshot = {
  imageId: string;
  imageUrl: string;
  title: string;
  credit?: string;
  note: string;
};

type ReferenceEdit =
  | { kind: "keep" }
  | { kind: "remove-all" }
  | { kind: "update-note"; imageId: string; note: string };

function applyReferenceEdit(
  saved: ReferenceSnapshot[],
  edit: ReferenceEdit,
): ReferenceSnapshot[] {
  if (edit.kind === "keep") return saved;
  if (edit.kind === "remove-all") return [];

  // Editing a note preserves the original image and credit.
  return saved.map(reference =>
    reference.imageId === edit.imageId
      ? { ...reference, note: edit.note }
      : reference,
  );
}

An illustrative contract distinguishing unchanged, removed and note-only edits; not production source.

06 / Portfolio & discovery

The right image. The right context.

Engineering challenge 05: portfolio settings must travel with the photo

Illustrative scenario: a salon uploads a three-photo look, hides the middle photo, assigns another to a professional and then changes the order. If settings are stored by position, the hidden flag and credit can attach to the wrong image.

We keep the photo's settings associated with its image URL through the current portfolio model. Reordering preserves those relationships. A whole look can also be hidden while retaining the individual settings for later editing.

The public representation omits unpublished looks and hidden photos, and excludes a look when all its photos are hidden. The optional credit is resolved for the relevant active professional. The customer gallery changes the displayed credit as the selected photo changes.

Compatibility was part of the work. Existing clients used an image_urls array. The extended model keeps that representation while adding optional photo metadata, descriptions, categories and publication state. Legacy records without the new metadata retain their expected publication behavior.

Portfolio editing with individual photo controls

Actual editor rendered with fictional test content, 17 October 2026. The stock-photo fixture illustrates the workflow; it is not claimed as a real salon's work.

This let us improve editorial control without requiring every mobile installation and existing portfolio record to change at once. It also gave the team a concrete regression target: new controls should improve the model without breaking older readers.

Engineering challenge 06: inspiration search needs honest data semantics

Beauty photography is useful for discovering a direction. It rarely establishes a treatment recipe. A photograph cannot reliably tell a customer which products were used, how long a service takes, what it costs or whether it is suitable for them.

We kept provider photography distinct from salon-owned portfolio content. The Styles experience exposes meaningful photo-search controls, preserves source and creator credits, and uses supplied metadata where available. Editorial content is allowed to have an empty state rather than being filled with invented expertise.

The browsing implementation includes category-specific queries, submitted search, pagination with duplicate removal, shareable URL filters and browser Back restoration. Mobile filter edits live in a draft until applied; dismissing the sheet discards that draft and returns focus.

Provider behavior is bounded. Successful responses use a six-hour, per-instance cache with a finite entry count. Identical requests already in progress can share the same pending result. Failures are not cached as successful content. This reduces repeated work while allowing an unsuccessful request to recover.

We also preserve the provider's actual file format and use appropriately sized images for cards and details. A valid PNG should not become a broken image because a URL was reconstructed with a JPEG assumption.

Styles library on the public website

Existing public capture with attributed provider photography. Search relevance is not professional suitability advice.

07 / Language & appearance

Designed to read both ways.

The same visit. Four ways to see it.

Matched captures from the same fixture workflow. Switch language and appearance to inspect the actual interfaces.

17 October 2026 captures · Demonstration data
Salony Home, English, light appearance, fictional fixtures

Engineering challenge 07: Arabic and appearance changes affect behavior

Arabic support includes direction, reading order, mixed-language content, navigation and the space available to labels. A number or brand name can remain left-to-right inside an otherwise right-to-left interface. A short English label can become a longer Arabic instruction.

We use Manrope and Cairo within the current visual system and review important layouts in both languages. The shared platform identity uses matte black, neutral surfaces and restrained lime accents, with a deliberate light appearance alongside dark mode.

Theme and language controls also interact with state. A person filling a salon application should not lose their draft when switching appearance. A gallery should return keyboard focus to its trigger when dismissed. A mobile menu should open and close without leaving navigation focus stranded.

The delivery reports include these behaviors as specific checks. They do not establish universal accessibility certification. Browser viewport checks, simulated enlarged text and native assistive-technology checks each prove different things.

English / lightEgyptian Arabic / light
English Home lightArabic Home light

Matched Home captures from the same dated fixture workflow. Dark counterparts and metadata.

08 / The salon’s working day

Built around the work behind the look.

What we customized for salon operations

The application reflects the shape of a salon's working day. We did not assume that a service catalogue, a staff list and an appointment calendar were independent screens.

CustomizationProduct reason
Branch-level services and schedulesA business can offer different work at different locations
Professional-specific service durationA visit's timing can depend on who performs it
Chair/resource capacityStaff availability alone does not establish physical capacity
Reception and queue workflowsWalk-ins and appointments share the same operational day
Booking policies and visit requestsPreparation and changes need understandable conditions
Optional inspiration referencesCustomers communicate visual preferences inside the visit context
Per-photo portfolio publishingSalons control which work appears and who receives credit
Business branding dataA salon's identity remains recognizable within the platform
Arabic/English and Cairo timeThe interface fits its intended operating context
Light/dark presentationCustomer browsing and desk work use the same brand coherently

Salon operational overview

Existing demonstration dashboard. Counts, names and appointment examples are sample data, not business outcomes.

This is implemented customization of the product domain. It should not be expanded into claims that hardware POS, NFC loyalty, every custom-domain configuration or a full international franchise system are already deployed. The later Salon OS direction has its own roadmap.

09 / Evidence & next steps

What works. What comes next.

How the system evolved: what the history actually supports

The repository has broad early commits and more detailed payment work in other reachable history. We use those records to explain engineering progression without inventing a sprint-by-sprint story.

Historical evidenceWhat it supports
11 May, 826ac05A written billing-phase design before related implementation
11 May, 1fa77c2Payment ledger model work
11 May, 3defa48Reconciliation/invoice implementation in that historical branch
11 May, 86ed6aeCustomer checkout and pending/failure journey work
11 May, c18ae4cSalon payment controls and dashboard finance work
11 May, 92a38a6Recovery-service work for incomplete payment operations
29 June, c8b24deMobile dark UI, card and web feature changes
October working tree and dated reportsCurrent branding, reference looks, map refinement, public pages, portfolio controls and deployment changes

The May commits demonstrate that payment work was divided into models, customer experience, operator experience and recovery concerns. They do not prove that each historical file remains active today. The October implementation is described from the current workspace and its delivery evidence, not attributed to a nonexistent October commit.

That distinction matters when explaining how a product was built. A case study should help another engineer understand the decisions without manufacturing a more convenient history.

Documented issues and their resolutions

Images that existed but failed in the website. The October image report records provider originals returning successfully while the web image pipeline rejected the source and the landing normalizer removed it. We aligned the source configuration used by those paths and verified that the images decoded in the resulting pages. The practical lesson was to inspect the entire media path, including normalization and optimization, rather than only the original file.

Arabic overflow in a horizontal gallery. Styles validation found overflow associated with hidden credits in the RTL gallery. The team corrected the layout and repeated the relevant checks. A hidden element can still influence layout; translating visible text is only part of RTL work.

A published version appearing later than expected. Deployment evidence records an interval where the platform had the new version while active application behavior still reflected older server code. Verification continued until the expected page and assets were actually served. Upload success and visible product activation are separate observations.

These are documented implementation experiences. The scheduling and reference-look examples earlier in the article are explanatory scenarios, not claims about named customers or recorded production incidents.

Verification with a defined scope

We use several kinds of evidence because each answers a different question. Unit tests examine rules and transformations. Browser journeys exercise interfaces and state changes. Builds check that applications compile and package. Native smoke checks establish a narrower result on a particular build and device environment.

The 17 October portfolio delivery records 59 focused web tests in nine files, all 25 web TypeScript shards, source/live browser checks and mobile validation including 218 tests across 43 files. It also records Android testing build 6 installed as an update and opened on an emulator.

The Styles delivery records 51 focused tests and 19 local plus 19 live browser checks. These are separate scoped runs with overlapping coverage. We do not add them into a larger, misleading “total tests passed” metric.

For this documentation review, we reran seven selected unit-test files and 44 tests passed. They cover references, portfolio logic, availability presentation, pricing, timezones, image handling and photo-search helpers. No application was launched and no screenshot was generated during the case-study task.

The available evidence does not establish full physical-device coverage, all provider delivery outcomes, an iOS store release or performance at a stated production traffic level. Those remain separate milestones. Public store links were still presented as Coming soon in the reviewed material.

Outcomes we can substantiate

Salony has a connected implementation for customer discovery, booking and salon operations. The reviewed source carries visit context across surfaces, models meaningful state transitions and supports a bilingual visual system. Public pages and an Android testing build have dated release evidence.

The strongest outcomes in this case study are functional and architectural: reference context survives later edits; portfolio controls preserve their image association; availability accounts for operational constraints; and public information distinguishes photography, actual salon work and planned features.

We do not have a supported before-and-after measurement of booking conversion, no-show reduction, revenue uplift or staff time saved. Those would require a defined measurement period, baseline and comparable usage data. A responsible next stage would measure booking completion, abandonment by step, appointment-change outcomes and operator time on common tasks, then use those findings to prioritize improvements.

The next product horizon

Future Salon OS planning explores deeper CRM, POS and cash workflows, merchant-funded loyalty, desktop reception hardware and wallet-related experiences. Those ideas extend a working operational foundation, but they introduce new accounting, hardware and rollout requirements.

Our next-step principle is to validate each new operational loop end to end. A new feature should have a clear owner action, a customer consequence, a persistent record and an observable completion state. That approach keeps an expanding product understandable to the people running it every day.

Frequently asked questions

What makes Salony a custom salon platform?

Its workflows connect service duration, professionals, branch schedules, physical capacity, visit preparation and portfolio publishing. Those domain relationships shape the application beyond a generic appointment form.

Why use a mobile app and a website?

They support different contexts. The website introduces the product and supports public discovery and salon operations. The mobile app carries the customer booking journey and ongoing visit/account interactions.

Does the Styles library generate guaranteed treatment recommendations?

No. It provides attributed inspiration and optional reference looks. The professional and customer agree on the actual treatment. Provider photographs do not establish products, price, duration or suitability.

Is every feature in the repository available to customers?

No. The active V1 navigation, configuration and release evidence determine availability. Premium/AI source and future Salon OS proposals are kept distinct from the current experience.

How should the screenshots be interpreted?

They are existing product captures with explicit provenance. Many use fictional fixtures and some are historical. They illustrate interfaces and states, not customer growth or financial performance.

Build a product around the work it needs to do

Our work on Salony connects the visible interface to the operational decisions underneath it: what can be booked, what the customer asked for, what the salon can deliver and what happens next.

If your product involves marketplaces, appointments or several teams acting on the same record, we can help define those relationships and turn them into working software.

Discuss your product with Softworks · Explore Salony


Prepared from the repository and dated evidence on 18 October 2026. Editorial/source notes · Image provenance · Choose another edition.

Softworks

Softworks Studio