The backend is not remote: apps/web is a Next.js 16 app with the API routes, better-auth, and a Neon Postgres data layer. Document the data model, the mobile<->web API contract, and the missing /api/logs route.
7.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
A time-tracking app for insole (orthotics) production, built on the "Create" / Anything AI platform and exported to run locally. The UI is in Dutch. A worker picks an insole type (Type zool: Kurk / Berk / 3D), a handling/task (Type handeling), and a count (Aantal zolen, default 2), then runs a stopwatch (start / pause / stop & save / double-press discard). The History tab lists past sessions and exports CSV; the Settings tab manages handelingen per zooltype.
It is a two-app monorepo, not frontend-only — the backend lives in apps/web:
apps/mobile— the Expo Router app (iOS / Android / web client). This is what the user runs on their phone via Expo Go / EAS builds.apps/web— a Next.js 16 app that serves the backend HTTP API (/api/*), authentication, and a near-empty web UI. The mobile app talks to it overEXPO_PUBLIC_BASE_URL. In production it is the deployed*.created.appsite.
The database is Neon serverless Postgres, reached only from apps/web via DATABASE_URL.
Layout
Yarn 4 (Berry) monorepo, node-modules linker. Workspaces = apps/* → apps/mobile and apps/web.
publisher/is NOT a workspace — it's a standalone OpenNext + AWS S3 tool (its ownyarn.lock) for building/deployingapps/web. Rarely touched.
Backend: API + data model
API routes live in apps/web/src/app/api/. The DB layer is apps/web/src/app/api/utils/sql.ts — a Neon tagged-template sql\...` (parameterised; interpolations are bind params, not string concatenation). Auth is **better-auth** (apps/web/src/lib/auth.ts): cookie sessions for web, Authorization: Bearer for mobile (token from/api/auth/token`).
Schema, reverse-engineered from the queries (no migrations file ships in the repo):
production_tasks—id,name,insole_types text[](subset ofKurk/Berk/3D)time_logs—id,task_id(FK → production_tasks),start_time,end_time,duration_seconds,pair_count,insole_type,notes
API surface the mobile app expects vs what apps/web provides:
| Endpoint | Method | Used by mobile | Exists in apps/web |
|---|---|---|---|
/api/tasks |
GET, POST | yes | ✅ api/tasks/route.ts |
/api/tasks/:id |
PUT, DELETE | yes | ✅ api/tasks/[id]/route.ts |
/api/logs |
GET, POST | yes | ❌ MISSING |
/api/export |
GET (CSV) | yes | ✅ api/export/route.ts |
/api/session, /api/auth/* |
— | (auth plumbing) | ✅ |
⚠ Known gap: /api/logs is missing
The mobile app reads the History list (GET /api/logs) and saves a finished session (POST /api/logs), but no such route exists in apps/web — only the CSV /api/export. Against this local backend, Stop & Save and the History tab 404. (The deployed *.created.app instance presumably has it; it just wasn't in this export.) Contract to rebuild it from the callers:
POST /api/logsbody:{ task_id, start_time (ISO), end_time (ISO), duration_seconds, pair_count, insole_type }GET /api/logsreturns an array of{ id, task_name (join on production_tasks.name), start_time, duration_seconds, pair_count, insole_type }, and (for parity with export) ideallyend_time, ordered bystart_time.
Commands
Run from the repo root unless noted. The root has no start/lint/test scripts — invoke the tools directly.
yarn install # install everything (Yarn 4)
npx oxlint # lint (config: .oxlintrc.json) — the real linter
npx oxfmt # format (config: .oxfmtrc.json) — 2-space, single-quote, semi, width 100
# Mobile (apps/mobile)
cd apps/mobile && npx expo start # dev server; press a/i/w or scan QR with Expo Go
cd apps/mobile && npx expo start --web # web target only
cd apps/mobile && npx tsc --noEmit # typecheck (strict; @/* -> src/*)
cd apps/mobile && yarn jest # tests (jest-expo); add a path or -t "name" for one
cd apps/mobile && eas build --profile <development|preview|production> --platform <android|ios>
# Web / backend (apps/web)
cd apps/web && yarn dev # Next.js dev on http://localhost:4000
cd apps/web && yarn build # next build (publisher wraps this for deploy)
cd apps/web && yarn typecheck # tsc --noEmit (next.config.js ignores TS errors at build time!)
cd apps/web && npx vitest # tests (vitest + jsdom)
eslint/typescript-eslintare in devDeps but there is no eslint config in the tree — use oxlint, not eslint.
Environment
Secrets are gitignored (.env). Mobile env is apps/mobile/.env (EXPO_PUBLIC_*): EXPO_PUBLIC_BASE_URL points the client at the web backend; EXPO_PUBLIC_PROJECT_GROUP_ID/HOST feed the patched global fetch. Web needs DATABASE_URL (Neon), plus BETTER_AUTH_URL and the trusted-origin URLs for auth. EXPO_PUBLIC_CREATE_ENV (PRODUCTION/DEVELOPMENT) + __DEV__ gate analytics, Sentry, the in-app "anything-menu", and dev-only native module stubs.
Architecture notes (mobile)
- Routing: Expo Router, file-based under
apps/mobile/src/app/._layout.tsxgates render onuseAuth().initiate()+isReady(loads the persisted session first) and provides the React Query client.(tabs)/holdsindex.tsx(Stopwatch),history.tsx(Geschiedenis),tasks.tsx(Instellingen). - Entry points split by extension. Native:
index.tsx→entrypoint.ts→App.tsx. Web:index.web.tsx→App.web.tsx(adds the Create sandbox-iframe plumbing — postMessage handshake, navigation sync, screenshot, healthcheck). - Global
fetchis monkey-patched.src/__create/polyfills.tsswapsglobal.fetchforsrc/__create/fetch.ts, which rewrites first-party (/api/...) URLs ontoEXPO_PUBLIC_BASE_URL, injects project/host headers, and attaches the SecureStore JWT. App code callsfetch('/api/...')and relies on this. - Web support is Metro module aliasing, not separate code.
apps/mobile/metro.config.jsresolveRequestswaps many native modules for stubs inpolyfills/web/whenplatform === 'web'. Adding a native dependency imported on web requires a web polyfill alias here, or the web build breaks. - Styling: NativeWind/Tailwind config extends
@anythingai/app/tailwind.config, but screens mostly use React NativeStyleSheet/inline styles. Inter font.
Conventions & gotchas
- Do not edit platform-managed files. Files under
apps/mobile/__create/andapps/mobile/src/__create/, the auth files inapps/mobile/src/utils/auth/, andapps/web/src/lib/auth.tscarry⚠ ANYTHING PLATFORM — DO NOT REWRITEheaders. They define the auth surface (signIn/signUp/signOut/auth/isAuthenticated/isReady), the fetch/sandbox plumbing, and the better-auth config (bearer plugin, name backfill, trusted origins,sameSite:'none'cookies). Rewriting them breaks auth or the Create preview.apps/mobile/src/app/_layout.tsxis editable except the<AuthModal />render and theinitiate()+isReadygate. - Do not bump patched dependencies.
react-native,expo-router,expo-store-review,react-native-purchases(-ui),@expo/cli,@react-native-community/netinfo, etc. usepatch:entries backed by.yarn/patches/, pinned further by rootresolutions/overrides. Upgrading discards the patch. When runningnpx expo install --fix, skip anypatch:package. - This is an exported template: versions are pinned exact (no
^) deliberately; prefer minimal, targeted changes.