Documentation
juliofruta.com
Monorepo for Julio César Guzmán Villanueva's personal portfolio, iOS engineering projects, and their supporting web presence. A Vite/Tailwind frontend is served by a Swift Vapor backend, packaged together into a single Docker image.
Repository structure
julio/
├── frontend/ # Vite multi-page app
│ ├── portfolio/ # index.html — personal CV
│ ├── delegalo/ # home services platform
│ ├── boscoso/ # resort living app
│ ├── disclosure/ # dating app waitlist
│ ├── feature-flags/ # admin flag panel
│ ├── src/main.js # Tailwind CSS entry point
│ └── vite.config.js
│
├── server/ # Swift Vapor backend
│ ├── Sources/App/
│ │ ├── configure.swift # middleware, JWT, SMTP
│ │ └── routes.swift # HTTP routes + flag store
│ ├── Public/ # static files (built frontend)
│ │ └── docs/ # auth-setup.html, README.html
│ └── Package.swift
│
├── Julio/ # visionOS / iOS app (TCA)
│ └── Vision/
│ ├── Dependencies/ # FeatureFlagsClient, …
│ └── Features/ # FeatureFlagsFeature, …
│
├── Dockerfile # multi-stage: Node → Swift → slim
├── docker-compose.yml # one-command build + run
├── .env.example # env variable template
└── .gitignore
Tech stack
| Layer | Technology & Documentation Link |
|---|---|
| iOS / visionOS app | Swift, SwiftUI, RealityKit, Composable Architecture (TCA) |
| Frontend | HTML5, Vanilla JS, Tailwind CSS v4 |
| Build tool | Vite (multi-page mode) |
| Backend | Swift 5.9, Vapor 4 |
| Auth | Sign In with Apple + vapor/jwt Session HMAC-SHA256 JWTs |
| SMTP via Mikroservices/Smtp | |
| Infrastructure | Docker Build (Compose, Dockerfile) |
Prerequisites
| Tool | Version | Used for | Documentation Reference |
|---|---|---|---|
| Node.js | 18+ | Frontend compile & build | Node.js Docs Portal |
| Swift | 5.9+ | Vapor backend compiler & core logic | Swift Language Guide |
| Xcode | 15+ | visionOS & iOS simulator/device builds | Xcode Developer Center |
| Docker | any | Containers, local run & production runtime | Docker Documentation Portal |
Development
1 — Frontend
Vite dev server with hot-reload. Pages are served at their directory paths.
cd frontend
npm install
npm run dev
Opens at http://localhost:5173. To build for production:
npm run build # outputs to frontend/dist/
2 — Backend
Set up your environment variables first:
cp .env.example .env
# edit .env with your values at the root
Build and run. Since Vapor reads .env from the execution directory, copy the env file to server/.env before running locally from inside the server folder:
cp ../.env .env
swift run App serve --env development --hostname 0.0.0.0 --port 8080
--env development flag, Vapor ignores .env entirely and all Environment.get() calls return nil, falling back to insecure dev defaults.
The server serves static files from server/Public/. After any frontend change, sync the build:
cd frontend && npm run build
cp -r dist/* ../server/Public/
3 — iOS / visionOS app
Open Julio.xcodeproj in Xcode and run on a simulator or device.
- Login Flow: Dynamically displays the Login view fullscreen when logged out, and transitions to the main tabbed layout once logged in.
- Haptics Sequence: Triggers 8 rapid light taps followed by a heavy tap when starting pull-to-refresh on the Activity tab, and another heavy tap upon completion.
- Feature Flags: Fully enabled and functional on iOS (previously macOS-only), authenticating against
http://127.0.0.1:8080(local Vapor server must be running). - Keyboard Feature: Removed.
Environment variables
Copy .env.example to .env at the repo root. In production, variables are injected automatically by docker-compose.yml — Vapor does not read the file directly. Details are available in the Vapor Environment Manual.
SESSION_SECRET
Required in production
HMAC-SHA256 key for session JWTs. Generate: openssl rand -hex 32. Reference: Vapor JWT Keys.
ADMIN_APPLE_USER_ID
Required
Your permanent Apple user ID (sub claim). See how to find it or consult Apple Verification docs.
APPLE_IOS_BUNDLE_ID
Optional
iOS bundle ID for Apple token audience check. Default: julio.fruta. Reference: Sign In with Apple REST API.
APPLE_SERVICE_ID
Optional — web only
Apple Service ID for web Sign In with Apple. Reference: Apple Service Identifiers.
SMTP_HOSTNAME / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD
Optional — Email Alerts
SMTP credentials for email notifications from Delegalo and Boscoso forms.
Reference: Vapor SMTP Library.
Authentication
The feature flags panel requires Sign In with Apple. Full reference at /docs/auth-setup.html.
Official Apple Documentation Resources:
How it works
-
1
Client triggers Sign In with Apple → Apple returns a short-lived identity token (JWT, 5 min).
-
2
Client sends token to
POST /auth/appleasAuthorization: Bearer <token>. -
3
Server fetches Apple's JWKS (cached 1 hr), verifies signature, expiry, and audience.
-
4
Server checks the token's
submatchesADMIN_APPLE_USER_ID. -
5
Server issues a 7-day session JWT (HMAC-SHA256, signed with
SESSION_SECRET). Stored in Keychain (iOS) orsessionStorage(web).
Finding your Apple user ID
Start the server without ADMIN_APPLE_USER_ID, then sign in. The server logs:
Copy that value into server/.env and restart with --env development.
Web Service ID setup
- 1. Create a Service ID at Apple Developer → Identifiers.
- 2. Enable Sign In with Apple, configure your domain, set redirect URI to
https://<your-domain>/feature-flags.html. - 3. Set
APPLE_SERVICE_IDinserver/.envand updateconst APPLE_SERVICE_IDinfrontend/feature-flags/feature-flags.html.
API reference
All Vapor-served endpoints in the monorepo are detailed below. Access the admin flags dashboard at /feature-flags.html.
| Method & Endpoint | Auth | Purpose / Effect |
|---|---|---|
GET /health |
None | Service health status check. Returns `"OK"`. |
GET /ping |
None | Network diagnostics and ping. Returns `"pong"`. |
POST /auth/apple |
Apple identity token | Exchanges Apple ID JWT for 7-day server session JWT. |
GET /api/flags |
Session JWT | Returns JSON array representing all in-memory feature flags. |
POST /api/flags |
Session JWT | Creates or updates a feature flag. Request: `{"key": "my_flag", "isEnabled": true}`. |
POST /notify-activation |
None | Fires email alert informing admin of Boscoso activation click event. |
POST /contact |
None | Delegalo customer lead form capture. Sends full email summary to admin. |
POST /disclosure-join |
None | Disclosed early adopters waitlist signup. Triggers email to admin. |
POST /boscoso-join |
None | Boscoso residence queue waitlist signup. Sends device and email details to admin. |
Production
The Dockerfile uses a three-stage build: Node builds the frontend, Swift compiles Vapor in release mode, then both are combined into a slim runtime image.
Docker Compose (recommended)
Fill in .env at the repository root, then from the repo root:
docker compose up --build # build image and start server
docker compose up # start without rebuilding
docker compose down # stop
docker-compose.yml reads .env at the repo root automatically — no -e flags needed. Consult the official Docker Compose Documentation for advanced parameters.
Manual
docker build -t julio-dev .
docker run -p 8080:8080 \
-e SESSION_SECRET="$(openssl rand -hex 32)" \
-e ADMIN_APPLE_USER_ID="your-apple-user-id" \
-e APPLE_IOS_BUNDLE_ID="julio.fruta" \
-e SMTP_HOSTNAME="smtp.gmail.com" \
-e SMTP_PORT="587" \
-e SMTP_USERNAME="your-email@gmail.com" \
-e SMTP_PASSWORD="your-app-password" \
julio-dev
.env directly. Secrets must be injected as environment variables — either via docker-compose.yml env_file: or -e flags.
Google Cloud deployment
Two GCP services are relevant depending on your setup.
Cloud Run
Cloud Run runs a single container from an image. docker-compose.yml is not used here — env vars are configured in the Cloud Run service settings instead.
1. Build and push the image to Artifact Registry:
docker build -t REGION-docker.pkg.dev/PROJECT_ID/REPO/julio-dev .
docker push REGION-docker.pkg.dev/PROJECT_ID/REPO/julio-dev
2. In the Cloud Run console, create or update your service and set environment variables under Edit & Deploy → Variables & Secrets:
docker-compose.yml is only used locally when targeting Cloud Run.
Compute Engine (VM)
On a Compute Engine VM you can run Docker Compose directly. Create .env at the repo root on the VM with your production secrets, then:
git pull
docker compose up --build -d
Served pages
| URL | Description |
|---|---|
| / | Personal portfolio / CV |
| /delegalo.html | Delegalo home services platform |
| /boscoso.html | Boscoso resort living app |
| /activar.html | Boscoso activation page |
| /privacidad.html | Boscoso privacy policy |
| /disclosure.html | Disclosed dating app waitlist |
| /feature-flags.html | Admin feature flags panel |
| /docs/auth-setup.html | Sign In with Apple setup guide |
| /docs/README.html | This page |
| /health | Returns OK |
| /ping | Returns pong |