DEV Community

yashraj jangir
yashraj jangir

Posted on AI-assisted

I Know a Spot: Small Discoveries, Open-Weight AI, and a Reason to Go Outside

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

I Know a Spot: Small Discoveries, Open-Weight AI, and a Reason to Go Outside

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

What I Built

Not every reason to go outside needs to be a famous landmark or a carefully planned trip. Sometimes it is a place nearby that you never knew existed: a carved doorway, a patterned wall, a quiet corner, or a small detail someone else noticed.

I Know a Spot is a mobile-first web app for sharing those small discoveries and finding somewhere worth seeing.

The idea is simple: notice → share → discover → go → mark explored.

Get to know your locality better, and when you travel, use the app to discover what other people have noticed.

A contributor takes or chooses a photo, adds a title and personal note, confirms a destination pin, and chooses who can see the spot. An explorer browses those discoveries, searches for what they feel like seeing, opens directions, and gets back to the real world.

There are two discovery feeds:

  • Connections: spots from you and your configured connections.
  • Public: spots within your saved discovery radius around an area you explicitly choose.

For this pilot, “Public” means visible to other authenticated, enrolled participants—not anonymous visitors. Public radius is a discovery preference, not a guarantee of privacy: an eligible participant can still open a known Public spot outside their selected radius.

The AI bridges the gap between how someone describes a place and how someone else searches for it. You can search by meaning instead of hoping a contributor used exactly the same keyword.

The app deliberately does not include likes, popularity rankings, public visit counts, or an endless engagement loop. Its main call to action is Open directions. “Explored” is a private, self-reported mark—not a GPS-verified achievement.

Demo

Deployed web app: I Know a Spot

Access note: I Know a Spot currently runs as an authenticated pilot. When a new user signs in with Google, the application automatically creates an enrolled membership for that Supabase Auth account. The backend still checks membership before granting access, and signing in again does not re-enable a disabled membership. There is no anonymous feed. The repository includes setup instructions for running the application with your own configuration.

Sign in with Google or email to start discovering overlooked places.

Suggested walkthrough

  1. Open Discover and switch between Connections and Public.

Browse recent spot discoveries shared by you and your connections.

  1. In Public, choose a discovery center manually or use the explicit current-location button.

Explore publicly shared spots around a selected area on the map.

  1. Change the saved radius in Profile and return to Public.
  2. Search for a description such as “somewhere tucked away with interesting textures.”

Find relevant spots by describing what you feel like seeing.

  1. Open a result, read the contributor’s access information, and launch external directions.
  2. Return and mark the spot explored.
  3. Add a new discovery with a photo, note, audience, and destination pin.

Share a photo, personal note, audience, and destination pin for a new spot.

I also took the project beyond local code checks. Phone testing, a real outing, searching real notes, and an authenticated walkthrough of the deployed application using Google sign-in were part of the build process. These are qualitative pilot observations, not a measured retention study or a controlled real-world search benchmark.

The frontend and backend are deployed over HTTPS. Deployment checks verified endpoint reachability and CORS, and I completed an authenticated walkthrough using Google sign-in on the final deployment. The deployed flow worked as expected.

Code

HackW1TouchGrass

I Know a Spot — application workspace

Mobile-web pilot with a later Capacitor path. See PRD.md, the 36-hour build plan, and future scope.

  • SETUP.md: manual install/environment/run/check commands.
  • SUPABASE_SETUP.md: user-run migration, account enrollment and live auth/RLS verification steps.
  • SPOT_SHARING_SETUP.md: user-run spot/private-Storage migration, backend-only admin configuration and live audience/media checks.
  • NEXT_FEATURE_PLAN.md: implementation handoff for the Public feed, saved-radius and manual discovery-area slice.
  • PUBLIC_DISCOVERY_SETUP.md: new Public-feed migration manual area/radius setup and user-run live boundary checks.
  • SEMANTIC_SEARCH_SETUP.md: MiniLM search, guarded searchable-spot SQL fixtures/cleanup and user-run checks; no new search migration.
  • SEMANTIC_SEARCH_EVALUATION.md: actual local MiniLM/HTTP synthetic comparison against keywords, with limits.
  • EXPLORED_SETUP.md: private self-reported explored state, new migration0004 and user-run persistence/authorization checks.
  • REPORTING_SETUP.md: private predefined reports, new migration0005 and protected local operator review/removal commands and checks.
  • API_CONTRACT.md: protected profile and spot/media API contract.
  • frontend/: React/TypeScript/Vite app (port 5173).
  • backend/…

Browse the source and setup instructions.

The project is split into a static-buildable frontend and an explicit backend API. Setup guides cover Supabase, sharing, Public discovery, semantic search, explored state, and reporting.

How I Built It

Open-weight AI at the center of discovery

The search model is Xenova/all-MiniLM-L6-v2, an Apache-2.0-licensed model running through Transformers.js in the Node backend.

The inference configuration is deliberately small and explicit:

  • Quantized q8 CPU inference.
  • 384-dimensional embeddings.
  • Mean pooling and normalization.
  • A 256-token input cap.
  • A pinned model revision with checksum-verified artifacts.

