Welcome to Glamio
Glamio is a booking app for one salon or barbershop. Clients book on their phone, stylists see their day on their phone, and the owner runs everything from a website.
This guide assumes you have never built an app before. It explains every step in plain words, from installing the tools to publishing in the app stores. Words that may be new to you are explained in the Glossary.
Phone app
For clients (book, change, cancel) and stylists (their schedule). Android and iPhone. Folder mobile/.
Web admin
A website for the owner: calendar, services, stylists, hours, clients, settings. Folder admin/.
Backend
The database and the booking rules, hosted on Supabase. Folder supabase/.
How Glamio works
Think of a salon's paper appointment book. Glamio puts that book online, in one safe place (the database). The phone app and the web admin are two windows onto the same book: whatever one writes, the other sees at once.
- Supabase is a service that keeps your database online. The booking rules live there too: for example, two clients can never book the same stylist at the same time, even if they press "Book" at the same second.
- Resend sends the 6-digit sign-in codes by email. Nobody needs a password.
- Firebase (optional) delivers push messages: "Booking confirmed", "See you tomorrow".
- Vercel (or Netlify) puts the web admin on the internet, at an address like
your-salon.vercel.app.
Who sees what
| Person | Uses | Can do |
|---|---|---|
| Client | Phone app | Browse services (no account needed), book one or more services, pick a stylist or "any", change or cancel before the cut-off time, see history, delete their account. |
| Stylist (staff) | Phone app | See their own schedule live, add walk-in clients, mark bookings Completed or No-show. |
| Owner | Web admin (and the phone app) | Everything: services, stylists, working hours, time off, closures, calendar, phone and walk-in bookings, clients, settings, numbers. |
The app decides who someone is by their email address. There are no passwords to forget.
The plan, at a glance
Here is the whole journey. Each line is a section of this guide; tick them off as you go.
- Install the tools on your computer (once). 1–2 h
- Create the database on Supabase and fill it with Glamio's tables. 15 min
- Set up sign-in emails with Resend, so people receive their 6-digit code. 15 min
- Add your business: name, time zone, currency, owner email. 5 min
- Put the web admin online and sign in as the owner. 15 min
- Fill in your salon in the web admin: services, stylists, working hours. 15 min
- Run the phone app on an emulator or your own phone, and book a test appointment. 20 min
- Make it yours (name, colors, logo) and publish in Google Play and the App Store.
Accounts you need
Create these accounts before you start. Most are free to begin with.
| Account | What for | Cost | |
|---|---|---|---|
| Supabase | Your database and sign-in | Free plan to start. For a real salon use the Pro plan (about $25/month): free projects pause after a week without use. | Required |
| Resend | Sending the sign-in code emails | Free for up to a few thousand emails a month | Required |
| A domain name | Emails come from your own address, e.g. no-reply@yoursalon.com | About $10–15/year from any domain seller | Required |
| GitHub | A private online copy of your code; Vercel builds the web admin from it | Free | Required |
| Vercel (or Netlify) | Putting the web admin online | Free plan is enough to start | Required |
| Google Play Console | Publishing the Android app | $25 once | To publish |
| Apple Developer Program | Publishing the iPhone app (and push on iPhone) | $99/year | To publish |
| Firebase (Google account) | Push notifications | Free | Optional |
Your computer
- Windows 10/11 or macOS, at least 8 GB of memory (16 GB is more comfortable) and about 30 GB of free disk space.
- To build the iPhone app you need a Mac. Apple does not allow building iPhone apps on Windows. With a Windows PC you can do everything else, including the Android app.
The terminal, in 3 minutes
Some steps ask you to "run a command". A command is a line of text you type into the terminal, a window where you talk to your computer by typing instead of clicking. You only need a few commands, and you can copy each one from this guide with the Copy button.
Open a terminal
Press ⌘ + Space, type Terminal, press Enter.
Press the Windows key, type PowerShell, press Enter.
Three things to know
- Paste and press Enter. Copy a command from this guide, paste it into the terminal (⌘+V on Mac, right-click or Ctrl+V on Windows), then press Enter.
- Folders matter. A command works on the folder the terminal is "in". To move into a folder, type
cdand the folder name. For examplecd mobilemoves into the phone app folder, andcd ..goes back up one level. - Wait for the prompt. When a command is finished, the terminal shows a new empty line to type on. Some commands take minutes the first time; that is normal.
cd mobile # go into the phone app folder
cd .. # go back to the main Glamio folderText after a # is a note for you. You can paste it along; the terminal ignores it.
VS Code, the editor
VS Code is a free program for opening and editing code files, a bit like Word but for code. You will use it to change settings files and to run the app.
- Download it from code.visualstudio.com and install it like any program.
- Open VS Code. Click the Extensions icon on the left (four small squares), search for Flutter and click Install. This also installs the Dart extension.
- Unzip the Glamio download somewhere easy, for example
Documents/glamio. In VS Code choose File → Open Folder… and pick the folder that containsmobile,adminandsupabase.
C:\My Files\Glamio (copy). Use something simple like C:\dev\glamio or ~/dev/glamio.Git
Git keeps the history of your code and uploads it to GitHub. You need it in Step 6 to put the web admin online.
Run this in the terminal. A window asks to install the "command line developer tools"; click Install. (If Git is already there, it says so; that's fine.)
xcode-select --installDownload Git for Windows from git-scm.com and install it. The default options are fine: just keep clicking Next.
Then tell Git your name and email (used to label your changes):
git config --global user.name "Your Name"
git config --global user.email "you@example.com"Flutter
Flutter is Google's toolkit for building apps. One code base makes both the Android and the iPhone app. The easiest way to install it is from inside VS Code:
- In VS Code press Ctrl+Shift+P (⌘+Shift+P on Mac). A search box opens at the top: the Command Palette.
- Type Flutter: New Project and press Enter.
- VS Code says it can't find the Flutter SDK. Click Download SDK.
- Choose a folder for Flutter, for example
C:\dev(Windows) or yourdevfolder (Mac). NotProgram Files. - Wait for the download (several minutes). When VS Code asks Add SDK to PATH, click it. This lets the terminal find Flutter.
- Close the "new project" box that may appear (you don't need a new project), then close and reopen VS Code and any terminal.
Check that it worked. In a new terminal:
flutter --versionYou should see something like Flutter 3.x.x • channel stable. Glamio is tested with the current stable Flutter.
Android Studio
You won't write code in Android Studio, but Flutter needs its Android SDK (the Android building blocks) and its emulator (a pretend Android phone that runs on your computer).
- Download Android Studio from developer.android.com/studio and install it with the standard options. On first start it downloads the Android SDK; let it finish.
- On the welcome screen click More Actions → SDK Manager. Open the SDK Tools tab, tick Android SDK Command-line Tools, and click OK.
- Accept Google's licences. In a terminal run the command below and type y + Enter every time it asks.
flutter doctor --android-licenses - Create an emulator: on the welcome screen click More Actions → Virtual Device Manager → + (Create device) → pick a phone such as Pixel 8 → Next → pick the newest system image (click the download icon next to it if needed) → Finish.
- Press the ▶ play button next to the new device. A phone appears on your screen. Leave it open when you run the app later.
Xcode (Mac only)
Xcode is Apple's tool for iPhone apps. Skip this section on Windows; you can still do everything for Android.
- Install Xcode from the Mac App Store (large download, about 10 GB). Open it once and let it install extra components.
- In the terminal, finish Xcode's setup:
It asks for your Mac password. While you type, nothing appears on screen; that's normal. Press Enter when done.
sudo xcodebuild -runFirstLaunch - Install Homebrew (an installer for developer tools) by following the one-line command on brew.sh. At the end it may print two or three commands under "Next steps"; run those too.
- Install CocoaPods (Flutter uses it to build iPhone apps):
brew install cocoapods - For the iPhone simulator: open Xcode → Settings → Components (called Platforms in some versions) and download the newest iOS simulator.
Node.js
Node.js runs the web admin on your computer and installs its building blocks. You need version 20.9 or newer; the current LTS ("long-term support") version is the right choice.
- Download the LTS installer from nodejs.org and install it with the default options.
- Close and reopen your terminal, then check:
You should see a version like
node -vv22.x.xor higher.
Supabase CLI
The Supabase CLI is a small command-line tool that sends Glamio's database tables, settings and server functions to your Supabase project.
brew install supabase/tap/supabase
supabase --versionOn Windows the simplest way is to run it through Node.js, with nothing extra to install. Wherever this guide says supabase, type npx supabase instead. The first time, it asks Ok to proceed? (y): type y and press Enter.
npx supabase --version(Prefer a permanent install? See Supabase's CLI guide, "Windows" with Scoop.)
Check everything
Flutter has a built-in health check. Run:
flutter doctorIt prints a list with ✓ (good) and ✗ or ! (needs attention). You need ✓ for:
- Flutter
- Android toolchain (if not: run
flutter doctor --android-licensesagain) - Xcode (Mac only, for iPhone)
- VS Code
A ✗ for "Chrome", "Visual Studio" or "Linux toolchain" is fine: Glamio doesn't use them.
What's in the download
| Folder or file | What it is |
|---|---|
mobile/ | The phone app (Flutter). Your settings go in mobile/.env; name, colors and switches in mobile/lib/vertical/. |
admin/ | The owner's web admin (Next.js). Name and links in admin/src/vertical/glamio.ts. |
supabase/migrations/ | The database tables and booking rules. You send them to Supabase in Step 2 and never edit them. |
supabase/setup.sql | The only database file you edit: your business name, time zone, currency and the owner's email. |
supabase/functions/ | Two small server programs: account deletion and push notifications. |
supabase/seed.sql | Sample salon data for the demo. Not used for your real salon. |
supabase/tests/ | Automatic checks for the database rules (for developers). |
brand/ | Logo, app icon and onboarding pictures as SVG source files, for rebranding. |
documentation/ | This guide. |
CHANGELOG.md | What changed in each version. |
.env.example are hidden in Finder and File Explorer by default, but VS Code shows them. Do your editing in VS Code.Create the database (Supabase project)
- Sign in at supabase.com/dashboard and click New project.
- Fill in:
- Name: your salon's name, for example Rosa Hair Studio.
- Database password: click Generate a password and save it in your notes. You need it in Step 2.
- Region: the one closest to your salon (shorter distance means a faster app).
- Click Create new project and wait 1–2 minutes.
- Collect three things for your notes:
- Project reference ("project ref"): Project Settings → General → Project ID. It looks like
abcdefghijklmnopqrst. - Project URL:
https://+ your project ref +.supabase.co. - Publishable key: Project Settings → API Keys. It starts with
sb_publishable_. (Older projects call it theanonkey; that one works too.)
- Project reference ("project ref"): Project Settings → General → Project ID. It looks like
Fill the database with Glamio's tables
Now you send Glamio's tables and booking rules to your new project. Open a terminal in the main Glamio folder (the one that contains supabase).
- Sign in to Supabase from the terminal. A browser window opens; click Authorize.
supabase login - Connect this folder to your project. Replace
YOUR-PROJECT-REFwith your project ref. When it asks for the database password, paste the one from Step 1 (nothing shows while you paste; press Enter).supabase link --project-ref YOUR-PROJECT-REF - Send the tables and rules. When it lists the files and asks to continue, type y and press Enter.
supabase db push
When it ends with Finished supabase db push., your database is ready. In the Supabase dashboard, Table Editor now lists tables such as bookings, services and staff.
npx supabase instead of supabase.Sign-in emails (Resend)
To sign in, a person types their email and receives a 6-digit code. Supabase's built-in email sender is only for testing: it sends very few emails per hour, and it doesn't allow the code email Glamio needs. So you connect your own sender. We use Resend, which is free for small volumes.
3a. Set up Resend
- Sign up at resend.com.
- Go to Domains → Add Domain and enter your domain, for example
yoursalon.com. - Resend shows a few DNS records (lines of settings). Log in where you bought your domain, open its DNS settings, and add each record exactly as shown. Then click Verify in Resend. It can take from a few minutes to a few hours before it turns green.
- Go to API Keys → Create API Key, give it a name, and copy the key (starts with
re_) into your notes. It is shown only once.
3b. Connect Resend to Supabase
- In the Supabase dashboard open Authentication → Emails → SMTP Settings and switch on Enable custom SMTP.
- Fill in:
Sender email no-reply@yoursalon.com(your verified domain)Sender name Your salon's name Host smtp.resend.comPort 465Username resendPassword Your Resend API key ( re_…) - Click Save.
3c. Send Glamio's sign-in settings
This sends the code email design and the sign-in settings (code length, expiry) to your project. In the terminal, in the main Glamio folder:
supabase config pushIt lists the changes and asks to confirm; type y and press Enter.
config push complains about email templates, check that custom SMTP is switched on and saved.Add your business
- In VS Code open
supabase/setup.sql. - Change the values in quotes:
supabase/setup.sql
insert into public.businesses (id, name, timezone, currency, phone, address) values ('00000000-0000-0000-0000-00000000b001', 'Rosa Hair Studio', 'Europe/London', 'GBP', '+44 20 1234 5678', '1 High Street, London'); insert into public.invites (business_id, email, role) values ('00000000-0000-0000-0000-00000000b001', 'owner@yoursalon.com', 'owner');- Time zone: the official name of your salon's time zone, such as
Europe/London,America/New_York,Asia/Dubai,Asia/KarachiorAustralia/Sydney. Full list: tz database time zones (column "TZ identifier"). It matters: all booking times are calculated in it, including daylight-saving changes. - Currency: a 3-letter code:
USD,EUR,GBP,AED,PKR, … - Owner email: the email you will sign in to the web admin with. Use an inbox you can open right now.
- Leave the long id (
00000000-…-b001) as it is. The phone app uses the same id.
- Time zone: the official name of your salon's time zone, such as
- In the Supabase dashboard open SQL Editor → New query. Copy the whole file into it and click Run. You should see
Success. No rows returned.
Upload the two server functions
Glamio has two small programs that run on Supabase's servers: delete-account (lets people delete their account, which Google and Apple require) and send-notifications (push messages). Upload both:
supabase functions deploy delete-account send-notifications --use-apiWhen it prints Deployed Functions, you'll see both under Edge Functions in the dashboard. (--use-api means "build them on Supabase's side", so nothing else is needed on your computer.)
Put the web admin online
The web admin must be on the internet so you can open it from any computer or phone. Vercel builds it from a private copy of your code on GitHub.
6a. Upload your code to a private GitHub repository
- On github.com/new create a repository: give it a name, choose Private, and leave all the "Add a README / .gitignore / license" boxes unticked. Click Create repository.
- In the terminal, in the main Glamio folder, run these lines one by one. In the 5th line, replace the address with the one GitHub shows you (it ends in
.git).If it asks you to sign in to GitHub, follow the browser window that opens.git init git add . git commit -m "My Glamio salon" git branch -M main git remote add origin https://github.com/YOUR-NAME/YOUR-REPO.git git push -u origin main
.env) are left out automatically.6b. Deploy on Vercel
- Sign up at vercel.com with your GitHub account.
- Click Add New… → Project and Import your Glamio repository.
- Next to Root Directory click Edit and choose
admin. Vercel then recognises it as a Next.js site. - Open Environment Variables and add two:
Name Value NEXT_PUBLIC_SUPABASE_URLYour Project URL ( https://….supabase.co)NEXT_PUBLIC_SUPABASE_ANON_KEYYour publishable key ( sb_publishable_…) - Click Create Project. If Vercel offers Optional Integrations → Supabase → Add, skip it: that would make a new, empty database instead of using yours.
- Click Deploy and wait 2–3 minutes. You get an address like
https://rosa-hair.vercel.app. Save it in your notes: this is your web admin address.
Deployment says "Blocked"? On Vercel's free Hobby plan, a private GitHub repository only deploys commits made by the same GitHub account you signed in to Vercel with. Make sure your Git name and email on your computer match that account (git config user.email), then push a new commit.
Using Netlify instead? Add new site → Import an existing project, set Base directory to admin and the build command to npm run build, and add the same two variables.
6c. Tell Supabase your web admin address
- Supabase dashboard → Authentication → URL Configuration: set Site URL to your web admin address and add the same address under Redirect URLs. Save.
- In VS Code open
supabase/config.toml, find the linesite_url = "http://localhost:3000"and put your web admin address there too. Then a latersupabase config pushwon't change it back.
6d. Sign in as the owner
- Open your web admin address. Enter the owner email from Step 4 and click Send code.
- Check your inbox (and the spam folder) for "Your sign-in code". Type the 6 digits and click Sign in.
- You see the Dashboard with a "Finish setting up" list. 🎉
Fill in your salon in the web admin
The dashboard's "Finish setting up" list walks you through this. Clients can only book once there is at least one service and one stylist with working hours who does that service.
Settings
Your address, phone, about text and logo, plus the booking rules:
| Setting | What it means | Example |
|---|---|---|
| Start times every | The gap between the times clients can choose | 15 min → 9:00, 9:15, 9:30… |
| Book up to | How far ahead clients can book | 30 days |
| Minimum notice | How soon a booking can start, counted from now | 60 min: at 10:00 the first free time is 11:00 |
| Clients can change or cancel until | After this, clients must call you | 2 h before |
| Upcoming bookings per client | Stops one person from blocking many times | 5 |
Also on Settings: Closures, days the whole salon is closed (holidays). No one can book on those days.
Services
Add what you sell. For each service:
- Duration: how long it takes, for example 30 minutes.
- Extra time after: cleaning or drying time when the stylist is still busy but the client is gone. Clients don't see it; it only keeps the next booking from starting too early.
- Price, an optional photo, a category (Hair, Beard, Colour…), and which stylists do it.
- Active: switch it off to hide a service you no longer offer. It disappears for new bookings, but existing bookings keep it and can still be moved. Hiding is safer than deleting.
Stylists
Add each person who takes bookings: name, title, photo, short bio. Then, on their page:
- Services: tick what they do.
- Working hours: per weekday; several periods a day are fine (for example 9–13 and 14–18 for a lunch break).
- Time off: holidays or appointments of this one person.
- Portfolio: photos of their work, which clients see when choosing a stylist.
- App access: see Staff app access.
Run the phone app
8a. Create the app's settings file
The app reads its settings from a file called .env in the mobile folder. You make it by copying the example file:
cd mobile
cp .env.example .envcd mobile
copy .env.example .envOpen mobile/.env in VS Code and fill in the first lines:
SUPABASE_URL=https://YOUR-PROJECT-REF.supabase.co
SUPABASE_ANON_KEY=sb_publishable_xxxxxxxxxxxxxxxx
BUSINESS_ID=00000000-0000-0000-0000-00000000b001
ADMIN_URL=https://rosa-hair.vercel.app # your web admin address
GOOGLE_SIGN_IN=false
GOOGLE_WEB_CLIENT_ID=
GOOGLE_IOS_CLIENT_ID=
APPLE_SIGN_IN=false
PUSH_ENABLED=false
DEMO_MODE=falseLeave the other switches on false for now. You can turn on push and Google sign-in later (see Push and Google sign-in).
NAME=value exactly like that: no spaces around = and no quotation marks.8b. Start a phone
- Android emulator: start it from Android Studio's Device Manager (▶).
- iPhone simulator (Mac): run
open -a Simulator. - Your own Android phone: in Settings → About phone, tap Build number 7 times to unlock Developer options. Turn on USB debugging there, connect the phone with a cable, and tap Allow on the phone.
- Your own iPhone: see 8d below.
8c. Run the app
Still in the mobile folder:
flutter pub get
flutter run --dart-define-from-file=.envThe first run takes 3–10 minutes; later runs are much faster. If several phones are connected, Flutter asks which one to use: type its number.
Or with a click: in VS Code open the Run and Debug panel (▶ icon on the left), choose Glamio (mobile) and press the green ▶. It already includes the .env file.
.env, stop and run again.8d. On your own iPhone (Mac only)
- Connect the iPhone with a cable and tap Trust. On iOS 16 and newer also turn on Settings → Privacy & Security → Developer Mode (the phone restarts).
- Open
mobile/ios/Runner.xcworkspacein Xcode (the .xcworkspace, not the .xcodeproj). - Click Runner at the top of the left list → tab Signing & Capabilities → Team: add your Apple ID and choose it. If Xcode says the bundle identifier is taken, change it to something unique such as
com.rosahair.app(better: rebrand the app id first, see Rebrand). - Back in the terminal run
flutter run --dart-define-from-file=.envand pick the iPhone. The very first iPhone build can take 30–60 minutes (Xcode builds Firebase once). It is not frozen; later builds take a minute or two. - The first time, the iPhone may block the app: Settings → General → VPN & Device Management → your Apple ID → Trust.
Test it end to end
Do this once before you tell anyone about the app. Use a second email address for the "client" (a free Gmail is fine).
- In the phone app, choose a service → a stylist (or "any") → a time → Book. It asks you to sign in: use the client email and the 6-digit code.
- The booking shows under My bookings.
- In the web admin, Calendar shows the same booking (the page updates by itself).
- In the phone app, change the booking's time, then cancel it. The web admin follows both changes.
- Sign out, then sign in with the owner email. You land on the schedule screen, not the client screens.
- In the web admin, add a walk-in booking from Calendar → New booking.
Daily use
Owner
Checks the dashboard and calendar, adds phone and walk-in bookings, moves or cancels bookings, marks the day's bookings Completed or No-show, manages services, stylists, hours and closures.
Stylist
Opens the phone app to see today's bookings (they update live), adds a walk-in client, marks Completed or No-show after the start time.
Client
Books, gets a confirmation and reminders (with push switched on), changes or cancels before the cut-off, calls the salon after it.
A booking's life
Every booking is in one of four states:
| State | Means | Who sets it |
|---|---|---|
| Confirmed | Booked and coming. Every new booking starts here. | Automatic |
| Completed | The client came. Only completed bookings count as revenue. | Owner or stylist, after the start time |
| No-show | The client didn't come. The time becomes free again. | Owner or stylist, after the start time |
| Cancelled | Called off by the client (before the cut-off) or the salon. Final. | Client, owner or stylist |
Completed and No-show have an Undo button for mistakes.
Staff app access
A stylist on the Stylists page is just a record (name, hours, services). To let that person open their own schedule in the phone app, give them access:
- Web admin → Stylists → the person → App access. Type their email and click Give access.
- They install the app and sign in with that email. They now see their schedule instead of the client screens. The admin shows Joined (or Invited while they haven't signed in yet).
- Someone leaves: click Remove access. They become a normal client again: they can still book, but no longer see the salon's schedule or clients. Their past bookings stay.
- Short break (holiday, sick leave): switch the stylist's Active off. They disappear for new bookings, and the app shows them "Your schedule is paused" until you switch it back on.
- Wrong email? Each stylist has one invite: click Remove access, then give access with the right email.
Rebrand: name, colors, logo
Do the app id first (if you plan to publish), then the rest in any order. After each change, run the app again to see it.
1. App id (package name)
Every app in the stores has a unique id, written like a reversed web address: com.rosahair.app. Glamio ships as space.alchemify.glamio; you must change it before publishing. In the mobile folder:
dart run change_app_package_name:main com.rosahair.app2. App name
| Where it shows | File | What to change |
|---|---|---|
| Under the icon on Android | mobile/android/app/src/main/AndroidManifest.xml | android:label="Glamio" |
| Under the icon on iPhone | mobile/ios/Runner/Info.plist | the <string> after CFBundleDisplayName and CFBundleName |
| Inside the app | mobile/lib/vertical/glamio_config.dart | appName: 'Glamio' |
| Web admin | admin/src/vertical/glamio.ts | appName: 'Glamio' |
3. Privacy policy and terms links
Both stores require a privacy policy. Put your links in privacyPolicyUrl and termsUrl in both mobile/lib/vertical/glamio_config.dart and admin/src/vertical/glamio.ts. They point to example.com until you change them.
4. Colors
- Open the free Material Theme Builder and enter your brand color.
- Export Flutter (Dart). Copy the light and dark values into
mobile/lib/vertical/glamio_theme.dart. Each value there has the same name as in the export (primary,surface, …). - Put the same colors in
admin/src/app/globals.css; the comments there name the matching values.
5. Logo, app icon and start screen
- The source files are in
brand/(SVG). Edit them in any design tool (Figma, Illustrator, Inkscape) or replace them with your own. - Export PNG files (1024 × 1024 px) and replace:
mobile/assets/images/logo.png: the logo, one color on a transparent background (the app tints it).mobile/assets/icon/app_icon.png: the full app icon.mobile/assets/icon/app_icon_foreground.png: the icon's symbol only, for Android's shaped icons.mobile/assets/icon/splash.png: the picture on the start screen.
- Generate the icons and start screen (in
mobile):The background color of the icon and start screen is set indart run flutter_launcher_icons dart run flutter_native_splash:createmobile/flutter_launcher_icons.yamland inmobile/pubspec.yaml(flutter_native_splash). - Onboarding pictures (the 3 intro slides):
mobile/assets/images/onboarding_1.pngto_3.png, 900 × 720 px. - Web admin: the browser tab icon is
admin/src/app/icon.svg(plusapple-icon.png); the logo is inadmin/src/components/brand-mark.tsx.
6. Font
Glamio uses Poppins. To change it, put your .ttf files in mobile/assets/fonts/, list them under fonts: in mobile/pubspec.yaml, and set fontFamily in glamio_config.dart. For the web admin, copy the same files to admin/src/app/fonts/ and update admin/src/app/layout.tsx.
7. Words and languages
All texts are in English, Spanish, French and Arabic:
- Phone app:
mobile/lib/i18n/en.i18n.json(andes,fr,ar). After editing, rundart run slanginmobile. - Web admin:
admin/messages/en.json(and the others).
For example, to say "Barber" instead of "Stylist", change those words in these files.
8. Feature switches
In glamio_config.dart, features turns on the stylist portfolio and the onboarding slides. Remove one to hide it.
Push notifications
With push on, clients get "Booking confirmed", a reminder 24 hours before and another 1 hour before; stylists and the owner get "New booking", "Booking moved" and "Booking cancelled". Glamio works fine without push: everything else stays the same.
1. Create a Firebase project and connect the app
- At console.firebase.google.com click Create a project (Google Analytics is not needed).
- Install the Firebase tools and sign in:
npm install -g firebase-tools firebase login dart pub global activate flutterfire_cli - In the
mobilefolder, connect the app to your project. Pick your project and tick android and ios:This creates the Firebase files for both platforms. The Android build picks them up by itself.flutterfire configure --out=lib/core/push/firebase_options.dart
2. iPhone only: Apple's push key
- In Apple Developer → Keys create a key with Apple Push Notifications service (APNs), download the
.p8file, and note the Key ID and your Team ID. - Firebase → Project settings → Cloud Messaging → your iOS app → APNs Authentication Key → Upload.
- In Xcode (
mobile/ios/Runner.xcworkspace) → Runner → Signing & Capabilities → + Capability: add Push Notifications, and Background Modes with Remote notifications ticked.
3. Give the server function its keys
- Firebase → Project settings → Service accounts → Generate new private key. A
.jsonfile downloads. Keep it private. - Supabase dashboard → Edge Functions → Secrets. Add two secrets:
FCM_SERVICE_ACCOUNTOpen the .jsonfile in VS Code, select everything, and paste it as the value.CRON_SECRETA long random text you make up, for example 40 letters and numbers. Keep it in your notes.
4. Start the sender
The server checks for new messages every minute. Start it once: in Supabase SQL Editor, paste the following, replace the two values in capitals, and click Run:
select vault.create_secret('https://YOUR-PROJECT-REF.supabase.co', 'project_url');
select vault.create_secret('THE-SAME-CRON-SECRET', 'cron_secret');
select cron.schedule('glamio-send-push', '* * * * *', $$
select net.http_post(
url := (select decrypted_secret from vault.decrypted_secrets where name = 'project_url')
|| '/functions/v1/send-notifications',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'x-cron-secret', (select decrypted_secret from vault.decrypted_secrets where name = 'cron_secret')),
body := '{}'::jsonb
);
$$);5. Switch it on in the app
In mobile/.env set PUSH_ENABLED=true, then run the app again. It asks for permission to send notifications: tap Allow.
Test: sign in as a stylist on one phone, book as a client on another phone (or the emulator). The stylist's phone shows "New booking"; tapping it opens the booking.
Google sign-in
Adds a "Continue with Google" button next to the email code. Do the app id change first.
- Google Cloud Console (use the same project as Firebase, if you have one) → Google Auth Platform → Get started: app name, support email, audience External, contact email → Create. While the app is in "Testing", add your Gmail under Audience → Test users. Publish it before your launch.
- Clients → Create client → Web application. Under Authorized redirect URIs add
https://YOUR-PROJECT-REF.supabase.co/auth/v1/callback. Copy the Client ID and Client secret. - Clients → Create client → Android: your app id and your computer's SHA-1 fingerprint, which this command prints (password:
android):On Windows usekeytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android%USERPROFILE%\.android\debug.keystore. After publishing on Google Play, create a second Android client with the SHA-1 shown in Play Console → App integrity. - For iPhone: Create client → iOS with your bundle id (the app id).
- Supabase → Authentication → Sign In / Providers → Google: enable it. Client IDs: the Web client ID (for iPhone, add a comma and the iOS client ID). Client Secret: the web secret. Turn on Skip nonce checks. Save.
- In
mobile/.env:GOOGLE_SIGN_IN=trueandGOOGLE_WEB_CLIENT_ID=…apps.googleusercontent.com. For iPhone alsoGOOGLE_IOS_CLIENT_ID, and add the reversed iOS client id (it starts withcom.googleusercontent.apps.) as a URL scheme inios/Runner/Info.plist, following google_sign_in's iOS steps.
Apple sign-in
Sign in with Apple is not included in this version. The APPLE_SIGN_IN switch in .env is there for a future version and has no effect yet.
GOOGLE_SIGN_IN=false. The email-code sign-in works for everyone. On Android you can turn Google sign-in on.Need Apple sign-in? We can add it as paid customization; see Support.
Publish on Google Play
1. Make your upload key (once)
Google needs to know updates really come from you, so every upload is signed with your private upload key. Create it (it asks for a password and some details):
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias uploadkeytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias uploadIf keytool is not found, use the one inside Android Studio: "C:\Program Files\Android\Android Studio\jbr\bin\keytool".
Then create the file mobile/android/key.properties with your values:
storePassword=THE-PASSWORD-YOU-CHOSE
keyPassword=THE-PASSWORD-YOU-CHOSE
keyAlias=upload
storeFile=/Users/you/upload-keystore.jksOn Windows write the path with double backslashes: storeFile=C:\\Users\\you\\upload-keystore.jks. Glamio uses this file automatically for release builds.
upload-keystore.jks and its password somewhere safe (not in the project folder, never on GitHub). They are already excluded from Git.2. Build the app file
Each upload needs a higher version number. In mobile/pubspec.yaml, version: 1.0.0+1 means "version 1.0.0, build 1": raise the number after + for every upload. Then, in mobile:
flutter build appbundle --dart-define-from-file=.envThe file to upload is mobile/build/app/outputs/bundle/release/app-release.aab.
3. Create the app in Play Console
- Play Console → Create app: name, language, App, Free.
- Complete the Set up your app tasks. Two need Glamio-specific answers:
- Privacy policy: your policy link.
- Data safety → Data deletion: people can delete their account in the app (Profile → Delete account) and on the web at
YOUR-WEB-ADMIN-ADDRESS/delete-account. Give that web link. - App access: booking needs sign-in with an emailed code. Explain this, and give the reviewers a test email inbox they can use, or ask us about a demo login.
- Upload the
.aabto Testing → Internal testing first, try it on your phone, then promote it to Production.
Google's review usually takes a few days for a new app. New personal developer accounts must first run a closed test with a group of testers before they can publish; Play Console tells you if this applies to you.
Publish on the App Store (Mac only)
- Join the Apple Developer Program ($99/year).
- In App Store Connect → Apps → + New App: choose your bundle id (the app id), name, language.
- In Xcode set your Team under Runner → Signing & Capabilities (see Step 8d).
- Raise the version in
mobile/pubspec.yamlas for Android, then build:flutter build ipa --dart-define-from-file=.env - Upload
mobile/build/ios/ipa/*.ipawith Apple's free Transporter app (Mac App Store): drag the file in and click Deliver. - In App Store Connect add screenshots, description, privacy policy link and the App Privacy answers, then Submit for Review. Give the reviewers a way to sign in (see the Android note above).
GOOGLE_SIGN_IN=false for the iPhone build (see Apple sign-in).Installing updates
When a new Glamio version comes out, read CHANGELOG.md first. Then:
- Copy the new files over your project, but keep your versions of:
mobile/.env,mobile/android/key.properties, the Firebase files, and everything you changed while rebranding (vertical/folders, icons, colors, texts). Comparing the folders with a tool such as VS Code's compare, or Git, makes this easier. - Update the database (new tables or rules):
supabase db push - Update the server functions:
supabase functions deploy delete-account send-notifications --use-api - Web admin: commit and push to GitHub (
git add .,git commit -m "Update Glamio",git push). Vercel rebuilds by itself. - Phone app: raise the version number, build and upload as in Publish.
Troubleshooting
The app shows "Setup needed — Missing keys"
mobile/.env is missing or incomplete, or the app was started without it. Check the three required lines, and start with flutter run --dart-define-from-file=.env from inside the mobile folder.
No sign-in email arrives
- Look in the spam folder.
- Check that your domain is Verified in Resend, and the SMTP settings in Supabase (Step 3b). Resend's Emails page shows each email it sent, or why it failed.
The email has a link instead of a 6-digit code
The code design wasn't sent. Run Step 3c (supabase config push) again, after custom SMTP is switched on.
The web admin says "Owners only"
You signed in with a different email than the one in setup.sql. Either sign in with that email, or make your current email the owner: in Supabase SQL Editor run the following (with your email), then sign out and in again:
insert into public.invites (business_id, email, role)
values ('00000000-0000-0000-0000-00000000b001', 'your-email@example.com', 'owner');The app shows no free times
Check in the web admin, in this order: the stylist has working hours on that weekday; the stylist is ticked for that service; both the stylist and the service are Active; there is no closure or time off that day; the day is within Book up to; for today, Minimum notice may have pushed all times past closing time.
Times look shifted by an hour or more
The business time zone is wrong. Fix it in web admin → Settings. The app always shows times in the salon's time zone, wherever the client is.
"supabase: command not found" (Windows: "not recognized")
On Windows, use npx supabase. On Mac, run brew install supabase/tap/supabase again, then open a new terminal.
supabase link or db push fails with a password error
Reset the database password in Supabase → Project Settings → Database, then run the command again with the new one.
The app worked yesterday, today nothing loads
On the free Supabase plan, projects pause after a week without use. Open the dashboard and click Restore. For a real salon, use the Pro plan.
The Android build fails
- Run
flutter doctorand fix anything marked ✗ for Android. - Then clean and try again, in
mobile:flutter clean, thenflutter pub get, then run again.
The iPhone build fails with "Signing" or "No team"
Set your Team in Xcode (Step 8d). With CocoaPods errors, run in mobile/ios: pod repo update and then pod install.
Push notifications don't arrive
PUSH_ENABLED=truein.env, the app was restarted, and you tapped Allow.- You don't get a push about your own action (book as a client, check the stylist's phone).
- In Supabase SQL Editor, this shows the last messages and any error (
push_not_configuredmeans the Firebase secret is missing):select kind, created_at, sent_at, attempts, last_error from public.notification_outbox order by id desc limit 10;
Glossary (plain words)
| App id / package name / bundle id | The app's unique name in the stores, like com.rosahair.app. Android and Apple use different words for the same thing. |
| Build | Turning the code into an app file you can install or upload. |
| CLI | "Command-line interface": a program you use by typing commands in the terminal. |
| Database | Where all the data lives: bookings, clients, services. Like a set of very organised spreadsheets. |
| Deploy | To put something online so others can use it. |
| DNS records | Settings of your domain name that tell the internet who may send email for it, among other things. |
| Edge Function | A small program that runs on Supabase's servers, not on the phone. |
| Emulator / simulator | A pretend phone on your computer, for testing. |
.env file | A small text file with the app's settings and keys. Private: never share or upload it. |
| Key (API key) | A long code that lets a program talk to a service. "Publishable" keys may sit in an app; "secret" keys must stay private. |
| Migration | A file that creates or changes database tables. Glamio's are in supabase/migrations/. |
| Push notification | A message that pops up on the phone, even when the app is closed. |
| Repository (repo) | A project folder whose history Git keeps, here stored privately on GitHub. |
| SDK | "Software development kit": the building blocks a tool needs, like the Android SDK. |
| SMTP | The standard way programs send email. Resend gives you an SMTP "post office" for your domain. |
| SQL / SQL Editor | SQL is the language for talking to a database. The SQL Editor is the box in Supabase where you paste and run it. |
| Supabase | The online service that hosts Glamio's database, sign-in and server functions. |
| Terminal | A window where you type commands. See The terminal, in 3 minutes. |
| Time zone name | The official name of a time zone, like Europe/London. It knows about summer and winter time. |
| Walk-in | A client who comes in without a booking; staff add them in the app so the time is blocked. |
Support & customization
Stuck? First check Troubleshooting. Still stuck? Write to us. Please include your purchase code, what you did, what you expected, what happened, and a screenshot of any error.
What support covers
As with every CodeCanyon item, support covers: answering questions about the item, help with bugs and reported issues, and help with the included features. It does not cover customization, installation services, or problems caused by third-party services (stores, hosting, email).
Want it done for you?
We offer paid services: full installation on your accounts, rebranding (name, colors, logo, store listings), store publishing, and custom features (for example payments, Apple sign-in, loyalty points or SMS reminders). Email us with what you need, or book a free 20-minute call on our contact page, for a quote.
Credits & licences
Glamio is built on these open-source projects. Thank you to their authors.
| Part | Licence |
|---|---|
| Flutter, Dart, go_router, Material icons | BSD-3-Clause / Apache 2.0 |
| Riverpod, slang, supabase_flutter, Firebase plugins | MIT / BSD-3-Clause |
| Next.js, React, Tailwind CSS, shadcn/ui, Base UI, next-intl, Zod, date-fns | MIT |
| Lucide icons | ISC |
| Poppins font (Indian Type Foundry) | SIL Open Font License 1.1 (mobile/assets/fonts/OFL.txt) |
Each package's full licence is in its own folder after flutter pub get / npm install. The photos in the online demo are not included in the download; add your own photos of your salon and work.