Fujimod
Try your camera firmware in the browser and build Fujimod SD boot files.
Explore nearby adoptable pets on a map, check listing sources, and compare disclosed needs with your home and routine.
LifestyleJavaScript · PythonGitHub @leancoderkavyOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
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
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Pawline combines authorized adoption feeds and moderated community submissions.
Pawline's read-only MCP server exposes current pet search, adoption-source status, and service health to compatible AI clients:
npx -y pawline-mcp
See mcp/README.md for client configuration and capability
boundaries. Availability is time-sensitive and must be confirmed with the
linked shelter.
Check 25 shelter websites for adoption pages and potential feed links:
python scripts/ingest.py --discover > discovery-results.json
Discovery needs no database credentials and does not import pets. It checks each
homepage, respects robots.txt, bounds page size and request time, and reports
errors per site so one unavailable website does not stop the others. The site
list is in scripts/discover.py. Results include deduplicated adoption_links
and feed_links; feed candidates may be calendars or embedded listing services,
not usable pet feeds. Review permission, content, and field mappings before
enabling an import. This is a manual command; scheduled ingestion is unchanged.
Install python -m pip install -r requirements.txt. The CLI loads the ignored
.vercel/.env.listing-review and .env.local files, preserving shell overrides.
It accepts AI_GATEWAY_API_KEY or the project's VERCEL_OIDC_TOKEN and uses
the operating system certificate store for HTTPS. On Windows, refresh the
short-lived project token and run a review with:
./scripts/review-pets.ps1 -MaxPages 25
./scripts/review-pets.ps1 -ListingUrl https://your-shelter.example/adopt/pet-id
The wrapper requires an authenticated Vercel CLI account and Node.js with
--use-system-ca support. It refreshes credentials without changing .env.local.
Alternatively, with a current token or API key configured, run Python directly:
python scripts/ingest.py --discover --llm --max-review-pages 25 > listing-reviews.json
python scripts/ingest.py --review-url https://your-shelter.example/adopt/pet-id
The first command reviews discovered adoption pages across shelters in round-robin
order. The second checks a specific pet page; repeat --review-url for more pets.
These commands make billable AI Gateway requests, capped at 25 pages by default
(configurable from 1 to 100). Override the model with PAWLINE_LISTING_REVIEW_MODEL.
Project OIDC tokens expire after 12 hours; rerun the PowerShell wrapper to refresh.
Each review reports pet name, listing validity, legitimacy signals, pet status,
and an explicit source last-updated date, with supporting page quotes. Missing
status is unknown; missing dates are null. checked_at is the scraper's check
time, not the shelter's update time. Quotes and names are checked against the
supplied text; this cannot establish that a model interpreted them correctly.
Legitimacy is an on-page assessment, not independent verification. All results
require review and never automatically change a pet's database status.
Reviews honor robots rules, validate redirect destinations, limit page text to
12,000 characters, and exclude scripts/styles. JavaScript-only listings may not
be visible. At most 30 pets are extracted per page; this is a bounded review,
not a complete shelter inventory. Fetch/model failures are review_error, never
evidence that a pet was adopted. The model has no browser or action tools.
LLM reviews share a persistent local ledger at
.vercel/listing-review-usage.sqlite3 across CLI runs in this checkout:
reviewed_at; checked_at records the current page check.Retry-After values. Limits and cooldowns return deferred.Keep the ledger to preserve limits. These controls cover this local checkout,
not other projects or machines using the same Gateway account, and cannot
guarantee the provider never returns 429. Historical calls made before the
ledger was introduced are not included. Control constants live in
scripts/review_usage.py. No paid calls are needed to run the usage tests.
npm run db:migrate:dry-run to parse the local schema and verify required migration artifacts without opening a database connection, then create a Postgres database and run db/schema.sql.db/public_sources.sql to install the reviewed Montgomery
County and King County definitions. Reviewed public feeds are enabled by
that migration.DATABASE_URL and a random CRON_SECRET in Vercel.sources with enabled = false.parser_config.mapping; JSON feeds
may also set records_path.Example parser configuration:
{
"records_path": "animals",
"mapping": {
"external_id": "id",
"name": "name",
"species": "species",
"breed": "breed",
"city": "location.city",
"country": "location.country",
"image_url": "photo",
"source_url": "adoption_url"
}
}
Parser configurations may also use constants, per-field value_maps, and
strip_html_fields. See db/public_sources.sql for reviewed examples.
Vercel calls /api/cron/ingest four times daily (00:00, 06:00, 12:00, and
18:00 UTC). The Python importer accepts
authorized HTTPS JSON, CSV, and published Google Sheet CSV feeds; it does not
scrape HTML. It sends conditional requests, limits response size, rejects local
network destinations, records each run, and upserts duplicate records.
Pet imports require an explicit, valid image URL. Missing, blank, malformed, and
non-web image values are skipped before database writes in both scheduled feed
importers; shelter CSV imports report those rows as errors. Legacy HTTP image
links are normalized to HTTPS for the production image policy. Events are
unaffected. This validates supplied photo URLs, not remote image availability;
an upstream host can still remove a photo later. Existing records are not purged.
Listings missing from two consecutive successful, non-empty snapshots are
marked unavailable; disappearance is never treated as proof of adoption.
Community submissions use /api/submissions and remain pending until a
reviewer changes the record to available and sets verified_at.
Pawline is a mobile-friendly pet adoption discovery app for finding adoptable dogs and cats, browsing nearby organizations on a map, viewing adoption events, and submitting community listings.
The discovery screen includes a seven-question lifestyle quiz covering home
type, activity level, children, existing pets, time alone, adopter experience,
and species preference. Matching is deterministic and runs in
src/matching.js; it does not make adoption decisions.
Each result separates:
Scores are an ordering aid, not a guarantee. Pawline never fills missing listing attributes with generated claims, and it links back to the shelter for current availability and final adoption decisions.
After the quiz, adopters can explicitly request a bounded AI compatibility draft. The server sends only quiz answers and public listing facts through Vercel AI Gateway; contact information, account data, and medical records are excluded. AI output is independently validated, capped below a perfect score, and presented as questions and evidence to review with the shelter—not an adoption decision or compatibility guarantee.
The scheduled importer also refreshes Pasadena Humane's official dog-adoption calendar four times daily. Upcoming events are listed with their source links, and live event coordinates appear alongside geolocated pets on the map.
npm install
npm run dev
npm run build
Copy .env.example to .env.local for local development. All provider
credentials stay in server-side Vercel functions; do not prefix them with
VITE_.
/api/pets reads two credential-free official feeds directly:
ADOPTABLE.Both adapters retain official shelter attribution and source links, accept only dogs and cats, normalize provider fields, and return partial/error status when a feed is unavailable. No synthetic fallback records are returned.
The server-side adapter at /api/pets uses the RescueGroups v5 public API.
Request one API key specifically for Pawline, accept the provider terms, and set:
RESCUEGROUPS_API_KEY
Without the key, the government feeds remain active and RescueGroups is omitted from the provider list.
Create a Neon Postgres database, run db/schema.sql, and set:
DATABASE_URL
CRON_SECRET
Community submissions remain private and pending until manually verified.
Only events with status = 'published' and pets with status = 'available'
plus a verified_at timestamp are returned publicly.
Create a URL-restricted Mapbox access token and set:
MAPBOX_ACCESS_TOKEN
Pawline proxies geocoding and static-map requests through server-side routes so the token is not shipped in the Vite bundle. Geocoding is temporary and results are used for the current search session; do not persist coordinates unless the Mapbox account and request are configured for permanent geocoding.
Verify a sending domain in Resend, create a sending-only API key, and set:
RESEND_API_KEY
PAWLINE_FROM_EMAIL=Pawline <[email protected]>
[email protected]
Each accepted submission triggers an internal review alert and a submitter acknowledgement. Email delivery failure is logged but does not discard the saved submission.
The List a Pet flow accepts multiple PDF, TXT, JPG, PNG, and WebP files (3 MB
combined). /api/extract-submission sends those files through the Vercel AI SDK
and AI Gateway to create an editable draft from directly supported facts.
Submitters must review the draft and attest to their authority, complete
medical/behavior disclosure, and local transfer-law compliance before the
listing is saved.
Uploaded records are stored in pet_submission_files; they are not public.
Only the selected primary photo becomes readable after moderators change the
pet to available. pet_submission_log records submission and AI-extraction
events. Apply db/schema.sql before enabling the flow. AI Gateway uses Vercel
deployment OIDC when available, or AI_GATEWAY_API_KEY outside that environment.
GET /api/health reports the two active public feeds and whether RescueGroups,
Neon, Mapbox, Resend, and the scheduled importer are configured without
exposing credentials.
Scheduled web search and AI SEO research are disabled. /api/discoveries
returns no web leads, and new SEO jobs cannot be queued. Existing web-lead
rows and private SEO review records remain in storage; an authorized operator
can still retrieve an existing SEO job with GET /api/seo-pipeline?job=JOB_UUID.
No old web leads are shown in the public discovery map. Official pet feeds,
shelter directory entries, and their existing import schedules continue.
Scheduled web discovery can queue recent public adoption-page leads for private operator review. The shelter workflow sends only the stored public title, snippet, HTTPS source URL/domain, city, and species hint to AI Gateway. It extracts a cited review record for these data points: organization, official domain, location, adoption/listing/feed URLs and format, dog/cat coverage, freshness evidence, terms, attribution, and any public contact information. It does not browse new pages, infer missing data, verify a shelter, activate a source, publish a listing, or send email automatically.
Apply db/schema.sql, then set these server-only values. Keep both enable flags
unset or false during setup; they are independent from the administrator
secret so a leaked review credential cannot enable paid AI calls or email.
SHELTER_OUTREACH_SECRET
SHELTER_OUTREACH_MODEL=google/gemini-2.5-flash-lite
SHELTER_OUTREACH_MONTHLY_MAX_GENERATIONS=10
SHELTER_OUTREACH_DAILY_EMAIL_LIMIT=20
SHELTER_OUTREACH_AI_ENABLED=false
SHELTER_OUTREACH_SEND_ENABLED=false
The private /api/shelter-outreach endpoint requires
Authorization: Bearer $SHELTER_OUTREACH_SECRET. Queue candidates with
{"action":"queue-discoveries"}. For one candidate, explicitly confirm
consentToAiProcessing: true before the enrich action. A human must then
record a reviewed contact email and an official-domain contact-source URL with
the approve-draft action. The resulting email is still unsent; send-email
additionally requires the exact sendConfirmation value and
SHELTER_OUTREACH_SEND_ENABLED=true.
Each send has a bounded daily limit, an internal outbox row, and a stable Resend idempotency key. If delivery is uncertain or rejected, Pawline leaves the draft for human review rather than retrying or sending a follow-up automatically. Register delivery webhooks separately before relying on delivery or bounce state as proof of receipt.
Adopt-a-Pet is intentionally not enabled by default. Its API requires a signed partnership agreement, provider approval of the implementation, shelter notice, and required attribution. Ticketmaster is also not used as an adoption-event source: keyword matches do not establish that an organizer is authorized or that an event is actually an adoption event.
The adoption platform adds canonical organizations, locations, hours,
memberships, claim tokens, verification events, and a nullable organization_id
on pets and sources. Existing shelter names are never automatically merged.
Claim links are 32-byte random values stored only as hashes, expire in seven
days, bind to the recipient's verified Clerk email, and are consumed atomically
with the administrator membership. Set PAWLINE_CANONICAL_ORIGIN to the
canonical HTTPS site; claim URLs never use a request Host header.
/api/resend-webhook is a dedicated raw-body Next route. Set
RESEND_WEBHOOK_SECRET and configure Resend to send email.sent,
email.delivered, email.bounced, and email.complained. Events are replay
safe by Svix delivery id. Bounces and complaints suppress that recipient
globally. Opt-out links remain activation-blocked until their signed endpoint
is implemented. This implementation creates reviewed outbox records only;
it does not authorize production shelter outreach or a provider send.
Draft and held applications remain private. A claimed organization can only
read a submitted application after the adopter selects the exact fields to
share. Held unclaimed-organization data requires explicit consent and must be
purged by the protected daily /api/cron/purge-held-applications job after its
30-day hold window. When the pet is already linked to an unclaimed canonical
organization with a reviewed HTTPS site and same-domain public contact address,
Pawline queues only a deduplicated, suppressed-aware invitation-needed
outbox record. It does not mint a claim link or send mail at application
creation. If the organization/contact is absent or insufficiently verified,
the application response truthfully reports manual_contact_required; shelter
name strings are never auto-merged.
/api/organization-reviews is a conservative review foundation. An adopter
can create one verified review only from their submitted, organization-linked
application; it enters pending moderation and is never publicly visible by
default. The public endpoint returns only published, verified reviews. An
organization administrator may make one safety-filtered reply to a published
review or file an appeal for Pawline moderation. Organization workspaces never
receive pending or rejected reviewer narratives; they can see only published
reviews and an appealed review that was previously public. The protected
/pawline-moderation/reviews route is available only to the verified Clerk
email configured in PAWLINE_MODERATION_EMAIL, and may publish or reject a
pending/appealed review. Evidence uploads and evidence access remain unavailable
until isolated evidence storage is separately authorized.
The application coach and intake summary are optional, structured, suggest-only helpers. To make any private task available, set every server-only control below after an evaluation and privacy review:
OPENROUTER_ENABLED=true
OPENROUTER_LIVE_CALLS_ENABLED=true
OPENROUTER_API_KEY=...
OPENROUTER_ZDR=true
OPENROUTER_DATA_COLLECTION=deny
OPENROUTER_ALLOWED_MODELS=one-reviewed-model
OPENROUTER_ALLOWED_PROVIDERS=one-reviewed-provider
OPENROUTER_APPLICATION_COACH_MODEL=one-reviewed-model
OPENROUTER_INTAKE_SUMMARIZER_MODEL=one-reviewed-model
Every task model must be in its immutable allowlist and cannot be
openrouter/auto. Requests use a fixed provider allowlist, disable fallbacks,
require supported parameters, set data_collection: "deny", and set zdr: true. Pawline stores metadata only: task, request id, prompt/schema version,
model/provider, latency, and token counts—never prompts, answers, messages,
documents, addresses, or contact details. Durable subject, organization, and
global limits run before any request.
This checkout has AI SDK 7 but not the official
@openrouter/ai-sdk-provider package in its lockfile. The disabled-by-default
server transport therefore uses OpenRouter's documented structured
chat-completions request shape. Before enabling production spend, add the
reviewed official adapter, preserve the same no-fallback/ZDR contract, and
rerun the frozen task evaluations. The server rejects invalid structured output,
uncited summary assertions, and decision language; AI cannot score, rank,
approve, decline, or act on an application.
Open Messages → Listing chats (/#messages). Adopters can start a thread
from the Message button on an available, verified Pawline pet. Shelter staff
can also open the inbox from Shelter workspace → Adoption questions. The
inbox includes search, unread/open/resolved filters, and a Shelter inbox filter.
Each conversation has paginated history, per-person unread counts, draft text
while switching conversations, retry-safe sends, reporting, resolve/reopen, and
block/unblock controls. Drafts remain in memory and clear when the user leaves
Messages or signs out; messages persist in PostgreSQL.
Canonical pets.organization_id links and current organization_memberships
give a shelter team access to its conversations. A shelter name alone never
grants access. Available, verified listings without a canonical organization
continue to use their individual claimed owner. Team membership is rechecked
on every API request, including reporting and video signaling. Removed team
members lose access even if they originally owned the thread. Migration only
shares legacy owner threads where that owner already belongs to the pet's
explicitly linked organization.
/api/direct-conversations, /api/direct-messages, /api/direct-message-report,
and /api/direct-video require verified Clerk bearer tokens and a migrated
database. Direct messages retain the existing moderation rules and durable
rate limits. Message creation requires a UUID clientMessageId; clients reuse
it when retrying the same send. Newest messages load first in pages of 60, with
a before UUID cursor for older history. The inbox returns up to 200 recent
conversations. PATCH /api/direct-conversations supports read (with the last
visible messageId), resolve, reopen, block, and unblock. Blocking pauses
both messages and calls; only the account that blocked can remove its block.
Ably is optional for listing chat. With ABLY_API_KEY, the server publishes
content-free invalidations to each participant's private channel; the client
reloads through authenticated APIs. Five-second polling while Messages is
visible provides a fallback and picks up missed events/new inquiries. No email,
push, or background ringing is sent. Arrange a time in chat and keep Messages
open to receive an incoming video invitation.
Video calls are one-to-one, scoped to the conversation, and require explicit acceptance. Either side can invite; a single shelter staff member can accept. The camera/microphone stay off until Preview devices is selected. The user then chooses Start call or Accept and join. Controls include mute, camera off, decline, cancel, and hang up. Leaving closes the peer connection and stops media tracks. The server expires unanswered invitations after 90 seconds (or a 45-second caller heartbeat timeout), disconnected accepted calls after 45 seconds, and all calls after one hour. Pawline does not record media. Only the caller and accepted recipient can access SDP/ICE signaling; other shelter staff can see call status. The implementation follows the browser WebRTC API.
Before enabling production:
npm run db:migrate:dry-run, then apply npm run db:migrate against the
intended database as a reviewed migration. The migration is idempotent and
request handlers never create tables. Deploy schema before application code.
Check /api/health: directMessagingConfigured reports credentials, while
directMessagingReady confirms required chat tables and columns exist.CLERK_SECRET_KEY, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, and the
authorized origins. The local test fixture does not exercise live Clerk.PAWLINE_CLOUDFLARE_TURN_KEY_ID and PAWLINE_CLOUDFLARE_TURN_API_TOKEN.
Pawline requests 65-minute credentials when each participant joins and uses
relay-only ICE. The long-lived API token never reaches the browser. As an
alternative, configure a coturn-compatible relay with PAWLINE_TURN_URLS
(comma-separated turn:/turns: URLs) and server-only
PAWLINE_TURN_SHARED_SECRET. The coturn relay takes precedence if both are
configured. TURN service billing and usage monitoring remain provider tasks.PAWLINE_VIDEO_ENABLED=true only after testing the provider over separate
networks. PAWLINE_VIDEO_ALLOW_DIRECT=true is for local development and is
ignored in production. With missing provider configuration, chat stays usable
and the Video call action explains that calling is unavailable. If credential
issuance fails, no call invitation is created.CRON_SECRET and ensure /api/cron/purge-video-signals runs every
15 minutes as specified in vercel.json. Hangup/block/resolve delete signaling
immediately; session reads remove expired signaling too. The scheduled job
handles abandoned sessions. Signals older than 70 minutes are deleted on the
next job, so worst-case scheduled retention is approximately 85 minutes.
Call status metadata remains for the conversation's recent-call history./api/health exposes configuration booleans for direct messaging and video;
these do not prove that the database is migrated or the relay works.
Validation:
npm test includes real PostgreSQL integration tests using disposable PGlite
storage and the production handler factories. No production DB writes occur.npm run test:chat runs the actual chat components and handlers on a loopback
fixture server, with two isolated users and Chromium simulated media devices.
It exercises persistence, mobile interaction, moderation, unread counts,
failure recovery, and actual WebRTC media between two browser contexts.
Install Chromium with npx playwright install chromium if needed. Traces and
screenshots are written to the OS temporary directory.e2e/; the production app
imports neither that resolver nor its database. No auth bypass is enabled by
an environment flag. Live Clerk, Ably, and cross-network TURN checks remain
separate deployment checks.Run npm run build followed by npm run test:app to test the built application
at 320, 390, 768, and 1440 pixels. Install Chromium once with
npx playwright install chromium. The suite starts an isolated local server
on port 3112 and intercepts API requests with explicitly named QA fixtures.
It does not send messages, submit applications, or call paid AI providers.
Coverage includes map species/radius/hours filters, saved-pet persistence and corrupt storage recovery, listing/event/lead/shelter details and source links, visit checklist mouse and keyboard controls, location validation/autocomplete, provider failure recovery, quiz navigation and consent gates, profile fields, private guest application drafts, menu navigation, and legal links.
Run npm run test:chat separately for the authenticated fixture messaging and
WebRTC workflows. CI runs both browser suites after the production build.
Screenshots and failure traces are written to the system temporary directory.
These tests do not establish live Clerk login, live shelter form submission,
Mapbox tile delivery, or cross-network TURN/provider readiness.