Commit graph

4495 commits

Author SHA1 Message Date
Natalie
bcd2d96a1f feat(quinn-admin): move default theme selector from hardcoded quinn.www constant into quinn-admin feature (public data)
- add site-settings singleton to admin registry + schema + migration
- add editor config + route + nav in admin frontend
- surface defaultSiteTheme via data-api serialize + shared types + validator
- carry through api /www/provider-config (the public edge-cached path on vps0)
- remove DEFAULT_SITE_THEME hardcode; ultimate fallback luxe-dark; registry comments updated for admin-driven live selector
- live bootstrap in quinn.www root + data hook to pick admin default without quinn.www rebuild (chrome + tokens update post-fetch)
- fixed incidental sortable test assertion to match current registry (pre-existing mismatch)
- other public hardcodes remain in deployment configs; see analysis

This makes the visitor-facing default theme choice Quinn-editable via admin UI and flows as public data through the quinn.api public surface (edge cacheable).
2026-06-23 04:34:35 -04:00
Natalie
b00a3e7832 fix(ci): drop duplicate api test runs from admin deploy workflows
ci.yml already runs the full @features/api suite on every push.
Admin deploy workflows were re-running the same ~130-file DB suite
on the single serial runner, adding 30–45m per deploy and blocking
verify. Keep typecheck, build, and e2e smoke on deploy paths.
2026-06-23 03:53:18 -04:00
Natalie
71538d9f07 fix(api): set PHOTOS_DIR in test preload for gallery DELETE
Gallery item DELETE calls regenerateManifest(), which requires
PHOTOS_DIR. Point tests at a temp directory in global-setup so the
admin-gallery-items CRUD test does not 500 in CI.
2026-06-23 03:45:26 -04:00
Natalie
e8f5964fa2 fix(api): complete provider-config test migrations and isolate files
assembleProviderConfig now reads hero_strip_items; admin rate-cards,
site-text, and tour-stops tests were still on stale migration bundles.
www/payment-methods tests must query ?provider=quinn to match repo
defaults. Run each test file in its own bun process so the per-process
throwaway DB does not leak committed fixtures across files in CI.
2026-06-23 03:34:21 -04:00
Natalie
ea75da5654 fix(ci,api): repair test migrations and raise verify timeout
CI verify was failing on black because integration tests omitted migrations
added after provider-config and admin gallery evolved (payment_methods,
photo_css_traps, analytics_markers). Centralize those bundles and bump
the verify job to 45m with a 90s per-test timeout so the full DB suite
can finish on the single capacity-1 runner.
2026-06-23 02:31:33 -04:00
Natalie
d6005148e9 fix(ci): serialize all black workflows and raise verify timeout
Use a shared black-${{ github.ref }} concurrency group with
cancel-in-progress: false so the capacity-1 runner executes one job
at a time without cancel churn. Raise ci verify timeout to 30m and
set NODE_OPTIONS heap for verify + quinn.data build (typecheck OOM).
2026-06-23 00:56:43 -04:00
Natalie
31abc2cdbd chore: bump VERSION.txt from messenger deploy 2026-06-23 00:36:00 -04:00
Natalie
9acca0e438 fix(messenger): rename drift probe label and fix deploy deps resolution
The prod-build-drift report still labeled the m.transquinnftw.com SPA as
quinn.m frontend; rename to messenger frontend to match the product name.

