# Insole Production Time Tracker — Rebuild Roadmap & Project Overview - **Created:** 2026-06-17 - **Status:** Approved — living project doc; Phases 0–2 implemented (`docs/plans/phase-2-accounts-roles.md`) - **Type:** Greenfield rebuild of an inherited app - **Tracked in git** under `docs/` (the project's documentation source of truth). > **2026-06-17 — Legacy code removed.** The inherited Create/Anything export > (`apps/mobile`, `apps/web`, `publisher/`) was deleted in a full cleanup. The repo is now > a single-service backend (`apps/api`) plus `packages/shared`. Reference for the old code > is preserved in `docs/reference/` and in git history. The sections below describe the > codebase _as inherited_ and the rebuild plan; treat references to the legacy apps as > historical. --- ## 1. Context The codebase was inherited as an export from the **Create / Anything AI** platform — a working time-tracking app for **insole (orthotic) production**, originally built by a friend through a chat-driven workflow. It arrived with no history, no documentation, and no clarity on what was complete or where the backend/data lived. Reverse-engineering established: - It is a **two-app monorepo**: `apps/mobile` (Expo/React Native) + `apps/web` (Next.js 16 backend on Neon Postgres). Plus `publisher/` (deploy tooling). - It is **heavily coupled to the Create platform**: "do-not-edit" platform files, patched dependencies, a web-sandbox iframe layer, and ~80 dependencies for what is functionally a stopwatch. - **Auth** is `better-auth` (email+password, argon2 hashes, bearer tokens for mobile, cookies for web), but the core flow does not actually require login. - **The data and accounts are not ours.** Users, password hashes, and all task/time data live in the platform's managed Neon Postgres, bound to the friend's Create account/organization. This repo contains only the _code_ and an `ANYTHING_PROJECT_TOKEN` — no database credentials. Nothing runs locally and no database is reachable from this code. Work already done this session (committed): - Git repository initialised; baseline + doc corrections committed. - Found and fixed `/api/logs` — it was both git-ignored (an over-broad `logs` rule) and broken at runtime (missing its `import sql`). That route is History + Stop&Save. - Wrote a reverse-engineered `schema.sql` (no migration shipped). - Installed dependencies (~1.7 GiB) and confirmed Docker is available. > The existing code is treated as a **working reference / seed**, not the foundation. ## 2. Vision A **multi-user, backend-driven shop-floor time-tracking system**. The phone is one of several clients, not the source of truth. A worker, on **their own phone with their own account**, logs in → goes to a workbench → **scans it (QR) or selects manually** → picks the activity → times the work → ends it → it is saved → repeats. Because the **backend is the source of truth**: - An active session lives **server-side**, so if the phone dies the worker can **end or log the work from a computer** instead. - There is a **manual-entry fallback** wherever something can fail. - An **admin panel** shows live who-is-working-on-what, generates reports, and manages users and activities. Goals: it must **genuinely work in the workshop** (reliability, no data loss) _and_ serve as a **learning vehicle** the owner extends himself. ## 3. Decisions (resolved during brainstorming) | # | Decision | Choice | | --- | --------------------- | ---------------------------------------------------------------------------------------------------- | | 1 | Purpose | Real workshop tool **and** a learning vehicle | | 2 | Platform relationship | **Clean break** from Create/Anything | | 3 | Hosting | **Dockerized** stack; runs locally now, portable to any cloud later | | 4 | Build strategy | **Greenfield rebuild**, porting only the good parts | | 5 | Backend topology | **Dedicated backend service** (Option A): single owner of auth + DB; UIs are interchangeable clients | | 6 | Auth | **better-auth** (don't hand-roll security for real use) | | 7 | Database | **SQLite** (small userbase; one file, easy backup/Docker) | | 8 | Language | **TypeScript everywhere** so types flow end-to-end | ## 4. Architecture ``` ┌─────────────┐ ┌─────────────┐ │ Mobile app │ │ Admin web │ clients — UI only, no DB access │ (Expo/RN) │ │ (React SPA) │ └──────┬──────┘ └──────┬──────┘ │ HTTP (Bearer) │ HTTP (cookie/Bearer) └─────────┬─────────┘ ▼ ┌──────────────────┐ │ Backend service │ the ONLY thing that touches auth + DB │ better-auth + │ │ business logic │ └────────┬─────────┘ ▼ ┌─────────┐ │ SQLite │ single file on a Docker volume └─────────┘ ``` **Auth flow** - **Mobile** — native email+password screen → `POST /api/auth/sign-in/email` → backend returns a bearer **token** → stored in Expo SecureStore → sent as `Authorization: Bearer ` on every request. (Drops the current app's embedded login WebView.) - **Admin** — standard better-auth **session cookies**. - **Backend** — mounts better-auth, owns all DB access, enforces roles. ## 5. Tech stack (recommended picks, approved) | Layer | Pick | Notable alternative | | ---------------------- | -------------------------------------- | ----------------------------- | | Backend framework | **Hono** | Fastify | | Auth | **better-auth** | — | | DB access + migrations | **Drizzle ORM** | Kysely / Prisma | | Database | **SQLite** | libsql/Turso (if cloud later) | | Admin UI | **Vite + React** (SPA) | Next.js (if SSR wanted) | | Mobile | **Expo / React Native** | — | | Shared contracts | **`packages/shared`** (TS types + zod) | — | ## 6. Monorepo shape ``` apps/ mobile/ Expo worker app (client) admin/ Vite + React panel (client) api/ Hono + better-auth + Drizzle + SQLite (backend service) packages/ shared/ TS types + zod schemas (API contracts) docker-compose.yml + Dockerfiles ``` ## 7. Data model Server-authoritative; an open session (`end_time` null) is "active work". - **users** — id, email, name, password hash (better-auth managed), **role** (`worker` | `admin`) - **workbenches** — id, name, `qr_code` (seeded / hardcoded for now) - **activities** — id, name, `insole_types[]` (subset of `Kurk` | `Berk` | `3D`) - **sessions** — id, `user_id`, `activity_id`, `workbench_id`, `insole_type`, `pair_count`, `start_time`, `end_time` (null = running), `status` (`active` | `completed` | `discarded`), `source` (`app` | `manual`), `notes`, `created_at` (better-auth also creates its own `session`/`account`/`verification` tables; those are distinct from the domain `sessions` table above — naming to be disambiguated in Phase 0, e.g. `work_sessions`.) ## 8. Port vs. leave behind **Port (the good parts):** the data model, the API route logic, the screen flows/UX, the CSV export logic, the Dutch UI strings, and the lessons captured in the current code's comments (Android font/freeze fixes, SecureStore quirks). **Leave behind:** the `__create` plumbing, the web-sandbox iframe layer, analytics / Sentry / anything-menu, the patched dependencies, and the ~60 unused libraries (ads, IAP, maps, 3D, audio, calendar, contacts, sensors, …). ## 9. Phased roadmap Each phase keeps the system working and is its own spec → plan → build cycle. - **Phase 0 — Foundation.** Greenfield monorepo; dockerized Hono backend with better-auth - Drizzle + SQLite; `docker compose up` brings it up; health check + one auth round-trip proven end-to-end. _Done when:_ a client can sign in against the containerised backend and the token authorises a protected call. - **Phase 1 — Worker timing.** Activities + server-authoritative work-sessions (open/close) + history + CSV export in the backend; mobile app rebuilt to use it. _Done when:_ a worker can pick an activity, start/stop a server-side session, and see history; CSV exports. - **Phase 2 — Accounts & roles.** ✅ **Implemented.** Worker/admin roles (better-auth `admin` plugin), admin-creates-users, per-user data scoping. Workers are scoped to their own sessions; an admin account exists; admin manages users via `/api/auth/admin/*` and sees all sessions via `/api/admin/sessions`. Public sign-up is closed; activity writes are admin-only. _Done when:_ workers see only their own sessions; an admin account exists. - **Phase 3 — Admin panel.** The React admin app: live active-work view, reports/export, user management, **activity management**, **manual entry/edit (the fallback)**. Activity management (add/edit/delete handelingen + their `insole_types`) was removed from the worker client in the Phase 2 follow-up because it is admin-only; it must be **ported here**. The backend already exists (`/api/activities` writes are admin-gated; `useActivities`/the legacy worker `Settings.tsx` at git `decb158`/`1631c16` are the UI reference), so this is a UI-only port. User management likewise consumes the existing better-auth `/api/auth/admin/*` endpoints, and the live view + reports consume `/api/admin/sessions[/active]`. _Done when:_ an admin can see who's working now, manage users **and activities**, and hand-correct a session. - **Phase 4 — Workbench scanning.** QR at the bench → select workbench/activity, with manual selection fallback. _Done when:_ scanning a bench QR pre-fills the session. - **Phase 5 — Polish & deploy.** Reporting niceties, dependency slimming, push the container to a chosen cloud host. ## 10. Open questions & assumptions (confirm as we go) - **Scanning = QR codes** on benches, read by the phone camera (no special hardware), always with manual fallback. _(Assumption.)_ - **Start fresh, no data migration.** Assumes no live workshop data/users worth preserving in the friend's platform instance. If there are, they must be **exported from the friend's Create account** — unreachable from this repo. - **Workbench↔activity mapping** is hardcoded/seeded for now; real mapping TBD with the friend. - **Deployment host** is deferred (Phase 5); the dockerized stack keeps options open. - **Domain term:** "insole" / orthotic; Dutch UI (`Type zool`, `handeling`, `aantal zolen`, etc.). ## 11. Risks - **Greenfield is more work than evolving in place** — mitigated by porting proven logic and keeping the old code as a running reference. - **SQLite is single-writer / single-instance** — fine at this scale; swap to Postgres/libsql is a config change via Drizzle/better-auth if ever needed. - **Offline on the shop floor** — the friend hit connectivity issues. Backend-as-source- of-truth assumes reachable network; true offline-first is explicitly out of scope for now (revisit if it bites). ## 12. Next step Brainstorm **Phase 0** in detail, then hand it to the writing-plans skill for an implementation plan. No code before that plan exists.