Easy-to-manage touch screens
Free, open-source touch screens. Guided USB setup, a drag-and-drop editor and local control. Made for Home Assistant.
The global guide to LGBTQ+ venues, events, travel and community. Find safe spaces near you and around the world.
LifestyleTypeScript · PLpgSQLGitHub @tmaederOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
queer.guide — community hub for LGBTQ+ events, news & travel, with personalized hybrid search
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
The global platform for LGBTQ+ travel, community, and safe spaces at queer.guide.Read the full README ↗The global platform for LGBTQ+ travel, community, and safe spaces at queer.guide.
| Layer | Stack |
|---|---|
| Frontend | React 19, Vite 8, TypeScript 5.9, Tailwind CSS 4, shadcn/ui |
| Routing & Data | React Router 8, TanStack Query + Table + Virtual |
| Backend | Supabase (PostgreSQL 17.4, Auth, Storage, Edge Functions) |
| Hosting | Cloudflare Pages + Cloudflare Workers |
| Search | Postgres search_documents (hybrid keyword + vector(1024) semantic + PostGIS geo), served by the search-proxy CF Worker, CF Workers AI (bge-m3 embeddings, reranker) via AI Gateway |
| Maps | MapLibre GL 6, Protomaps basemaps, Mapbox geocoding (frontend), Photon/Nominatim (pipelines) |
| AI | Cloudflare Workers AI (llama-3.3-70b enrichment, llama-3.1-8b relevance gating, bge-m3 embeddings); OpenAI gpt-4o-mini as the legacy fallback path (USE_OPENAI=1) |
| Workflows | pgmq + workflow-dispatcher, admin_automations registry + pg_cron |
| Payments | Stripe |
| i18n | i18next — 11 languages (ar, de, en, es, fr, it, ja, ko, pt, ru, zh) |
| Editor | Tiptap |
| Monitoring | Sentry, Umami (self-hosted) |
src/ # React app (~280 pages, feature-grouped components)
supabase/
├── functions/ # 220 Deno Edge Functions
└── migrations/ # 1,255 PostgreSQL migrations
functions/ # Cloudflare Pages Functions (edge middleware, sitemaps, bot SEO)
workers/
├── assistant/ # CF Worker: conversational concierge (Durable Object + tool loop)
├── extract/ # CF Worker: server-side URL → markdown extraction
├── image-cdn/ # CF Worker: image transform + cache layer
├── image-ingest/ # CF Worker: image mirror/dedup → R2
├── ingest/ # CF Worker: embedding drain for search
├── search-proxy/ # CF Worker: search read path over Postgres RPCs
├── snapshot-archiver/ # CF Worker: admin/editorial snapshot archival
├── submit/ # CF Worker: extension submissions → ingestion_staging
├── team-inbox/ # CF Worker: team inbox ingestion
├── travel-inbox/ # CF Worker: travel inbox ingestion
└── trip-inbox/ # CF Worker: trip-planning inbox ingestion
scraper/ # Node.js scraping pipeline (Cheerio + Playwright)
extension/ # Chrome extension (MV3, React 19) — user venue/event submissions
e2e/ # Playwright E2E tests (86 specs)
scripts/ # Operational scripts
docs/ # Architecture docs, ADRs, runbooks
.github/workflows/ # GitHub Actions (CI, deploy, crons, nightly e2e, data-quality gates)
Requirements: Node.js 22+, npm.
npm install # .npmrc sets legacy-peer-deps
npm run dev # port 8080
| Script | Purpose |
|---|---|
npm run dev | Vite dev server (port 8080) |
npm run build | Production build → dist/ |
npm run lint | ESLint |
npm test | Vitest (src/**) |
npm run test:functions | Deno tests for supabase/functions/** |
npm run typecheck | tsc against a recorded baseline — fails only on new errors |
npm run typecheck:functions | tsc for functions/ (zero-tolerance gate) |
A root Makefile provides cross-package convenience targets (make install, make build, make test, make lint).
Sub-packages have their own package.json:
scraper/ — cd scraper && npm install && npm testextension/ — cd extension && npm install && npm run buildworkers/* — each uses wrangler dev / wrangler deployHybrid (keyword + semantic) personalized search with reranking, served entirely from Postgres.
See SEARCH_SYSTEM.md and workers/search-proxy/README.md.
Frontend ──► search-proxy (CF Worker)
├── AI Gateway → Workers AI (bge-m3 embed + reranker)
└── Supabase RPCs (search_hybrid / search_facets / search_autocomplete)
over the denormalized search_documents table
Supabase ──entity writes──► search_reindex_queue ──drain (1/min)──► search_documents
workers/ingest ──*/5 drain──► content_embeddings ──trigger──► search_documents.embedding
Indexed types: venues, events, cities, countries, news, marketplace, personalities, tags, queer_villages, landmarks, organizations, groups, guides, milestones.
Two layers. admin_automations is the registry of record and pg_cron is the only scheduler;
the ingestion_staging state machine plus dual-mode pipeline-* stage functions and
commit_*_staging_batch SQL RPCs are the recurring engine. pipeline-executor + the admin
Builder remain the manual/on-demand tool.
source-* (data fetchers, with cheap prefilters)
→ pipeline-normalize
→ pipeline-extract / sanitize
→ pipeline-validate
→ pipeline-deduplicate
→ [LLM enrichment — gated, budgeted]
→ pipeline-quality-score
→ pipeline-review-gate
→ pipeline-commit
Cheap deterministic gates run before paid stages; LLM spend is centrally capped in llm_budget,
with AI_DISABLED=1 as the hard kill switch. Queues: scheduled_jobs, import_jobs,
content_processing, dead_letter — exponential backoff retry, concurrency limits, idempotency keys.
News (hourly): RSS sources → sanitize → LLM enrichment (tags, summary, geo) → fingerprint dedup → commit. Source health auto-managed with exponential backoff and auto-pause at 8 consecutive failures.
Marketplace (daily, multi-source fan-in): Awin + Shopify + Etsy → Workers AI LGBTQ+ relevance gate → dedup → price-history tracking → image mirroring → embeddings. Weekly link-rot sweeper.
User submissions (Chrome extension): extracts structured data from any webpage via JSON-LD/microdata/OpenGraph/DOM heuristics → CF Worker stages into ingestion_staging → flows through the standard pipeline.
Observable at /admin/pipelines (Builder, Monitor, Sources, Staging, Dedup audit); health is gated
in CI by scripts/check-pipeline-health.mjs.
Content does not stop at ingest. Per-entity quality layers re-verify records continuously — events (trust score, liveness, corroboration), venues (cross-source consensus + closure signals), cities and countries (completeness + factual backfill), amenities, dedup, and personhood. Each writes an append-only signal ledger, routes ambiguous decisions to an admin review queue, and never auto-publishes a claim it cannot ground in a source.
admin_roles.canManageContent| Component | How |
|---|---|
| Frontend | Push to main → Cloudflare Pages auto-deploys |
| Edge functions | supabase functions deploy <name> --project-ref xqeacpakadqfxjxjcewc |
| Workers | wrangler deploy from each worker directory |
| DB migrations | Merged to main → CI supabase db push |
| Scraper | GitHub Actions cron |
See docs/runbooks/ for operational procedures (deploy, rollback, secret rotation, reindex, failed pipelines).
| Type | Tool | Run |
|---|---|---|
| Unit/component | Vitest + testing-library | npm test |
| Edge functions | Deno test | npm run test:functions |
| E2E | Playwright | npm run test:e2e |
| Types | tsc (baseline ratchet) | npm run typecheck |
| Scraper | Vitest | cd scraper && npm test |
E2E nightly at 03:00 UTC via GitHub Actions; i18n and a11y smoke tests on PRs touching relevant code. Data-quality, pipeline-health, migration-drift and SEO gates run on their own schedules.
Subway map system. A paper card over a page-wide ground layer of the four track colors, ink
type, and four semantic "line" colors used for wayfinding — --track-pink, --track-blue,
--track-green, --track-yellow. Track colors are fill-only, never body text, never encode risk,
and always carry a 1px ink ring so contrast is satisfied fill-vs-ring. One accent per context;
the four only meet on network diagrams and the intersection gradient. Light + dark mode.
Type: Anton for display (96/76/52/32/20 px ladder), Space Grotesk for everything else.
Both self-hosted. Always use a size token — arbitrary text-[NNrem] is blocked by ESLint.
Shape: semantic radius — rounded-panel (26px, dialogs/sheets/page shells),
rounded-container (18px, cards), rounded-element (12px, buttons/inputs/rows),
rounded-badge (9px, chips). Nothing square. rounded-full for avatars and dots only.
Surfaces: containers carry no frame. A card reads by covering the ground layer plus one soft
elevation (--shadow-soft); borders survive only where WCAG 1.4.11 requires them — form controls,
the ring on a track-colored mark, and components whose edge is the component.
Spacing: strict 8 pt grid — even-step Tailwind utilities only.
Layout: every page frames content with <PageContainer> (one gutter ladder, caps at 1600 /
768 prose / 512 forms). Hand-rolled page wrappers are an ESLint error.
Icons: TransitIcon (custom stroke-only wayfinding set) for navigation and content-type concepts;
lucide-react for UI chrome.
Exceptions: muted --destructive for hard errors, traffic-light colors on the trip safety
briefing, functional categorical scales (maps, equality scores, password strength). Crisis and
safety pages are animation-free.
55 shadcn/ui primitives in src/components/ui/. ESLint enforces color, radius, spacing, shadow and
layout constraints. Full spec: docs/design-system/README.md.
robots.txt checked per domain (1h cache), Crawl-delay honored, ≥3s polite delays + jitter. No anti-bot bypassing, no CAPTCHA solving, no login-walled sources. Per-source kill switches via DISABLE_SOURCE_<NAME>=true.