Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"configurations": [

{
"name": "ShoeInn API (uvicorn)",
"name": "Skruhb API (uvicorn)",
"type": "python",
"request": "launch",
"module": "uvicorn",
Expand Down
40 changes: 23 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# ShoeInn
<img src="brand/svg/skruhb-logo-deep.svg" alt="Skruhb" width="246" />

Sneaker care scheduling, provider dispatch, notifications, and payment workflow demo.
# Skruhb

Operations software for cleaning and care businesses, including booking, provider dispatch, notifications, and payment workflows.

## Brand assets

The approved concept 45 compact SK ligature is the product identity. Exact Figma source exports are preserved in `brand/source`; cleaned, editable production masters for the deep blue-green, white, black, symbol-only, and horizontal lockups live in `brand/svg`. Platform raster derivatives live with the applications that consume them.

This repository is a small monorepo. Run each app from its own folder:

Expand Down Expand Up @@ -121,7 +127,7 @@ Useful options:
- `-SkipInstall` to skip `pip install`
- `-PaymentMode mock` or `-PaymentMode service`
- `-PaymentServiceBaseUrl "http://localhost:8001"` for service payment mode
- `-MobileRedirectBase "exp://<YOUR-LAN-IP>:8081/--"` for Expo Go returns, or `shoeinn://app` for a dev build
- `-MobileRedirectBase "exp://<YOUR-LAN-IP>:8081/--"` for Expo Go returns, or `skruhb://app` for a dev build
- `-Port 8000` to override the API port

If `apps/api/.env` already exists, the scripts preserve existing payment settings unless you explicitly pass `-PaymentMode`, `-PaymentServiceBaseUrl`, or `-MobileRedirectBase`.
Expand Down Expand Up @@ -244,20 +250,20 @@ Invoke-RestMethod -Method Post "http://localhost:8000/dev/seed?reset=true&demo_m

Default demo logins all use `Password1!`:

- Global admin: `admin@shoeinn.com`
- Customer: `customer@shoeinn.com`
- Pelham owner: `pelham.admin@shoeinn.com`
- Pelham providers: `pelham.driver1@shoeinn.com`, `pelham.driver2@shoeinn.com`
- Helena owner: `helena.admin@shoeinn.com`
- Helena provider: `helena.driver@shoeinn.com`
- Alabaster owner: `alabaster.admin@shoeinn.com`
- Alabaster provider: `alabaster.driver@shoeinn.com`
- Global admin: `admin@skruhb.com`
- Customer: `customer@skruhb.com`
- Pelham owner: `pelham.admin@skruhb.com`
- Pelham providers: `pelham.driver1@skruhb.com`, `pelham.driver2@skruhb.com`
- Helena owner: `helena.admin@skruhb.com`
- Helena provider: `helena.driver@skruhb.com`
- Alabaster owner: `alabaster.admin@skruhb.com`
- Alabaster provider: `alabaster.driver@skruhb.com`

Mt. Juliet quick-demo logins use `Password123!`:

- Customer: `customer.mtjuliet@shoeinn.demo`
- Provider: `provider.mtjuliet@shoeinn.demo`
- Company admin: `admin.mtjuliet@shoeinn.demo`
- Customer: `customer.mtjuliet@skruhb.demo`
- Provider: `provider.mtjuliet@skruhb.demo`
- Company admin: `admin.mtjuliet@skruhb.demo`

The seed response also returns the current login list and generated company IDs.

Expand Down Expand Up @@ -313,7 +319,7 @@ $env:EXPO_PUBLIC_GOOGLE_MAPS_API_KEY="your-google-directions-api-key"
$env:EXPO_PUBLIC_MOBILE_REDIRECT_BASE="exp://<YOUR-LAN-IP>:8081/--"
```

Use `EXPO_PUBLIC_MOBILE_REDIRECT_BASE="shoeinn://app"` for a dev build or standalone app that supports the custom scheme.
Use `EXPO_PUBLIC_MOBILE_REDIRECT_BASE="skruhb://app"` for a dev build or standalone app that supports the custom scheme.

## Optional Payment Service

Expand Down Expand Up @@ -346,7 +352,7 @@ Then set these API values in `apps/api/.env`:
```env
PAYMENT_MODE=service
PAYMENT_SERVICE_BASE_URL=http://localhost:8001
PAYMENT_MOBILE_REDIRECT_BASE=shoeinn://app
PAYMENT_MOBILE_REDIRECT_BASE=skruhb://app
```

For Expo Go return-flow testing, use an explicit Expo URL instead:
Expand Down Expand Up @@ -496,5 +502,5 @@ Example login:
```powershell
Invoke-RestMethod -Method Post "http://localhost:8000/auth/login" `
-ContentType "application/json" `
-Body '{"email":"customer@shoeinn.com","password":"Password1!"}'
-Body '{"email":"customer@skruhb.com","password":"Password1!"}'
```
2 changes: 1 addition & 1 deletion apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PAYMENT_MODE=mock
PAYMENT_SERVICE_BASE_URL=
# Stripe should redirect to the mobile/frontend experience, not the API host.
# Development/dev client example:
# PAYMENT_MOBILE_REDIRECT_BASE=shoeinn://app
# PAYMENT_MOBILE_REDIRECT_BASE=skruhb://app
# Expo Go example:
# PAYMENT_MOBILE_REDIRECT_BASE=exp://192.168.1.29:8081/--
PAYMENT_MOBILE_REDIRECT_BASE=
4 changes: 2 additions & 2 deletions apps/api/.env.staging.example
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ PAYMENT_CHECKOUT_CANCEL_URL=https://api.your-domain.com/payments/return/cancel
# App return URL after the browser success/cancel page.
# For installed preview/dev builds, use your app scheme.
# For Expo Go local testing, this may be exp://<LAN-IP>:8081/--/payment-return
PAYMENT_RETURN_APP_URL=shoeinn://payment-return
PAYMENT_RETURN_APP_URL=skruhb://payment-return

# Legacy/optional redirect base. Keep blank unless existing code still reads it.
PAYMENT_MOBILE_REDIRECT_BASE=

# Demo/test seed routes are still available in staging v2.
# Protect them at the deployment layer or add an explicit seed secret before external demos.
# Protect them at the deployment layer or add an explicit seed secret before external demos.
6 changes: 3 additions & 3 deletions apps/api/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ShoeInn API
# Skruhb API

FastAPI backend for authentication, companies, premium care services, booking holds, appointments, provider/company operations, live updates, notifications, payment reconciliation, and demo seeding.

Expand Down Expand Up @@ -111,7 +111,7 @@ Example login:
```powershell
Invoke-RestMethod -Method Post "http://localhost:8000/auth/login" `
-ContentType "application/json" `
-Body '{"email":"customer@shoeinn.com","password":"Password1!"}'
-Body '{"email":"customer@skruhb.com","password":"Password1!"}'
```

## Payment Modes
Expand All @@ -129,7 +129,7 @@ Use service mode only when `apps/payment` is running:
```env
PAYMENT_MODE=service
PAYMENT_SERVICE_BASE_URL=http://localhost:8001
PAYMENT_MOBILE_REDIRECT_BASE=shoeinn://app
PAYMENT_MOBILE_REDIRECT_BASE=skruhb://app
```

For Expo Go return-flow testing:
Expand Down
2 changes: 1 addition & 1 deletion apps/api/app/core/brand.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
APP_NAME = "ShoeInn"
APP_NAME = "Skruhb"
CARE_MARKETPLACE_POSITIONING = "Premium care, pickup, and delivery from trusted local teams."
2 changes: 1 addition & 1 deletion apps/api/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
force=True, # <- IMPORTANT: overrides existing handlers/config
)

app = FastAPI(title="ShoeInn API")
app = FastAPI(title="Skruhb API")

static_dir = Path(__file__).resolve().parent / "static"
static_dir.mkdir(parents=True, exist_ok=True)
Expand Down
4 changes: 2 additions & 2 deletions apps/api/app/routers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ def _create_demo_user(db: Session, *, email: str, role: str, full_name: str, pas

def _seed_demo_data(db: Session) -> dict[str, object]:
now = datetime.now(timezone.utc)
company_one = Company(name="Downtown ShoeInn", city="San Francisco", state="CA")
company_two = Company(name="Uptown ShoeInn", city="New York", state="NY")
company_one = Company(name="Downtown Skruhb", city="San Francisco", state="CA")
company_two = Company(name="Uptown Skruhb", city="New York", state="NY")
db.add_all([company_one, company_two])
db.flush()

Expand Down
42 changes: 21 additions & 21 deletions apps/api/app/routers/dev_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class SeedMarket(TypedDict):
},
],
"customer": {
"email": "customer@shoeinn.com",
"email": "customer@skruhb.com",
"role": "customer",
"full_name": "Jordan Demo Customer",
},
Expand All @@ -150,18 +150,18 @@ class SeedMarket(TypedDict):
{
"name": "Pelham Pickup & Press",
"admin": {
"email": "pelham.admin@shoeinn.com",
"email": "pelham.admin@skruhb.com",
"role": "company_admin",
"full_name": "Pelham Owner Demo",
},
"providers": [
{
"email": "pelham.driver1@shoeinn.com",
"email": "pelham.driver1@skruhb.com",
"role": "provider",
"full_name": "Mason Route Lead",
},
{
"email": "pelham.driver2@shoeinn.com",
"email": "pelham.driver2@skruhb.com",
"role": "provider",
"full_name": "Ava Delivery Lead",
},
Expand Down Expand Up @@ -193,13 +193,13 @@ class SeedMarket(TypedDict):
{
"name": "Helena Shoe & Dry Care",
"admin": {
"email": "helena.admin@shoeinn.com",
"email": "helena.admin@skruhb.com",
"role": "company_admin",
"full_name": "Helena Owner Demo",
},
"providers": [
{
"email": "helena.driver@shoeinn.com",
"email": "helena.driver@skruhb.com",
"role": "provider",
"full_name": "Noah Helena Driver",
},
Expand Down Expand Up @@ -231,13 +231,13 @@ class SeedMarket(TypedDict):
{
"name": "Alabaster Clean Run",
"admin": {
"email": "alabaster.admin@shoeinn.com",
"email": "alabaster.admin@skruhb.com",
"role": "company_admin",
"full_name": "Alabaster Owner Demo",
},
"providers": [
{
"email": "alabaster.driver@shoeinn.com",
"email": "alabaster.driver@skruhb.com",
"role": "provider",
"full_name": "Liam Alabaster Driver",
},
Expand Down Expand Up @@ -343,23 +343,23 @@ class SeedMarket(TypedDict):
},
],
"customer": {
"email": "mtjuliet.customer@shoeinn.com",
"email": "mtjuliet.customer@skruhb.com",
"role": "customer",
"full_name": "Jordan Demo Customer",
},
"quick_demo_users": {
"customer": {
"email": "customer.mtjuliet@shoeinn.demo",
"email": "customer.mtjuliet@skruhb.demo",
"role": "customer",
"full_name": "Avery Mt. Juliet Customer",
},
"provider": {
"email": "provider.mtjuliet@shoeinn.demo",
"email": "provider.mtjuliet@skruhb.demo",
"role": "provider",
"full_name": "Cameron Mt. Juliet Provider",
},
"company_admin": {
"email": "admin.mtjuliet@shoeinn.demo",
"email": "admin.mtjuliet@skruhb.demo",
"role": "company_admin",
"full_name": "Reese Mt. Juliet Company Admin",
},
Expand All @@ -368,18 +368,18 @@ class SeedMarket(TypedDict):
{
"name": "Mt. Juliet Pickup & Press",
"admin": {
"email": "mtjuliet.admin@shoeinn.com",
"email": "mtjuliet.admin@skruhb.com",
"role": "company_admin",
"full_name": "Mt. Juliet Owner Demo",
},
"providers": [
{
"email": "mtjuliet.driver1@shoeinn.com",
"email": "mtjuliet.driver1@skruhb.com",
"role": "provider",
"full_name": "Harper Route Lead",
},
{
"email": "mtjuliet.driver2@shoeinn.com",
"email": "mtjuliet.driver2@skruhb.com",
"role": "provider",
"full_name": "Ethan Delivery Lead",
},
Expand Down Expand Up @@ -411,13 +411,13 @@ class SeedMarket(TypedDict):
{
"name": "Providence Shoe & Dry Care",
"admin": {
"email": "providence.admin@shoeinn.com",
"email": "providence.admin@skruhb.com",
"role": "company_admin",
"full_name": "Providence Owner Demo",
},
"providers": [
{
"email": "providence.driver@shoeinn.com",
"email": "providence.driver@skruhb.com",
"role": "provider",
"full_name": "Lucas Providence Driver",
},
Expand Down Expand Up @@ -449,13 +449,13 @@ class SeedMarket(TypedDict):
{
"name": "Golden Bear Clean Run",
"admin": {
"email": "goldenbear.admin@shoeinn.com",
"email": "goldenbear.admin@skruhb.com",
"role": "company_admin",
"full_name": "Golden Bear Owner Demo",
},
"providers": [
{
"email": "goldenbear.driver@shoeinn.com",
"email": "goldenbear.driver@skruhb.com",
"role": "provider",
"full_name": "Mia Golden Bear Driver",
},
Expand Down Expand Up @@ -505,7 +505,7 @@ def _all_demo_company_names() -> set[str]:


def _all_demo_emails() -> set[str]:
emails = {"admin@shoeinn.com"}
emails = {"admin@skruhb.com"}
for demo_market in DEMO_MARKETS.values():
emails.add(demo_market["customer"]["email"])
emails.update(user["email"] for user in demo_market["quick_demo_users"].values())
Expand Down Expand Up @@ -739,7 +739,7 @@ def get_or_create_user(email: str, role: str, full_name: str, *, password: str =
created["users"] += 1
return user

global_admin = get_or_create_user("admin@shoeinn.com", "admin", "ShoeInn Global Admin")
global_admin = get_or_create_user("admin@skruhb.com", "admin", "Skruhb Global Admin")
customer = get_or_create_user(
market["customer"]["email"],
market["customer"]["role"],
Expand Down
8 changes: 8 additions & 0 deletions apps/api/app/routers/payment_return.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ def _payment_return_page(*, title: str, body: str, app_url: str | None) -> HTMLR
padding: 32px 24px;
box-shadow: 0 20px 40px rgba(17, 24, 39, 0.08);
}}
.brand {{
display: block;
width: 190px;
max-width: 60%;
height: auto;
margin: 0 0 28px;
}}
h1 {{
margin: 0 0 12px;
font-size: 28px;
Expand All @@ -102,6 +109,7 @@ def _payment_return_page(*, title: str, body: str, app_url: str | None) -> HTMLR
</head>
<body>
<main>
<img class="brand" src="/static/skruhb-logo-deep.svg" alt="{APP_NAME}" />
<h1>{title}</h1>
<p>{body}</p>
{open_app_link}
Expand Down
2 changes: 1 addition & 1 deletion apps/api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "shoeinn-api"
name = "skruhb-api"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion apps/api/scripts/seed_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def seed_services(session: Session) -> int:

company = session.execute(select(Company).limit(1)).scalar_one_or_none()
if company is None:
company = Company(name="ShoeInn", city="Anywhere", state="CA")
company = Company(name="Skruhb", city="Anywhere", state="CA")
session.add(company)
session.flush()

Expand Down
Loading
Loading