Skip to content
Open
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
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,12 @@ PUBLIC_DETOX_SINGLE_SESSION_PRODUCT_ID=BSRNUARXBO7LYS7GDGUJYRP4
PUBLIC_DETOX_SINGLE_SESSION_VARIATION_ID=EDZDJOKHPNW462I7AXSKKJ6T
PUBLIC_DETOX_SINGLE_SESSION_PAYMENT_LINK=
PUBLIC_SQUARE_BOOKING_URL=https://deeper-than-skin-llc.square.site/appointments
PUBLIC_MARKET_PULSE_ENDPOINT=https://smashpro.app/api/v1/index.php?path=public/commerce/market-pulse&app_slug=deeper-than-skin
MARKET_CATEGORY_ID=
FEATURED_MARKET_CATEGORY_ID=
LAKE_CAROLINA_MARKET_CATEGORY_ID=
SODA_CITY_MARKET_CATEGORY_ID=
MARKET_CATEGORY_NAME=Market
FEATURED_MARKET_CATEGORY_NAME=Featured Drinks
PUBLIC_MARKET_REACTION_VIDEO_1=
PUBLIC_MARKET_REACTION_VIDEO_2=
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ api/bootstrap/*.local.php
.env
.env.*
!/.env.example
.env.ftp
.vscode/sftp.json
.vscode/settings.json
api/v1/routes/_square.config.php
Expand Down
28 changes: 0 additions & 28 deletions .vscode/sftp.example.json

This file was deleted.

68 changes: 63 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,69 @@ Updates go live automatically on commit.

### API Deploy Workflow

- Edit PHP API routes only inside `api/v1/routes/`
- Saving those files uploads them to `/public_html/smashpro.app/api/v1/routes/`
- Frontend files do not auto-deploy through FTP
- Frontend still deploys through normal Git/build flow
- Keep `.vscode/sftp.json` local only
FileZilla remains a safe manual backup, but API deploys can be run from scripts.
Credentials are loaded from a local `.env.ftp` file and must never be committed.

1. Install `lftp`.
- Git Bash/MSYS2: install the `lftp` package through MSYS2.
- WSL Ubuntu: `sudo apt update && sudo apt install lftp`.
- macOS: `brew install lftp`.
- On this Windows workstation, MSYS2 is installed at `C:\msys64` and the npm
scripts call `C:\msys64\usr\bin\bash.exe` directly.

2. Create local FTP credentials in `.env.ftp`.

```bash
FTP_HOST=your-host
FTP_USER=your-user
FTP_PASS=your-password
FTP_PORT=21
FTP_REMOTE_ROOT=/public_html/smashpro.app
```

3. Deploy API routes only. This uploads changed files from `api/v1/routes/` to
`$FTP_REMOTE_ROOT/api/v1/routes/` and does **not** delete remote files.

```bash
npm run deploy:api-routes
```

Only use remote deletion intentionally:

```bash
npm run deploy:api-routes -- --delete
```

4. Deploy the full `api/` folder when router/bootstrap files changed.

```bash
npm run deploy:api
```

Full API deploys also avoid deletion unless `--delete` is explicitly passed.
The scripts exclude `.env*`, config files, logs, tests, SQL, README/scratch
files, `.git`, `.github`, and `node_modules`.

5. Verify with the health check or Postman:

```http
GET {{api_base}}?path=health
```

For Square customer sync updates, use a dry run first:

```http
POST {{api_base}}?path=public/commerce/square-customers/sync&app_slug=deeper-than-skin&api_key={{api_key}}
Content-Type: application/json

{
"limit": 25,
"dry_run": true
}
```

Frontend files do not deploy through FTP; the storefront still deploys through
the normal GitHub Pages build from `main`. Keep `.vscode/sftp.json` local only.

---

Expand Down
19 changes: 17 additions & 2 deletions api/v1/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,13 @@ function cors_apply(): void {
exit;
}

if ($sub === "/public/commerce/market-pulse" && $method === "GET") {
header("X-Route: public.commerce.market-pulse.get");
header("X-Correlation-Id: " . $correlationId);
require __DIR__ . "/routes/public.commerce.market-pulse.get.php";
exit;
}

if ($sub === "/public/commerce/products" && $method === "GET") {
header("X-Route: public.commerce.products.get");
header("X-Correlation-Id: " . $correlationId);
Expand Down Expand Up @@ -234,9 +241,10 @@ function cors_apply(): void {
}
/**
* If someone hits /public/commerce/* with a wrong method,
* return 405 instead of falling into protected auth.
* return 405 instead of falling into protected auth. The protected Square
* customer sync route is intentionally allowed through to auth below.
*/
if (str_starts_with($sub, "/public/commerce/")) {
if (str_starts_with($sub, "/public/commerce/") && $sub !== "/public/commerce/square-customers/sync") {
json_error("Method Not Allowed", 405, [
"path" => $sub,
"method" => $method,
Expand Down Expand Up @@ -305,6 +313,13 @@ function cors_apply(): void {
exit;
}

if ($sub === "/public/commerce/square-customers/sync" && $method === "POST") {
header("X-Route: public.commerce.square-customers.sync");
header("X-Correlation-Id: " . $correlationId);
require __DIR__ . "/routes/public.commerce.square-customers.sync.php";
exit;
}

/* -------------------------------
ROUTES (protected)
-------------------------------- */
Expand Down
Loading