The encoder receives query text and spot titles and notes. It does not receive photos, coordinates, or member IDs as model inputs. Notes can still contain personal information, so minimizing structured inputs does not mean that all text is nonsensitive.

The search flow is:

Authenticated request
  → resolve eligible spots for the selected feed
  → apply Public radius filtering where applicable
  → embed query and eligible title/note text
  → rank by cosine similarity
  → revalidate eligibility and current text
  → return up to three existing spots
Enter fullscreen mode Exit fullscreen mode

Authorization and geographic eligibility happen before ranking. AI is not an access-control layer.

Results show the contributor’s original words. There is no generated claim that a place is safe, open, accessible, or a certain number of minutes away. A low-quality or unavailable search should produce an honest empty or error state, not an invented destination.

For this small pilot, bounded in-memory vectors and direct comparison are enough. I did not add a vector database or a generative chatbot just to make the architecture look more “AI.”

Testing whether semantic search adds anything

I compared the actual cached MiniLM model against a keyword baseline using a 12-query synthetic fixture, with synthetic authentication and candidate data rather than live Supabase records.

  • Of 11 positive queries, semantic search returned a relevant result in the top three for 11/11, compared with 7/11 for the keyword baseline.
  • One unrelated negative query returned no semantic matches.

That is useful regression evidence, but it is a small, purpose-built dataset—not proof of general search quality. The similarity cutoff remains provisional for real contributor notes. Real-note search was tried separately without a new quantified comparison.

The rest of the stack

Layer Technology
Mobile web UI React, TypeScript, Vite, Tailwind
Maps Leaflet / React Leaflet
API Node.js and Fastify
Photo processing Sharp
Auth, database, protected media Supabase Auth, Postgres, Storage
Frontend hosting GitHub Pages
Backend hosting Docker image in ECR, running on ECS Fargate behind an HTTPS Application Load Balancer

The model artifacts are included in the backend image. Requests never download weights, and inference runs on infrastructure I control rather than a separate hosted model API. This is server-side inference, not on-device or offline inference.

Disclosure: AI assisted with the project and with drafting this article.

What the difficult parts taught me

Mobile lifecycle matters. Returning from the phone camera could trigger a repeated Supabase SIGNED_IN event, causing the verified workspace—and the unfinished form—to remount. The fix ignores only an exact same-user, same-token duplicate event. Token changes, account changes, and explicit access checks still reverify access. This does not solve a browser discarding the entire page.

Visual polish can introduce real regressions. An early UI pass combined conflicting button color classes, leaving white text on a light background. Explicit primary and selected-state styles fixed that. The navigation also moved into a persistent bottom bar after testing made the long Add form’s bottom-only Cancel action inconvenient.

Container size is not model size. The first backend image was about 1.05 GB uncompressed even though its model artifacts were about 23 MB. ONNX runtime dependencies accounted for most of the footprint. I kept the working runtime intact rather than deleting binaries without a tested replacement.

The final runtime image was tested for non-root startup, health checks, actual normalized 384-dimensional embeddings, and Sharp WebP processing. The latest local backend test run passed 139 tests, and the frontend suite passed 67. These checks do not independently validate remote Supabase policies.

Current limits

This is an online-only, bounded pilot—not an unrestricted public platform. New Google Auth users receive an enrolled application membership automatically, while existing memberships are checked by the backend. Connections are configured by the operator, and the app does not yet include in-app connection requests.

Full browser-discard draft recovery is not implemented. Independent checks of all direct Storage and forbidden-write boundaries, exact radius boundaries, and media-erasure behavior remain outstanding. I am keeping those gaps visible rather than treating a successful deployment as a security audit.

Why Does Open Innovation Matter?

For this project, open innovation means being able to choose a small model, understand its role, and run it where it fits the product.

An open-weight encoder made it possible to:

  • Run inference in the backend container without sending every query and eligible note to a separate model provider.
  • Pin and verify the model artifacts, making the retrieval setup inspectable and repeatable.
  • Evaluate semantic ranking against a simple baseline, rather than treating a hosted model’s output as an unexplained recommendation.
  • Keep model choice replaceable, with explicit evaluation work required if I change models, tokenization, or embedding dimensions.
  • Avoid per-request model API charges, while still acknowledging that AWS hosting, storage, and networking cost money.

A closed embedding API could also rank text. The difference here is not that closed systems cannot do semantic search; it is that I can distribute and run the model artifacts, control the inference environment, and investigate retrieval behavior without depending on a remote model endpoint.

That control does not make the whole app private or offline. Supabase processes application data, and maps and external directions have their own data flows. It lets me make a narrower, defensible statement about where model inference happens.

The outcome I care about is not a longer AI conversation. It is someone finding one interesting place, closing the app, and going to see it.

My Agent Session

I built with assistance from omnirush.ai across implementation, debugging, UI iteration, testing, and deployment. The camera-return bug and deployment configuration were particularly useful examples of turning a broad symptom into a specific, testable change.

Community references

Two useful perspectives from DEV informed the UI and packaging work:

Top comments (0)