Yaltopia-Tickets-App/AGENTS.md
2026-06-05 13:39:37 +03:00

5.9 KiB

Yaltopia Tickets App — Agent Guide

First Read

Read these before writing any code:

  • app/_layout.tsx — root stack, guards, heartbeat, fonts, theme
  • lib/api.ts — API services & endpoint definitions
  • lib/api-middlewares.ts — auth injection + token refresh logic
  • lib/routes.ts — all route definitions with guard metadata
  • lib/auth-store.ts — zustand persisted auth state

Commands

npm run start       # expo start
npm run android     # expo run:android
npm run ios         # expo run:ios
npm run web         # expo start --web

No lint, typecheck, or test scripts exist. No postinstall hook beyond patch-package.

Project Structure

  • app/ — expo-router file-based screens; entry point is expo-router/entry (set in package.json main)
  • app/(tabs)/ — 5 bottom tabs: index (Home), payments, scan, proforma, news
  • lib/ — API client (api.ts), middleware (api-middlewares.ts), stores, guards, routes, permissions, theme, utils
  • components/ — shared UI; components/ui/ has shadcn-style primitives (button, text, card)
  • Path alias: @/ → project root (tsconfig paths)

Key Conventions

  • Navigating: useSirouRouter<AppRoutes>().go("routeName", { params }) — NOT expo-router's router.push. Import AppRoutes from @/lib/routes.
  • API calls: Use the @simple-api client (api.{service}.{endpoint}({ body, params, query, headers })). For file uploads (scan), use raw fetch with FormData.
  • Auth tokens: Never manually inject Bearer. authMiddleware does it automatically + proactively refreshes near-expiry tokens via refreshTokens() singleton promise.
  • Phone numbers: Ethiopian +251 is auto-prepended. Input fields accept the 9-digit number without prefix.
  • Toast: import { toast } from "@/lib/toast-store" then toast.success("Title", "Message"), .error(), .warning(), .info().
  • Form screens use inline StyleSheet.create for input styles and useInputColors() custom hook for theming. No form validation library.

UI Patterns (look at existing screens)

  • Tab bar: Floating pill, absolute, bottom: 25, marginHorizontal: 20, borderRadius: 32 (see app/(tabs)/_layout.tsx)
  • Primary color: #ea580c (orange) — used as text-primary, bg-primary, color="#ea580c"
  • Cards: <Card> + <CardContent> from @/components/ui/card, often wrapped in <ShadowWrapper level="xs">
  • Text: <Text variant="h1|h2|h3|h4|p|muted|small"> from @/components/ui/text
  • Buttons: <Button variant="default|outline|destructive|ghost|secondary" size="default|sm|lg|icon">
  • Status badges: text-[9px] font-semibold uppercase tracking-widest with semi-transparent bg
  • Section labels: font-bold text-xs uppercase tracking-widest
  • Filter pills: rounded-[4px] px-4 py-1.5
  • Bottom sheet pickers: <PickerModal> + <SelectOption> from @/components/PickerModal
  • Confirmation modals: <ActionModal> from @/components/ActionModal
  • Empty states: <EmptyState> with previewLines, actionLabel, onActionPress
  • No gradients anywhere (enforced by AGENTS.md). Use solid colors.

State Stores (zustand)

Store File Persisted? Key
useAuthStore lib/auth-store.ts Yes (AsyncStorage) yaltopia-auth-storage
useLanguageStore lib/language-store.ts Yes (AsyncStorage) app-language
useToast lib/toast-store.ts No

Theme is persisted via saveTheme()/loadTheme() in lib/theme.ts using AsyncStorage key app_theme_preference. Not a zustand store.

API Endpoints (lib/api.ts)

BASE_URL = https://api.yaltopiaticket.com/

Services: auth, invoices, payments, proforma, scan, users, company, news, notifications, rbac, support, faq

Middleware pipeline: logger → transformer → refresh (401 retry) → auth (Bear token + proactive refresh)

Route Guards (@sirou)

Routes are defined in lib/routes.ts with guards metadata (strings "auth" or "guest"). Guards are pure functions in lib/auth-guards.ts. GlobalGuard in app/_layout.tsx runs supplementary auth/guest checks.

Scan Flow

Camera → capture → preview → press "Extract" → raw fetch POST to /scan/invoice or /scan/payment-receipt with FormData → parse OCR result → api.invoices.create() with mapped data → navigate to detail.

Notes

  • Google Sign-In is lazy-loaded in a try/catch block — native module may not be available in Expo Go.
  • SMS scanning (react-native-get-sms-android) is Android-only and also lazy-loaded.
  • No local database — pure API-consumed app.
  • RBAC permissions in lib/permissions.ts — roles: ADMIN, BUSINESS_OWNER, EMPLOYEE, ACCOUNTANT, CUSTOMER_SERVICE, AUDITOR, VIEWER.
  • CSS variables in global.css power NativeWind theme. darkMode: "class" in tailwind config.

Design Context

Before any UI work, read these two files for design strategy + visual system:

  • PRODUCT.md — register, users, brand personality, design principles, anti-references
  • DESIGN.md — colors, typography, components, elevation, do's and don'ts
  • .impeccable/design.json — machine-readable design tokens with tonal ramps and component snippets

Key rules:

  • Primary orange #E46212 on ≤20% of surfaces. Flat-by-default (no shadows on cards/buttons). One typeface (DM Sans, weight creates hierarchy). True white backgrounds, not tinted.

UI Build Process

When building UI, ALWAYS use both skills together:

  1. yimpeccable (.agents/skills/yimpeccable/) — run $impeccable <command> per its reference. Provides design guidance, register context, color/typography/layout rules.
  2. ui-ux-pro-max (.opencode/skills/ui-ux-pro-max/) — run python3 .opencode/skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system or domain-specific searches. Provides design system recommendations, color palettes, font pairings, UX guidelines.

Always load both skill files and follow their workflows on any UI task.