WallpaperMachine
The wallpapers you love. A new home on your Mac.
Your Personal Outdoor Intelligence Companion
Translation pending
LifestyleGitHub @meiyulin22OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
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 ↗Meri is a personal outdoor intelligence companion: a Next.js PWA where a Journey starts from one sentence of natural language and stays useful as the plan gets clearer.
The product goals and principles live in docs/PROJECT.md. The layer contracts and request flows live in docs/ARCHITECTURE.md. This file covers how to run the project and how to find your way around it.
The complete Chinese directory/layer and file guide lives in docs/CODEBASE_GUIDE.md. Detailed user operations, state changes, APIs, and failure boundaries live in docs/USER_FLOW_CURRENT.md. The database table/field directory and relationships live in docs/DATABASE_SCHEMA.md.
npm install
cp .env.example .env.local # then fill in the values below
npm run dev
Open http://localhost:3000.
Every variable is server-side only. None of them may use the NEXT_PUBLIC_
prefix, because that would ship the value to the browser.
Required:
| Variable | Used for |
|---|---|
MOONSHOT_API_KEY | The LLM behind conversation, extraction, and recommendation |
DATABASE_URL | Neon Postgres connection string |
TIANDITU_API_KEY | Tianditu, the national map platform, which validates that a destination really exists and suggests places as you type |
Optional. Recommendation degrades without it rather than failing:
| Variable | Missing means |
|---|---|
BOCHA_API_KEY | Recommendations are generated without discovery search context; access checks and image enrichment are not connected to the current workflow |
The remaining variables in .env.example override defaults:
LLM_MODEL, MOONSHOT_BASE_URL, MERI_TIMEZONE, LLM_DEBUG_OUTPUT, and
LOG_LEVEL.
Meri verifies places with Tianditu. Amap was removed in 1.0702: its free tier for
individual developers ends a year after sign-up and a public deployment needs a paid
licence. Tianditu has no popularity signal — it ranks same-named places by text, so
苍山 may lead with the village in 广西 rather than the mountain in 大理 — and it has no
photo API. Cards and covers use the reviewed catalog in public/photos, and
recommendation cards the catalog misses may be filled at run time from Wikimedia
Commons and, with PIXABAY_API_KEY, Pixabay; those downloads are kept in
MERI_MEDIA_DIR (required in production, outside the release directory and kept across
deploys; development falls back to .cache/media), capped by MERI_MEDIA_MAX_BYTES
(default 500 MB).
The block near the end of .env.example (QWEATHER_API_KEY, QWEATHER_API_HOST,
TUNIU_API_KEY, ROLLINGGO_API_KEY) holds keys Generate plan is planned to use; the
app does not read them yet.
npm run lint
npm run typecheck
npm test
npm run build
npm test runs every *.test.ts and *.test.tsx file under src/ through the
Node test runner. Tests sit next to the code they cover.
Database schema changes go through Drizzle Kit:
npx drizzle-kit generate
npx drizzle-kit migrate
Each top-level directory answers one question.
docs/ Product and architecture documents
src/app/ What the URLs are: App Router pages and route handlers
src/components/ What the screen looks like: React components
src/domain/ What Meri's concepts are: pure types and validation, no IO
src/capabilities/ What Meri can do: one directory per capability
src/agents/ What Meri decides for itself: Mastra agents and their tools
src/platform/ How Meri talks to the outside world: ports and adapters
Two rules hold the layers apart:
src/domain/ performs no IO. It defines Trip, TripState, TripDraft, and
the certainty of each field (known, approximate, ambiguous, missing),
and it validates anything arriving from outside. It never calls a network or a
database.src/platform/ implements external integrations. Application services use
ports and normalized results; production factories and some route handlers
assemble the concrete adapters. Browser components also request Meri's own APIs.
Provider-specific HTTP/SDK handling belongs in adapters, not domain rules.src/capabilities/ is named after what the code does, not where it runs, and
holds one directory per capability, so a whole flow reads top to bottom in one
place. It contains no React components.
src/capabilities/journey/ Creating, loading, and updating a Journey
src/capabilities/conversation/ Interpreting a Workspace message and wording the reply
src/capabilities/destination/ Confirming a destination names a real place
src/capabilities/recommendation/ Turning preferences into validated, province-filtered suggestions
src/agents/ holds the parts that choose their own next step. A capability is a
fixed flow written in code; an agent gets a goal and tools and decides which tool
to call from what the last call returned. Its tools are thin wrappers over
src/platform/ ports, and nothing an agent produces is saved before code has
validated it. Today it holds a trial agent; the Planner behind Generate plan is
designed in src/agents/README.md.
src/platform/llm/ Structured-output port, Moonshot adapter
src/platform/location-provider/ Location and suggestion ports
src/platform/tianditu/ Tianditu place check and input tips
src/platform/search/ Search ports, one shared Bocha Web Search
request and the Discovery Search adapter
src/platform/persistence/ Repository ports at the top, with the Postgres
and in-memory adapters and the Drizzle schema
beneath them
src/platform/identity/ Guest identity
src/platform/observability/ Logger and error serialization
This is the beginning of the README. Read the rest at the original. Read the full README ↗