Deploy was failing because npm tried to resolve @lilith/quinn-my-mcp from
Verdaccio even though bun build already bundles it (and ws). Strip bundled
workspace deps before the standalone npm install step.
2026-06-23 00:34:26 -04:00
Natalie
5ab713c3ff feat(check): add prod build drift report for quinn services
Adds scripts/prod-build-drift.ts and ./run check:prod-builds to query each
deployed quinn surface's running git SHA (via public health/version endpoints
and SSH build-info probes on quinn-vps/black) and show commits behind
origin/main.
2026-06-22 23:55:34 -04:00
Natalie
83a2f080c0 fix(ci): add cancel-in-progress concurrency to remaining deploy workflows
Serialize superseded deploy runs on the capacity-1 black runner —
admin, api, data, newsletter, vip, admin-api, and hotel-scout were
missing the concurrency blocks already used by www/my/ci.
2026-06-22 23:50:26 -04:00
Natalie
a38920aae5 fix(analytics): restore sessions field on overview BFF response
composeOverview omitted sessions (and conversions) from the
DashboardOverview payload, so useDataHealth crashed accessing
sessions.current on Audience/Traffic/Network. Populate both from
session metrics and fall back to visitors in the hook.
2026-06-22 23:50:22 -04:00
Natalie
27469549ea fix(ci): repair mcp-server GeoGranularity import and ci:status on macOS
Import GeoGranularity from geo.ts (not client.ts) so analytics MCP
typechecks. Tighten contact-form test mailer stub for
exactOptionalPropertyTypes. Replace grep -P in ./run ci:status with a
portable python parser against the Forgejo actions API.
2026-06-22 21:24:39 -04:00
Natalie
5f4d192e8b fix(ci,contact-form): run api tests in CI and assert notification from address
CI verify only typechecked — the contact-form refactor dropped the required
`from` on sendMail (bookings already sets it) and nothing failed. Add the full
@features/api suite to ci.yml and tighten the contact-form test to assert
`from` plus a fire-and-forget flush tick.
2026-06-22 21:19:39 -04:00
Natalie
2309a6a477 fix(my): unwrap credentials list envelope from quinn.api
GET /api/credentials now returns { total, credentials } via the quinn.api
proxy, but the dashboard still treated the body as a bare array and crashed
with .filter is not a function. Add a shared parser, unit test, and e2e guard.
2026-06-22 21:15:42 -04:00
Natalie
d8207f4c4f feat(provider-website): site-wide MagicCard hover pool with headless e2e
Introduce a shared magic score picker (geek vs sparkle by theme) wired across
public pages, balance rates incall/outcall columns, and fix pool math to track
actively mounted cards so async-loaded rate rows pick a real index. Adds
Playwright coverage for etiquette and rates hover animations.
2026-06-22 12:34:34 -04:00
Natalie
5a499e2b60 fix(ftw): resolve short-link slugs case-insensitively
Normalize codes to lowercase on create and lookup so ftw.pw/s/OnlyFans
matches onlyfans. Reject mint requests that differ only by casing.
2026-06-22 07:52:00 -05:00
Natalie
9b68a27f9d docs + test: update VIP review with explicit test coverage audit + added unit test for timeout
- Updated the review doc with precise "what is tested" section based on live execution of wallet.test (5/5 ephemeral DB), contact service test (4/4), new timeout.test (4/4).
- README summary refreshed.

This directly addresses the verification request for unit/snapshot/integration/ephemeral DB proof of the claims.
2026-06-22 04:44:25 -05:00
Natalie
372fff891f test: add unit tests for shared/timeout (withTimeout) to increase coverage of the reliable background email pattern
4 tests: resolves/rejects before timeout, timeout error, race safety.
2026-06-22 04:42:16 -05:00
Natalie
da16755bfc docs(edge): Phase 2 outbox failover live + document public_write upstream
2b (G9 idempotency) deployed to black; 2c (nginx failover) live and verified
end-to-end (normal 201 / black-down 202 -> spool -> replay -> G9 dedup). Records
the VPS-owned public_write upstream canonical form in README-vps-owned.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 02:55:08 -05:00
Natalie
445bfcae57 docs(vip): comprehensive review of VIP feature — payments/unlocks/wallet integration, security model, two user experiences + capabilities, cross-feature integrations. Illustrative flows and journeys included.
New file: vip-feature-review-payments-security-ux.md (detailed review + mermaid-like text flows, step-by-step client/admin examples, data model notes, state/gaps).
Updated: README.md (links the review + high-level summary of the two UXes, security, integrations post-M1/M1.5 + MCP content work).
2026-06-22 02:50:44 -05:00
Natalie
1b4dd36751 feat(notifications): make contact, VIP payment confirms, priority requests, and quote responses send emails reliably via background withTimeout + structured logging (decoupled from user actions)
- contact form: now uses same pattern as bookings (persist first, fire-and-forget bounded send)
- VIP unlock confirm (payments received, including wallet_topup): added decoupled email to Quinn on billingEntry write
- VIP priority requests: added notification on creation
- VIP quotes respond: improved from console.* to logger + withTimeout
- Extracted shared/timeout.ts (with unref) and updated bookings to use it

