K

Documentation

Boba developer docs

A Docusaurus-style guide for the Next.js admin workspace, Neon data model, API routes, and the companion Chatur iOS app.

Boba contains two active product surfaces:

  • web/: a Next.js admin workspace backed by Neon.
  • chatur/: a SwiftUI iOS app with location logging, camera capture, geospatial views, notepad, finance tracking, and pomodoro workflows.

The /docs page reads these Markdown files from web/docs/documents/ and renders them inside the Next app.

Repository map

PathPurpose
web/appNext.js App Router pages and route handlers.
web/docs/documentsDocusaurus-style Markdown files rendered by /docs.
web/db/schema.sqlRepeat-safe Neon schema and seed data.
chatur/SwiftUI iOS app source.

Local setup

Install dependencies, configure Neon, and run the web app locally.

Install dependencies from the web workspace:

cd web
npm install

Install the shared API workspace:

cd ../api
npm install
cp worker/.dev.vars.example worker/.dev.vars

Copy the example environment file:

cp .env.example .env

Set the Worker DATABASE_URL in api/worker/.dev.vars. Set the web NEXT_PUBLIC_API_BASE_URL to the local Worker URL:

NEXT_PUBLIC_API_BASE_URL="http://127.0.0.1:8787"

Start the Worker:

cd api
npm run dev

Start the web dev server in another terminal:

cd web
npm run dev

Run a direct Neon smoke test:

cd api
npm run test:neon

Run a production build check:

npm run build

Architecture

How the static Next.js app, shared Worker API, and Neon database fit together.

The web workspace uses the Next.js App Router and exports static pages. Runtime data requests go to the shared Cloudflare Worker in api/.

AreaLocationNotes
Pagesweb/appDashboard, interviews, counters, login, and docs routes.
API Workerapi/workerShared JSON API for web and web-extension clients.
API clientweb/lib/api-client.jsBuilds URLs from NEXT_PUBLIC_API_BASE_URL.
Databaseweb/db/schema.sqlNeon schema and seed data.

Runtime flow

  • Client pages fetch JSON from ${NEXT_PUBLIC_API_BASE_URL}/api/*.
  • The Worker uses @neondatabase/serverless.
  • DATABASE_URL is configured as a Worker secret.
  • Static page privacy should be handled by hosting, such as Cloudflare Access.

Important files

  • web/app/page.js
  • web/app/interviews/page.js
  • web/app/counters/page.js
  • web/app/docs/page.js
  • web/lib/api-client.js
  • api/worker/src/index.js
  • web/scripts/run-next.mjs

Database

Neon schema, tables, and common SQL operations.

The canonical web database schema is web/db/schema.sql.

Apply the schema:

cd web
set -a
source .env
set +a
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f db/schema.sql

Tables

TablePurposeImportant columns
questionsInterview question libraryid, tags, title, question_text, answer_test, difficulty
countersQuick Apply countersid, title, count, is_pinned, created_at
copy_textsReusable snippetsid, title, text_content, created_at

Common SQL

Select all questions:

select id, tags, title, question_text, answer_test, created_at, difficulty
from public.questions
order by created_at desc, id desc;

Delete one question:

delete from public.questions
where id = '<question-id>';

API routes

Shared Worker API reference for web and extension clients.

All API routes are served by the shared Cloudflare Worker in api/worker.

When AUTH_ENABLED=true, requests must include a valid dashboard_session cookie unless they are auth endpoints.

MethodPathDescription
GET/api/healthChecks Neon connectivity.
GET/api/dashboardReturns dashboard metrics and recent data.
GET/api/interview-questionsLists interview questions.
POST/api/interview-questionsCreates an interview question.
PATCH/api/interview-questions/:idUpdates an interview question.
DELETE/api/interview-questions/:idDeletes an interview question.
GET/api/countersLists Quick Apply counters.
POST/api/countersCreates a counter.
GET/api/copy-textsLists saved snippets.
POST/api/copy-textsCreates a saved snippet.
GET/api/map-pinsLists map pins.
POST/api/map-pinsCreates a map pin.
PATCH/api/map-pins/:idUpdates a map pin.
DELETE/api/map-pins/:idDeletes a map pin.
POST/api/auth/loginCreates a signed session cookie.
POST/api/auth/logoutClears the session cookie.

Create question body:

{
  "tags": ["system-design", "technical"],
  "title": "System Design",
  "question_text": "How would you design a rate limiter?",
  "answer_test": "Look for requirements, trade-offs, storage, and failure modes.",
  "difficulty": "Hard"
}

Authentication

Optional single-admin authentication behavior.

Authentication is disabled unless AUTH_ENABLED=true in the Worker environment.

AUTH_ENABLED=true
ADMIN_EMAIL="admin@example.com"
ADMIN_PASSWORD="use-a-long-unique-password"
AUTH_SECRET="at-least-32-random-characters"

Generate a secret:

openssl rand -base64 32

Request flow

  • The Worker handles login, logout, and API authentication.
  • Session tokens are signed with Web Crypto in api/worker/src/index.js.
  • The session cookie is named dashboard_session.
  • Static page access should be protected at the hosting layer when docs or screens must be private.

Troubleshooting

Debugging notes for local web development and Neon connectivity.

Direct Neon works but API calls fail

Run the direct smoke test:

cd api
npm run test:neon

Then check the Worker route:

curl -i http://127.0.0.1:8787/api/health

If the route fails but the direct script works, inspect:

  • api/worker/.dev.vars
  • DATABASE_URL Worker secret in production
  • ALLOWED_ORIGIN CORS configuration
  • Worker logs from Wrangler or Cloudflare

For web client issues, confirm:

NEXT_PUBLIC_API_BASE_URL="http://127.0.0.1:8787"

Chatur iOS

SwiftUI app structure, persistence, and build commands.

chatur/ is the SwiftUI iOS app in this repository.

Screens

  • Home
  • Location Tracker
  • Camera
  • GeospatialAR
  • Notepad
  • Finance
  • Pomodoro

Persistence

SQLite tables in chatur/DatabaseStore.swift:

  • locations
  • photos
  • water
  • outside_time

Notepad content uses @AppStorage("notepad.text").

Finance hard costs are JSON encoded in UserDefaults.

Build

xcodebuild -project boba.xcodeproj -scheme chatur -destination 'generic/platform=iOS Simulator' build