AlpacApps is an open-source property management platform. Set up a super low cost do-it-all system from scratch — messaging, marketing, tenant management, and finance. You just need to set up the required (mostly free) accounts, then tell Claude Code what you have, where it is, and what you ideally want. Then watch the AI magic transpire.
Starting from: $0/month infrastructure • ~$10/month for Claude Code (API + Sonnet)
The philosophy: You set up the (mostly free) vendor accounts and gather credentials. Then tell Claude Code what you have and what you want — it handles all the terminal work: database migrations, CLI setup, edge function deployment, git pushes.
What can you build with this?
A full-stack business platform. The layers build on each other — pick what you need.
Key principle: No backend server. All application logic runs client-side in the browser. Supabase provides the database, authentication, and serverless functions. For file storage, you can use Supabase Storage (1 GB free) or Cloudflare R2 (10 GB free, zero egress fees). GitHub Pages serves static files for free.
CSS: Tailwind CSS v4 is available alongside existing CSS custom properties. The Tailwind source (styles/tailwind.css) defines AAP design tokens (colors, fonts, shadows, radii) and is compiled to styles/tailwind.out.css by GitHub Actions CI on every push. Use npm run css:build locally or npm run css:watch for development. All pages load both site.css (custom properties) and tailwind.out.css (utility classes).
Select what you need
Core services are pre-selected. Toggle optional ones on or off.
How much will you build?
This mainly affects your Claude Code plan and usage-based services.
Estimated annual cost$0
1. GitHub + Starter Template Free
First, get a GitHub account and create your project from the starter template. Everything here is done in your browser — no terminal needed.
Create a GitHub account
You'll need a free GitHub account to host your site and store your code. If you already have one, skip to the next step.
Click the green "Use this template" button → "Create a new repository"
Enter your project name as the Repository name (e.g., my-salon-app)
Make sure Public is selected (required for free GitHub Pages hosting)
Click "Create repository" — GitHub copies all the template files into your own repo
Turn on GitHub Pages
In your new repo, go to Settings (gear icon near the top)
Click Pages in the left sidebar
Under "Source," select Deploy from a branch → main → / (root) → Save
Wait 1–2 minutes. Your site is live at https://<username>.github.io/<project-name>/
Download the project to your computer
You need a copy of your project on your computer. This takes two steps:
a) Open a terminal
Mac: Press Cmd + Space, type Terminal, press Enter
Windows: Press Win + R, type cmd, press Enter
b) Paste this command into your terminal
Click Copy below, then paste into your terminal (Ctrl+V on Windows, Cmd+V on Mac) and press Enter:
git clone https://github.com/USERNAME/my-salon-app.git
cd my-salon-app
This downloads your project files into a folder on your computer. You'll point Claude Code at this folder in the next step.
Windows: Git not installed?
If you see "git is not recognized," download Git from git-scm.com, install it (use all defaults), then close and reopen your terminal and try again. Mac already has Git built in.
Connect Git to your GitHub account
Before Claude Code can push code to your repository, Git needs to know your GitHub credentials. The easiest way is GitHub CLI, which handles this through your browser — no passwords or tokens to manage.
a) Install GitHub CLI
Mac: Paste into Terminal: brew install gh Don’t have Homebrew? Paste this first: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Windows: Paste into your terminal: winget install --id GitHub.cli Then close and reopen your terminal.
b) Log in to GitHub through your browser
Paste this into your terminal and press Enter:
gh auth login
It will ask a few questions — pick these answers:
Where do you use GitHub? → GitHub.com
Preferred protocol? → HTTPS
Authenticate Git with GitHub credentials? → Yes
How would you like to authenticate? → Login with a web browser
It will show a one-time code and open your browser. Paste the code, click Authorize, and you’re done.
How to verify it worked:
Run gh auth status in your terminal. You should see your GitHub username and “Logged in to github.com.”
Claude Code is your AI developer. Once it's set up, you won't need to use the terminal again — but if Claude asks you to do something in the terminal or bash something, just ask it to do it by itself. Claude can handle everything from here, but sometimes forgets.
Recommended: Claude Pro ($20/month) or higher
The free tier works, but you'll hit usage limits quickly when setting up infrastructure. The Pro plan ($20/month) gives you significantly more usage. For intensive development, consider Max ($100) or Max+ ($200).
Open the app and click the Code tab in the top right to open Claude Code
Point it at the project folder you cloned in Step 1
Stuck on any step? Take a screenshot, paste it into the Claude desktop app, and ask: “What do I do?” — Claude can read screenshots and will walk you through it.
Already comfortable with the terminal?
You can also install Claude Code as a standalone CLI: npm install -g @anthropic-ai/claude-code, then run claude from your project directory. Same features, same skills — these instructions just assume the desktop app.
Run the setup wizard
Once Claude Code is open in your project folder, type:
/setup-alpacapps-infra
Claude will ask you what you're building, which services you need, then walk you through the entire setup — creating your database, deploying edge functions, configuring webhooks, and building your CLAUDE.md (checked into repo) and CLAUDE.local.md (gitignored credentials). You don't need to read the rest of this guide unless you want to understand what's happening under the hood.
Slash command not working?
The /setup-alpacapps-infra skill requires the Max plan ($100/month) or higher. If you're on the Pro plan, type this instead:
Read .claude/skills/setup-alpacapps-infra/SKILL.md and follow those instructions to set up my project
This does the exact same thing — Claude reads the setup guide and walks you through it step by step.
What the rest of this guide is for
The sections below explain each service in detail. For each one, you:
You create the account and copy credentials (in your browser)
You give Claude the credentials (just paste them into the chat)
Claude handles everything else — updates your config files, installs CLIs, creates tables, writes edge functions, deploys, and pushes code
You never need to edit files yourself. Just tell Claude what you want in plain English.
"Set up Supabase. Here are my credentials: project ref is abc123, anon key is eyJ..."
installs Supabase CLI, links project, updates CLAUDE.md + CLAUDE.local.md, creates tables with RLS, creates storage buckets, commits and pushes
3. Supabase Free
Database, storage, auth, and serverless edge functions — all in one.
If prompted to create an organization first, give it any name (e.g. “Personal”) and select the Free plan
Set a database password — save this securely (you’ll paste it to Claude)
Choose a region close to your users, click Create new project, and wait 1-2 minutes
Where to find your project ref: After your project is created, look at the URL in your browser’s address bar. It will look like: https://supabase.com/dashboard/project/abcdefghijk/...
The highlighted part (a random string of letters and numbers) is your project ref. You can also find it on your project’s home page under Project Settings → General.
Paste your project ref here — the links below will update so you can click straight to the right pages:
## Supabase Details
- Project ID: `YOUR_PROJECT_REF`
- URL: `https://YOUR_PROJECT_REF.supabase.co`
- Anon key: `your-anon-key-here`
- Database password: `your-db-password`
### Direct Database Access (for Claude)
Session pooler connection string (paste yours from Database settings):
psql "postgres://postgres.YOUR_PROJECT_REF:YOUR_URL_ENCODED_PASSWORD@aws-0-REGION.pooler.supabase.com:5432/postgres" -c "SQL HERE"
URL-encode special characters in password (! = %21, @ = %40).
### Supabase CLI Access (for Claude)
If CLI not installed: npm install -g supabase && supabase login && supabase link --project-ref YOUR_PROJECT_REF
supabase functions deploy <function-name>
supabase secrets set KEY=value
For Claude: Run these directly. Don't ask the user.
Then tell Claude
"Set up my Supabase project. Install the CLI, link it, create the core database tables for [your domain], enable RLS on all tables, and create storage buckets for photos and documents."Claude will install the CLI, login, link, create shared/supabase.js, run SQL for tables + RLS + storage policies, commit, and push.
4. Google Sign-In (Optional) Free
If your app needs user login (admin dashboard, customer accounts, etc.), the easiest option is “Sign in with Google.” Supabase has built-in support — you just need to create a Google Cloud project and get OAuth credentials.
Same Google Cloud project: This step and Step 10 (Google Gemini) both use Google Cloud. Create one project and use it for both — no need to set up two.
Choose External (unless you’re on Google Workspace and only want internal users) → click Create
Fill in the required fields:
App name: your app’s name (what users see)
User support email: your email
Developer contact email: your email
Click Save and Continue through the Scopes, Test Users, and Summary steps (defaults are fine)
Publishing status: Your app starts in “Testing” mode, which means only test users you add can sign in. To let anyone sign in, click Publish App on the consent screen page. Google may ask you to verify your app if you use sensitive scopes, but basic sign-in (email/profile) doesn’t require verification.
### Authentication (Google OAuth via Supabase)
- Google Client ID: `your-client-id.apps.googleusercontent.com`
- Auth is handled by Supabase Auth (no edge function needed)
- Redirect URI: `https://YOUR_PROJECT_REF.supabase.co/auth/v1/callback`
- Sign-in method: supabase.auth.signInWithOAuth({ provider: 'google' })
Then tell Claude
"Set up Google Sign-In. Create a login page with a 'Sign in with Google' button using Supabase Auth, and add an auth check to the admin pages so only authenticated users can access them."Claude will create shared/auth.js, add login/logout UI, set up auth guards on admin pages, commit, and push.
### Email (Resend)
- API key: `re_your_key_here` (store as Supabase secret: RESEND_API_KEY)
- From address: notifications@yourdomain.com (or onboarding@resend.dev)
Then tell Claude
"Set up email sending with Resend. Store the API key as a Supabase secret and create a send-email edge function."Claude will run supabase secrets set, create the edge function, deploy it, commit, and push.
10DLC Registration (Required for US) — do this now, it takes time.
Go to Messaging → Compliance. Create a Brand (Sole Proprietor), then a Campaign (use case: business notifications). Assign your number. Approval can take days to weeks — SMS won't work without it.
"Set up Telnyx SMS. Create the telnyx_config and sms_messages tables, write the send-sms and telnyx-webhook edge functions, and deploy with --no-verify-jwt."Claude will create tables, insert config, write both edge functions, deploy, create shared/sms-service.js, commit, and push.
Access Token — Sandbox for testing, Production for real charges
Location ID — Square Dashboard → Locations
Give Claude these credentials
### Payments (Square)
- Application ID: `sq0idp-your-app-id`
- Sandbox Access Token: `your-sandbox-token`
- Location ID: `your-location-id`
- Environment: sandbox (switch to production when ready)
- Config stored in `square_config` table
- Edge function: `process-square-payment`
- Sandbox SDK: https://sandbox.web.squarecdn.com/v1/square.js
- Production SDK: https://web.squarecdn.com/v1/square.js
Then tell Claude
"Set up Square payment processing. Create the config and payments tables, a process-square-payment edge function, and a client-side square-service.js module."Claude will create tables, insert config, write the edge function + client module, deploy, commit, and push.
8. Stripe (Payments) Pay-as-you-go
Stripe handles ACH bank transfers (0.8% capped at $5), card payments (2.9% + 30¢), and outbound payouts to associates via Stripe Connect ($0.25/payout).
"Set up Stripe payment processing. Create the stripe_config and stripe_payments tables, a process-stripe-payment edge function (PaymentIntent creation), a stripe-webhook edge function (HMAC-verified), and a client-side stripe-service.js module. Support ACH bank transfers and card payments."Claude will create tables, insert config, write and deploy both edge functions, create the client module, commit, and push.
### E-Signatures (SignWell)
- API key: `your-signwell-api-key`
- API base: https://www.signwell.com/api/v1
- Auth: X-Api-Key header
- Config stored in `signwell_config` table
- Deploy webhook with `--no-verify-jwt`
Then tell Claude
"Set up SignWell for e-signatures. Create the config table, a webhook edge function, and client-side signwell-service.js and pdf-service.js modules."Claude will create the table, insert config, write and deploy the webhook, create client modules, commit, and push.
10. Google Gemini (AI Matching) Free
Optional. Useful for fuzzy matching (e.g., matching bank transaction sender names to tenants).
Already set up Google Sign-In? You already have a Google Cloud project from Step 4. Use the same project — just grab a Gemini API key below.
### AI Matching (Google Gemini)
- API key: `your-gemini-key` (store as Supabase secret: GEMINI_API_KEY)
Then tell Claude
"Store my Gemini API key as a Supabase secret."Claude will run: supabase secrets set GEMINI_API_KEY=your_key_here
11. Cloudflare R2 (Object Storage) Free
Optional. S3-compatible object storage with 10 GB free and zero egress fees. Great for documents, manuals, PDFs, and media that don’t need Supabase Storage’s RLS.
Go to R2 Object Storage in the left sidebar → Create bucket
Name your bucket (e.g., your project name), choose a region, click Create bucket
In bucket Settings, enable Public Development URL (allows public read access via a pub-*.r2.dev URL)
Go to R2 Object Storage → Manage R2 API Tokens → Create API token
Give it Object Read & Write permission, apply to your bucket, create the token
Copy the Access Key ID and Secret Access Key (shown only once!)
Give Claude these credentials
### Cloudflare R2
- Account ID: `your-cloudflare-account-id` (from the R2 dashboard URL or Overview page)
- Bucket name: `your-bucket-name`
- Public URL: `https://pub-xxxx.r2.dev` (from bucket Settings → Public Development URL)
- Access Key ID: `your-access-key`
- Secret Access Key: `your-secret-key`
Then tell Claude
"Store my R2 credentials as Supabase secrets and create the R2 upload helper and config table."Claude will:
supabase secrets set R2_ACCOUNT_ID=... R2_ACCESS_KEY_ID=... R2_SECRET_ACCESS_KEY=... R2_BUCKET_NAME=... R2_PUBLIC_URL=...,
create r2_config table, create supabase/functions/_shared/r2-upload.ts (S3-compatible upload with AWS Sig V4)
12. Background Workers (Optional)
Some features need always-on processes that can’t run in the browser or in Supabase Edge Functions. These run on a cloud VM (any provider: DigitalOcean, Google Cloud, Hetzner, etc.).
What runs here
Automated bug fixer — polls for bug reports, runs Claude Code to fix them, commits, merges
Feature builder — picks up feature requests, implements them autonomously
Device pollers — Tesla vehicles (every 5 min), LG washer/dryer (every 30s)
Camera PTZ proxy — relays pan/tilt/zoom commands to cameras via home server
Reverse proxy — Caddy for camera HLS streams, nginx for Sonos API relay
Typical sizing
Tier
Spec
Cost
Good for
Basic
2 vCPU, 2 GB RAM
~$12/mo
A few lightweight pollers + image gen
Full
2 vCPU, 4 GB RAM
~$24–32/mo
All workers including Claude Code automation (bug fixer, feature builder)
You do
Spin up an Ubuntu VM on any cloud provider
Install Node.js 18+, Tailscale (if you have a home server), and Caddy/nginx as needed
Clone your repo and set up each worker as a systemd service
Workers query Supabase directly using the REST API or service role key
Then tell Claude
“Set up the background workers on my server at [IP]. Create systemd services for the bug fixer, device pollers, and image gen worker. Add SSH access details to CLAUDE.local.md.”
13. Custom Domain (Optional)
No rush on this step. Your site is already live at https://<username>.github.io/<project-name>/ and that works great while you’re building. Come back to this when you’re ready to share your app with the world under your own brand name.
1. Buy a domain
If you don’t already own one, buy a domain from any registrar. Here are popular options:
Under Custom domain, type your domain (e.g., myapp.com) and click Save
GitHub will show a message that a DNS check is pending — that’s normal until you complete step 3
3. Point your domain to GitHub Pages (DNS settings)
This is the key step: you need to tell your domain registrar to send traffic to GitHub’s servers. The exact screens look a little different at each registrar, but you’re doing the same thing everywhere.
Find your DNS settings:
Namecheap: Dashboard → click Manage next to your domain → Advanced DNS tab
Cloudflare: Select your domain → DNS → Records
Squarespace Domains: Domains panel → click your domain → DNS → DNS Settings
Add these records:
Type
Name / Host
Value / Points to
A
@
185.199.108.153
A
@
185.199.109.153
A
@
185.199.110.153
A
@
185.199.111.153
CNAME
www
<username>.github.io
What do these mean?
The four A records tell browsers “when someone types myapp.com, go to GitHub’s servers.”
The CNAME record makes www.myapp.com work too, by pointing it to your GitHub Pages address.
The @ symbol means “the root domain” (i.e., myapp.com with nothing in front of it).
If your registrar already has default records (like parking page records), delete those first, then add the ones above.
4. Turn on HTTPS
Wait 5–30 minutes for DNS changes to propagate (sometimes up to 24 hours)
Go back to your repo’s Settings → Pages
The DNS check should now show a green checkmark
Check the box for Enforce HTTPS — GitHub provides a free SSL certificate automatically
How do I know it’s working?
Visit your domain in a browser. If you see your site, you’re done. If not:
Double-check that you entered the A record IPs exactly as shown above
Make sure you deleted any old/default DNS records that might conflict
DNS changes can take up to 24 hours to fully propagate — wait and try again
Use dnschecker.org to verify your records are visible worldwide
14. CLAUDE.md Templates
Claude Code uses two files for project context: CLAUDE.md (checked into the repo) for shareable project context, and CLAUDE.local.md (gitignored) for credentials and operator directives. Enter your project name and download both.
CLAUDE.md (checked in) includes:
Project overview and tech stack
Architecture and key files
Database schema and common patterns
Deployment workflow (push to main = live)
External systems overview (no credentials)
Coding conventions
CLAUDE.local.md (gitignored) includes:
Operator directives (push immediately, direct DB access, version bumping)
Supabase project ref, URL, psql connection string
Live URLs (GitHub Pages)
External service credentials: Resend, Telnyx, Square, SignWell
Server access (cloud VM SSH, worker configuration)
Tip: The setup wizard (Step 2) builds both files for you automatically as it sets up each service. Don't forget to add CLAUDE.local.md to your .gitignore.
15. Day-One Checklist
You do (in your browser)
Core Stack — Free:
Create GitHub account and repository
Enable GitHub Pages on the repo
Create Supabase account and project
Copy: project ref, anon key, DB password, and session pooler connection string
User Login — Free (Google OAuth):
Create Google Cloud project
Set up OAuth consent screen (publish when ready)
Create OAuth client ID (Web application)
Add Supabase callback URL as authorized redirect URI
Enable Google provider in Supabase Auth settings
Copy: Client ID, Client Secret
Email — Free (Resend):
Create Resend account
Verify your domain (or use onboarding@resend.dev)
Copy: API key
SMS — Pay-as-you-go (Telnyx):
Create Telnyx account, add payment method
Buy a phone number (~$1/month)
Create Messaging Profile, assign number, set webhook URL
Register for 10DLC (mandatory for US — do early, approval takes time)
Copy: API key, Messaging Profile ID, phone number
Payments — Free until you process (Square):
Create Square developer account and application
Copy: Application ID, sandbox access token, location ID
Once you've given Claude your credentials, tell it to set everything up. You can either use the setup skill or paste this prompt:
"I've set up all my vendor accounts. Please:
Set up the project structure and push to GitHub
Install and link the Supabase CLI
Create the database tables I need for [your domain]
Set up email sending with Resend
Set up SMS with Telnyx
Set up payment processing with Square
Set up e-signatures with SignWell
Deploy all edge functions and store API keys as secrets"
Or just type /setup-alpacapps-infra in Claude Code — the skill walks through the same setup interactively, asking what services you need as it goes.
Claude handles everything from there — creating tables, writing edge functions, deploying, setting secrets, committing, and pushing. You never need to touch the terminal yourself.
16. Mobile App (iOS & Android) Free to develop
The mobile app wraps the same web codebase in a native shell using Capacitor 8. Residents get a native app experience (home screen icon, push notifications, no browser chrome) while you maintain a single codebase.
How It Works
Web App (HTML/CSS/JS) → Capacitor WebView → Native iOS / Android App
↓
Same Supabase backend as web
Capacitor takes your existing web code, loads it inside a native WebView, and gives you access to native device APIs (push notifications, camera, status bar) through JavaScript plugins. There's no need to learn Swift or Kotlin — your web skills are all you need.
Tech Stack
Layer
Technology
Notes
Native shell
Capacitor 8
Wraps web content in native WebView
UI
Vanilla HTML/CSS/JS
Dark theme, bottom tab bar, no framework needed
Auth
Supabase Auth
Inline email/password + Google OAuth
Data
Supabase JS SDK
Same client as web app
OTA Updates
@capgo/capacitor-updater
Push code updates without App Store review
Push Notifications
@capacitor/push-notifications
FCM (Android) + APNs (iOS)
Development Tools
Platform
IDE
Requirements
iOS
Xcode 15+
macOS only, free from App Store. Apple Developer account ($99/year) for App Store distribution
Android
Android Studio
macOS, Windows, or Linux. Google Play Console ($25 one-time) for Play Store distribution
On the Phone
Platform
Runtime
Min Version
iPhone / iPad
WKWebView (Safari engine)
iOS 16+
Android
Android WebView (Chromium engine)
Android 6.0+ (API 23)
On iOS, the app runs inside Apple's WKWebView (same engine as Safari). On Android, it uses the system WebView powered by Chromium. Both provide near-native performance for web content.
Build & Deploy
Claude does this
Claude Code handles the build process. The workflow is:
Build web assets — A script (copy-web.js) copies your web files into the mobile project, injects capacitor.js, and patches any redirect-based navigation
Sync to native — npm run sync from the mobile/ directory copies web assets into the iOS and Android native projects
Run on device — Open Xcode (iOS) or Android Studio (Android) and press Play
# From the mobile/ directory:
npm run sync # Build + sync to both platforms
npm run open:ios # Open Xcode — press Play to run
npm run open:android # Open Android Studio — press Run
Key Design Decisions
Single codebase — Web and mobile share the same data services (shared/services/). Write once, runs on web + iOS + Android
No framework required — Vanilla JS with CSS-based tab switching. No React Native, no Flutter, no Swift/Kotlin to learn
Lazy-loaded tabs — Each tab module loads on first visit via dynamic import(), keeping startup fast
OTA updates — After the initial App Store submission, code changes (HTML/CSS/JS) can be pushed live instantly via Capgo — no App Store review wait
Inline login — Capacitor WebView can't handle multi-page redirects, so the mobile app uses an inline login form instead of a separate login page