FIVEM COMMUNITY / PORTFOLIO + PRIVATE TOOLS
Katie
MonroePhotography.
A portfolio with
its own back office.
A FiveM photography portfolio with private content tools and an explicit missing-configuration fallback.
And a way
to manage it.PUBLIC EXPERIENCE / PRIVATE TOOLS
- My contribution
- Public portfolio, Worker API,
admin console & deployment
- Context
- FiveM photography project
June 2026 account
- Built with
- JavaScript · Vite · Worker
Turso · R2
01 / THE BUILDA portfolio with work happening behind it
Katie Monroe is a photographer character in a Los Santos roleplay community. The site pairs an image-led public portfolio with private tools for managing the work behind it: photo uploads, collections, commission enquiries, and shoot scheduling.
My contribution covered the public portfolio, Worker API, admin console, and deployment. This is a FiveM community project, not a claim about a commercial photography client's results.
The presentation here uses an illustrated contact sheet and system diagrams. A verified full-resolution gallery capture is not available in the supplied handoff, so the illustration is not presented as the finished application.
02 / THE BUILDTwo deployments, different responsibilities
The historical build uses vanilla JavaScript and Vite for the public front end, deployed on Vercel. Its gallery, lightbox, motion, and story routing are ES modules rather than a React application.
A separately deployed Cloudflare Worker handles the API. Turso provides libSQL storage, R2 holds images, and the account describes signed JWT authentication for protected operations.
KATIE / RESPONSIBILITIES
The system, with the boundaries left in.
Select a component to read what the supplied account says it does.
Vite + vanilla JavaScript
Static front end
The historical account describes ES modules for the gallery, lightbox, motion, and story routing, deployed on Vercel. It does not describe a React front end.
Static front end: The historical account describes ES modules for the gallery, lightbox, motion, and story routing, deployed on Vercel. It does not describe a React front end.
Private console: Private tools cover uploads, collections, commission enquiries, and shoot scheduling. These responsibilities are not a screenshot of the console.
Cloudflare Worker: A hand-written method/path router with gated() wrappers for admin operations. The account describes signed JWT authentication.
Turso / libSQL: The documented database stores application data and supports the fixed-window rate limiter.
R2: The source says images upload without a resizing step. Derivative sizes are listed as future work.
Bundled samples: The shown loader returns local SHOTS/CATS when no Worker URL is configured. That alone does not establish configured-outage recovery.
This keeps the public-facing assets separate from the operations that need secrets. The private console manages content; it is not simply a second visual theme for the gallery.
03 / THE BUILDUseful without configuration—not a blanket outage promise
The supplied loader has a concrete fallback. With no Worker URL configured, it returns bundled sample photos and categories. With a Worker URL, it requests photos and collections from the API.
GALLERY / CONFIGURATION EXPLORER
Three situations. Only two branches shown.
An absent API configuration and a configured API failure are not the same condition.
if (!workerUrl)Recovery path not shown.
The request helper and caller are needed to know the actual failure behavior.
Use the bundled sample collection.
The missing-configuration branch returns bundled SHOTS and CATS. It does not make an API call.
The original article made a broader “never blank” claim. Its excerpt does not show recovery from a failed configured API request. The request helper and calling code would need to be inspected to establish that behavior.
The commission flow has a different responsibility. The source describes an explicit failure when there is no way to deliver an enquiry, rather than a success message for a message that was not sent.
04 / THE BUILDThe private tools need clear boundaries
The Worker uses a hand-written method-and-path router. Protected routes call a gated() wrapper; the article's examples include private collection access, private photo access, and uploads.
That makes the intended boundary visible in the excerpt. It is not proof that every route is correctly protected. The account also describes a Turso-backed fixed-window rate limiter and 164 tests across the Worker, front end, and admin console. That test count belongs to the June 2026 source, not this portfolio pass.
05 / THE BUILDWhat I would improve next
The original account identifies three areas for further work: simplify the router as it grows beyond its reported 31 routes, add image derivatives rather than uploading only source-sized files, and share some rendering code between the public site and admin console.
Those remain next steps in this account. No image pipeline, routing refactor, or expanded test coverage is being claimed as newly delivered.
The technical article shows the loader and routing excerpts. The client-facing article explains why useful fallback content and truthful delivery feedback need different treatment.
Source, dates, and what this page verifies
This rewrite is grounded in the supplied project account and complete related articles. Publication dates describe those accounts, not a new release. The original application, its permissions, screenshots, test results, and deployment have not been re-audited.
The diagrams are local explanations with no API calls, database operations, test execution, or saved input. Source conflicts and unsupported outcomes are identified in the reading copy and the handoff. No production deployment occurred.