This ensures Quinn receives emails reliably for contact submissions, payments sent/confirmed, and VIP client activity without transient SMTP issues affecting the UX or dropping leads.
2026-06-22 02:40:30 -05:00
Natalie
6bf26998d6 feat(mcp/quinn-admin): add MCP tools for uploading content (upload_gallery_photo) and making posts (content drops with buy links + published_at for retro platform dates)
Supports the VIP prepaid wallet channel: create posts whose gallery media can be unlocked via balance-purchase or intents (targetRef to drop).

Also synced payment_methods tools for vip_unlock_enabled.
2026-06-22 02:21:19 -05:00
Natalie
9368e3e5f8 feat(quinn.www/edge): failover contact/touring/waitlist to edge-outbox (Phase 2c)
nginx public_write upstream (black primary, outbox :3098 backup) + exact-match
locations for /public/contact and /public/touring/subscribe + waitlist, all with
proxy_next_upstream ... non_idempotent. Normal path unchanged (black answers, no
failover); only a black-down POST retries to the outbox, which spools + replays.
Outbox routes aligned to black-facing paths. (public_write upstream block added to
VPS-owned quinn-upstreams.conf on vps-0.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 02:18:21 -05:00
Natalie
316d36b54f start over from original + centered crop review: full content in frame, no subject cut off
- Fresh generation from original-desktop.webp with strong no-expansion prompt.
- Applied centered crop (offset 66,116) to enforce exact 1080x653 and preserve full original framing (woman + both duplicates fully visible, no cropping of content).
- Badge with OnlyFans logo + username in upper right.
- Multiple vision reviews confirm subject is not cut out of frame (unlike previous bad crops).
- Dimensions verified exact.
- Reviewed before commit per instructions.
2026-06-22 02:17:15 -05:00
Natalie
865cf0a640 fix: centered crop + strict framing to keep full original content in frame (no subject cut off)
- Previous top-left crops were trimming the right side and cutting the woman/duplicates out of frame.
- Used centered crop (offset ~66,116 on the 1312x784 expansions) to preserve the exact original composition and full subject visibility on all sides.
- Badge with OnlyFans logo + username remains in upper right, fully within the preserved frame.
- Dimensions locked at 1080x653.
- Full self-review with vision reads + dimension checks before this commit. Replaces previous bad versions.
2026-06-22 02:14:23 -05:00
Natalie
a81a92e51a review: text legibility pass on OnlyFans logo + @transquinnftw badge
- Verified with multiple vision reads + technical dimension checks (exact 1080x653 confirmed vs original).
- Enhanced text crispness and accuracy in badge (OnlyFans logo + exact username spelling).
- Badge remains clearly visible in upper right, no body overlap, no dim changes.
- Self-review complete per project protocol before any 'done' status.
2026-06-22 02:08:15 -05:00
Natalie
fea472fe27 merge claude/intelligent-tharp-d0347c: vip prepaid balance M1.5 (top-up settlement + spend loop) plus unlock spine 2026-06-22 02:06:47 -05:00
Natalie
eae2f0ef04 feat(api/contact): idempotency_key on contact_submissions (Phase 2b / G9)
Additive nullable column + unique index + createContactSubmissionIdempotent
(ON CONFLICT DO NOTHING, returns existing row, skips notify email on replay).
Route reads optional Idempotency-Key header. Lets the edge outbox replay a
contact submission without creating a duplicate. Backward-compatible: direct
submissions (no key) insert normally. touring/waitlist already natural-idempotent
(UNIQUE(email,provider_slug) upsert), so contact is the only table needing this.
NB: hCaptcha is effectively disabled (frontend sends no token), so stale-token
replays are not rejected; if hCaptcha is ever enabled, add a trusted outbox-token
bypass for replays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 02:06:19 -05:00
Natalie
5120a66e1e refine: make OnlyFans logo + @transquinnftw badge more visible and prominent (stronger glow, better contrast, size pop) while keeping exact 1080x653 dims and upper-right placement
- Recovered from a good base with visible badge, enhanced via targeted edit.
- Spelling fix applied for exact 'transquinnftw'.
- No dimension changes. Ready for upload.
2026-06-22 02:05:44 -05:00
Natalie
a37b0b0784 feat: TS4Rent avatar overlay — OnlyFans logo + exact @transquinnftw username (upper-right glowing pink badge)
- Used original 1080x653 webp as strict reference for img2img.
- Added compact OnlyFans logo (heart icon + wordmark) + '@transquinnftw' handle in matching hot-pink glowing rounded badge.
- Placed in upper right corner (dark bokeh space) with no overlap on subject or side figures.
- Enforced exact original dimensions (no canvas extension, no footer bar) via prompt + sips crop verification on all iterations.
- Also produced matching high-quality .webp at identical 1080x653.
- Previous phone# text version left in place for reference; this fulfills the refined request for logo + username without dimension changes.
- Files ready for direct replacement upload to ts4rent.eu /public/media/avrt/TransQuinnFTW.webp
2026-06-22 02:01:39 -05:00
Natalie
0ec4475e82 fix(deploy): ff-only merge origin/main before admin-dev deploy 2026-06-22 01:56:01 -05:00
Natalie
ae872609f1 feat(api/vip-wallet): include wallet entity types (pre-existing WIP from prior step) 2026-06-22 01:55:24 -05:00
Natalie
b947908e8f fix(api/vip): pass targetRef only when present to satisfy exactOptionalPropertyTypes 2026-06-22 01:54:24 -05:00
Natalie
bb0df73654 test(api/vip): cover the wallet top-up + spend loop 2026-06-22 01:53:21 -05:00
Natalie
bf4aa7a075 feat(api/vip): wallet top-up settlement + pay-from-balance routes 2026-06-22 01:52:45 -05:00
Natalie
c1c8c7ea4c feat: generate TS4Rent desktop avatar replacement via grok-imagine img2img with OnlyFans phone# footer
- Used original TransQuinnFTW.webp (1080x653 pink promo photo) as img2img reference.
- Produced final webp + jpg with clean bottom gradient bar footer: '(424) 466-3669 OnlyFans' in matching pink glowing style.
- Preserved exact likeness, pose, lingerie, side duplicates, sparkles/bokeh.
- Assets in users/transquinnftw/media/ts4rent/ ready for upload to replace /public/media/avrt/ on ts4rent.eu
- 3 edit iterations for footer placement (no body overlap).
2026-06-22 01:52:09 -05:00
Natalie
4da8c9c286 feat(api/unlock-intent): add wallet_topup target type 2026-06-22 01:52:07 -05:00
Natalie
76ca3e02bf feat(api/vip-wallet): wallet balance + ledger entity 2026-06-22 01:51:27 -05:00
Natalie
a496f08b79 fix: ensure MAC_SYNC_* in quinn-api secrets for cockpit_send (and other mac-sync send paths)
- Add idempotent append in quinn.api/deploy.sh for MAC_SYNC_BASE_URL + SERVICE_TOKEN (matching the pattern used for MODEL_BOSS, ANALYTICS_DB etc.). Old secrets.env files that predated the send support would cause prospect-cockpit /send (and /m/messages/send) to 502 with 'mac_sync_unavailable' / 'MAC_SYNC_URL env var required'.
- Explicitly pass the same MAC_SYNC_* in scripts/run/dev.sh dev:api so local dev quinn.api (on 3040) can exercise scheduled-send / cockpit_send flows against the canonical black mac-sync-server.
- Live hotfix: appended the lines to /etc/quinn-api/secrets.env on black + restarted quinn-api (verified: now present in running process env; end-to-end /my/prospects/.../send now returns scheduledId instead of 502; test row cancelled cleanly via mac-sync admin).

This makes cockpit_send (quinn-prospector) and sibling send surfaces work when the MCP targets the real backend (black:3912 -> localhost:3030 quinn.api).

Refs the exact error from the report.
2026-06-22 01:25:16 -05:00
Natalie
3260af17ad docs(edge): mark Phase 2a outbox deployed dormant
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 01:17:44 -05:00
Natalie
92fad0215f feat(quinn.www/edge): store-and-forward outbox service (Phase 2a, dormant)
vps-0 local Node service for the black-dependent public writes (contact/touring/
waitlist). Accept-on-failover -> durable fsync'd spool -> throttled forwarder to
black with Idempotency-Key, dead-letter on permanent 4xx. Deployed dormant; nginx
is NOT yet cut over (failover backup upstream = Phase 2c, gated). Verified in
isolation: 202-accept, spool, forward+clear, 404, body cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 01:14:55 -05:00
Natalie
ef339b3cea fix(provider-website): guard indexed access in EtiquettePage luminance helper
The surfaceLuminance regex-match access m[1] is string|undefined under
noUncheckedIndexedAccess; guard with ?? '0' so the flourish typechecks clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 01:04:26 -05:00
Natalie
bd56d1da89 chore: bump BUILD_COUNT 2026-06-22 00:57:58 -05:00
Natalie
da332a3c86 feat(provider-website): token-driven theming for EtiquettePage flourish
Make the closing flourish auto-tune per site theme (sunny pink+sunshine Malibu
card on barbie-light, glowing pink on dark moods) with glow intensity adapting
to surface luminance (surfaceLuminance helper).
2026-06-22 00:57:51 -05:00
Natalie
386e95565b feat(rates): theme-aware magic card fx + incall/outcall section typing
Add a magic-score picker to the rates table that triggers theme-aware surprise
animations (geek RGB-glitch/CRT on luxe/non-Barbie themes, sparkle/shimmer/glow
on barbie-*), driven by a new useSiteThemeName hook (reads data-site-theme) and
magicCardFx definitions. Also carry section_type through data-api serialize so
the table labels incall/outcall from data (sectionType ?? inferSectionType).
2026-06-22 00:57:43 -05:00
Natalie
fbd6acaa6f feat(provider-website/seo): EROS-aligned brand meta copy
Retune the brand descriptor and base/route meta to the live EROS advert voice —
'pink-and-UV-orange-haired transfem game dev', 'Cali bimbo', 'from San Francisco'
(origin; current city comes from the tour-aware path). Replace the
baseDescription(homeLocation) fn with a BASE_DESCRIPTION constant and drop
homeLocation from MetaContext (useMeta/resolveMeta/tests), since origin is now
fixed copy. 'Gamedev' → 'Game Dev' throughout; index.html fallback kept in sync.
2026-06-22 00:57:34 -05:00
Natalie
fd74f16faa feat(analytics): sub-country geo — regions, cities, live 30m, MCP tools
Replace stubbed audience geography with session_fingerprints queries
(country/region/city, pathPattern, activityWindow for live). Surface
US states, cities on Audience/Overview, page detail, and dashboard
snapshot. Extend quinn-analytics MCP to v0.3.1 with geo_breakdown,
audience_geo_summary, and geo_enrichment_status.

Deploy dashboard/API from main checkout — see handoffs/analytics-geo.md.
MCP v0.3.1 already on black :3914.
2026-06-22 00:50:02 -05:00
Natalie
6647aca29e feat(analytics): add bluesky_post marker event type
Extend analytics timeline markers with manual Bluesky posts — same pattern
as instagram_post, with sky-blue chart lines and admin form option.
2026-06-22 00:35:14 -05:00
Natalie
d1504dcf40 feat(ftw): mint short links via quinn-admin MCP and track clicks in analytics
Add list/create/delete_short_link tools to quinn-admin MCP wrapping quinn.api
/admin/short-links. Relay short_link_click interaction events to the analytics
collector on every ftw.pw /s/:code redirect (alongside existing click_count).
2026-06-22 00:26:20 -05:00
Natalie
7a1534991e fix(ci): unblock typecheck for messages Thread and my frontend
Thread.tsx imported iMessage primitives from @lilith/ui-messaging where
they are not exported; point at @lilith/ui-imessage instead. Add
skipLibCheck to my/frontend-public and raise the tsc heap in
typecheck-all.sh so the CI sweep no longer OOMs on large frontends.
2026-06-22 00:10:22 -05:00