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 appSwift, SwiftUI, RealityKit, Composable Architecture (TCA)
FrontendHTML5, Vanilla JS, Tailwind CSS v4
Build toolVite (multi-page mode)
BackendSwift 5.9, Vapor 4
AuthSign In with Apple + vapor/jwt Session HMAC-SHA256 JWTs
EmailSMTP via Mikroservices/Smtp
InfrastructureDocker Build (Compose, Dockerfile)

Prerequisites

Tool Version Used for Documentation Reference
Node.js18+Frontend compile & buildNode.js Docs Portal
Swift5.9+Vapor backend compiler & core logicSwift Language Guide
Xcode15+visionOS & iOS simulator/device buildsXcode Developer Center
DockeranyContainers, local run & production runtimeDocker Documentation Portal

Development

1 — Frontend

Vite dev server with hot-reload. Pages are served at their directory paths.

bash
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:

bash
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:

bash
cp ../.env .env
swift run App serve --env development --hostname 0.0.0.0 --port 8080
Note: Without the --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:

bash
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.

How it works

  1. 1

    Client triggers Sign In with Apple → Apple returns a short-lived identity token (JWT, 5 min).

  2. 2

    Client sends token to POST /auth/apple as Authorization: Bearer <token>.

  3. 3

    Server fetches Apple's JWKS (cached 1 hr), verifies signature, expiry, and audience.

  4. 4

    Server checks the token's sub matches ADMIN_APPLE_USER_ID.

  5. 5

    Server issues a 7-day session JWT (HMAC-SHA256, signed with SESSION_SECRET). Stored in Keychain (iOS) or sessionStorage (web).

Finding your Apple user ID

Start the server without ADMIN_APPLE_USER_ID, then sign in. The server logs:

ADMIN_APPLE_USER_ID is not set. Attempting user sub: 000000.abc123…

Copy that value into server/.env and restart with --env development.

Web Service ID setup

  1. 1. Create a Service ID at Apple Developer → Identifiers.
  2. 2. Enable Sign In with Apple, configure your domain, set redirect URI to https://<your-domain>/feature-flags.html.
  3. 3. Set APPLE_SERVICE_ID in server/.env and update const APPLE_SERVICE_ID in frontend/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:

bash
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

bash — build
docker build -t julio-dev .
bash — run
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
Production mode does not read .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:

bash
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:

SESSION_SECRET
ADMIN_APPLE_USER_ID
APPLE_IOS_BUNDLE_ID
SMTP_HOSTNAME  /  SMTP_PORT  /  SMTP_USERNAME  /  SMTP_PASSWORD
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:

bash
git pull
docker compose up --build -d

Served pages

URL Description
/Personal portfolio / CV
/delegalo.htmlDelegalo home services platform
/boscoso.htmlBoscoso resort living app
/activar.htmlBoscoso activation page
/privacidad.htmlBoscoso privacy policy
/disclosure.htmlDisclosed dating app waitlist
/feature-flags.htmlAdmin feature flags panel
/docs/auth-setup.htmlSign In with Apple setup guide
/docs/README.htmlThis page
/healthReturns OK
/pingReturns pong