Strip API Surface
Strip API Surface
Section titled “Strip API Surface”Strip is a Fiber HTTP server that renders Templ pages and serves HTMX-style JSON fragments. It has no direct DB writes for domain entities — every business read or mutation is forwarded to sirloin over gRPC.
Topology
Section titled “Topology”flowchart LR Browser -->|HTTPS| Strip[Strip Fiber<br/>:8080] Strip -->|Clerk SDK / cookie| Clerk[(Clerk)] Strip -->|gRPC| Sirloin[(sirloin StripService<br/>v5)] Strip -->|HTTPS| OpenRouter[(OpenRouter LLM)] Strip -->|HTTPS| Brisket[(brisket links)]
See apps/strip/cmd/app/main.go startFiberServer (line 330+).
Middleware Stack (in order)
Section titled “Middleware Stack (in order)”Registered in cmd/app/main.go:
requestid.New()— request ID for trace correlation.recover.New(EnableStackTrace: true)— panic recovery, returns 500.helmetMiddlewareForStage— security headers (CSP varies by stage).limiter.New(globalRateLimitMax) — IP-keyed global rate limit. Asset paths (/assets,/assets/...) are skipped viashouldSkipGlobalRateLimit.compress.New— gzip/brotli on dynamic responses.- Static file serving for
/assets.
A stricter authLimiter is layered onto /login, /auth/refresh, and /auth/clerk/callback.
Auth Surface
Section titled “Auth Surface”Auth is enforced by two middlewares (apps/strip/internal/app/middleware/):
AuthMiddleware.RequireAuth— verifies a Clerk session cookie or__sessiontoken; populatesc.Locals("userId" | "userEmail" | "sessionToken").AuthorizationMiddleware.RequirePermission(perm)— RBAC, fails with 403. HTMX requests get a JSON body +HX-Reswap: none, otherwise the forbidden Templ page.
Two dev-only bypass paths exist and emit SECURITY WARNING logs:
X-Auth-Bypass: <uuid>header (or?auth=<uuid>) matchingSTRIP_AUTH_BYPASS_UUID.Stage == developmentwithclerkService == nil.
Permission catalog (internal/app/authorization/authorization.go): view:dashboard, view:users, manage:credits, view:characters, create:character, update:character, delete:character, manage:nsfw, manage:approved_celebrity, view:media, delete:media, view:audit_logs, view:dataset, view:examples, view:payments, create:users, manage:roles, manage:admins.
Public Routes
Section titled “Public Routes”| Method | Path | Handler | Notes |
|---|---|---|---|
| GET | /health |
inline | liveness, no auth |
| GET | /login |
HandleLogin |
Clerk login page |
| POST | /login |
HandleLoginPost |
authLimiter |
| POST | /auth/refresh |
HandleRefreshToken |
authLimiter |
| POST | /auth/clerk/callback |
HandleClerkCallback |
authLimiter |
| GET | /sso-callback |
HandleSSOCallback |
|
| GET | / |
createRootHandler |
redirects per session state |
Protected Pages (RequireAuth)
Section titled “Protected Pages (RequireAuth)”| Path | Handler | Extra perm |
|---|---|---|
GET /dashboard |
HandleDashboard |
— |
GET /ask-strip |
HandleAskStrip |
view:audit_logs |
GET /users |
HandleUsers |
— |
GET /characters |
HandleCharactersPage |
— |
GET /dataset-gallery[/load-more] |
HandleDatasetGallery |
— |
GET /media[/load-more] |
HandleListMedia |
— |
GET /media/gallery[/load-more] |
HandleMediaGallery |
— |
GET /popular-examples[/load-more] |
HandlePopularExamplesGallery |
— |
GET /shop-vi[/load-more] |
HandleShopVIListing |
— |
GET /payments |
HandlePayments |
view:payments |
GET /auditlogs |
HandleAuditLogs |
view:audit_logs |
GET /roles |
HandleRolesPage |
manage:roles |
DELETE /api/media/:id |
HandleDeleteMedia |
delete:media |
POST /logout |
HandleLogout |
— |
Protected JSON / HTMX API (/api/*, RequireAuth)
Section titled “Protected JSON / HTMX API (/api/*, RequireAuth)”| Method | Path | Handler | Perm |
|---|---|---|---|
| GET | /api/auth/mcp-token |
HandleMCPToken |
— |
| GET | /api/users/search |
HandleUserSearch |
— |
| GET | /api/command-palette/search |
HandleCommandPaletteSearch |
— |
| GET | /api/search/preview |
HandleSearchPreview |
— |
| GET | /api/activity-feed |
HandleActivityFeed |
— |
| POST | /api/ask-strip/support-brief |
HandleAskStripSupportBrief |
view:audit_logs |
| POST | /api/ask-strip/chat |
HandleAskStripChat |
view:audit_logs |
| GET | /api/users/:id |
HandleUserDetails |
— |
| GET | /api/users/:id/panel |
HandleUserPanel |
— |
| POST | /api/users/:id/credits |
HandleAddCredits |
manage:credits |
| POST | /api/users/:id/characters |
HandleCreateCharacter |
create:character |
| POST | /api/users/create |
HandleCreateClerkUser |
create:users |
| GET | /api/characters/:id |
HandleCharacterDetails |
— |
| GET | /api/characters/:id/panel |
HandleCharacterPanel |
— |
| POST | /api/characters/:id/update |
HandleUpdateCharacter |
update:character |
| POST | /api/characters/:id/bypass-onboarding-checks |
HandleBypassCharacterOnboardingChecks |
update:character |
| DELETE | /api/characters/:id |
HandleDeleteCharacter |
delete:character |
| GET | /api/media/:id/panel |
HandleMediaPanel |
— |
| GET | /api/auditlogs/:id |
HandleAuditLogDetails |
view:audit_logs |
| GET | /api/roles |
HandleListRoles |
manage:roles |
| POST | /api/roles |
HandleSetRole |
manage:roles |
| DELETE | /api/roles/:userId |
HandleDeleteRole |
manage:roles |
Templ Pages
Section titled “Templ Pages”Templ files render every protected page above. They live under apps/strip/internal/app/strip/templates/ and are compiled by templ generate into *_templ.go siblings. The strip Fiber handlers call templates.<Page>(...).Render(ctx, c) rather than c.Render. See services/strip-datatable/ and services/strip-filters/ for the shared render primitives.
Downstream gRPC Calls
Section titled “Downstream gRPC Calls”Strip embeds the generated client at apps/strip/internal/pkg/pb/sirloin/v5/. The proto contract is proto/sirloin/v5/strip.proto, service sirloin.v5.StripService. RPCs called by handlers include:
StripListUsers,StripUpdateUserStripListCharacters,StripCreateCharacter,StripUpdateCharacter,StripDeleteCharacter,StripBypassCharacterOnboardingChecksStripListMedia,StripFailMediaStripListPopularExamples,StripListPopularCategoriesStripListDatasetImagesStripLogAudit,StripListAuditLogs,StripGetAuditLogStripGetUserRole,StripListUserRoles,StripSetUserRole,StripDeleteUserRole(proto/sirloin/v5/strip.proto:33-36)StripCreateClerkUser(proto/sirloin/v5/strip.proto:39)StripFoxy360CreateThread,StripFoxy360SendMessage,StripFoxy360GetRun,StripFoxy360ListMessages,StripFoxy360ListArtifacts(proto/sirloin/v5/strip.proto:42-46)StripGetDashboardStats,StripGetSchema,StripRunReadonlyQuery(proto/sirloin/v5/strip.proto:28-30)StripGetPaymentsDashboard(proto/sirloin/v5/strip.proto:47) — the aggregated renewal, cohort and decline series behind/paymentsStripListAvailableCharacters(proto/sirloin/v5/strip.proto:49). Credits surface as fields onStripListUsers/ character responses (credits_min,remaining_credits,standard_credits,full_access_credits) — no dedicated credits RPC.
The keepalive client is created in cmd/app/main.go (grpcKeepaliveTime=30s, grpcKeepaliveTimeout=10s) and reused for the process lifetime.