5.9 KiB
Yaltopia Tickets App — Agent Guide
First Read
Read these before writing any code:
app/_layout.tsx— root stack, guards, heartbeat, fonts, themelib/api.ts— API services & endpoint definitionslib/api-middlewares.ts— auth injection + token refresh logiclib/routes.ts— all route definitions with guard metadatalib/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 isexpo-router/entry(set inpackage.jsonmain)app/(tabs)/— 5 bottom tabs: index (Home), payments, scan, proforma, newslib/— API client (api.ts), middleware (api-middlewares.ts), stores, guards, routes, permissions, theme, utilscomponents/— 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'srouter.push. ImportAppRoutesfrom@/lib/routes. - API calls: Use the
@simple-apiclient (api.{service}.{endpoint}({ body, params, query, headers })). For file uploads (scan), use rawfetchwith FormData. - Auth tokens: Never manually inject Bearer.
authMiddlewaredoes it automatically + proactively refreshes near-expiry tokens viarefreshTokens()singleton promise. - Phone numbers: Ethiopian
+251is auto-prepended. Input fields accept the 9-digit number without prefix. - Toast:
import { toast } from "@/lib/toast-store"thentoast.success("Title", "Message"),.error(),.warning(),.info(). - Form screens use inline
StyleSheet.createfor input styles anduseInputColors()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(seeapp/(tabs)/_layout.tsx) - Primary color:
#ea580c(orange) — used astext-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-widestwith 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>withpreviewLines,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.csspower 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-referencesDESIGN.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
#E46212on ≤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:
- yimpeccable (
.agents/skills/yimpeccable/) — run$impeccable <command>per its reference. Provides design guidance, register context, color/typography/layout rules. - ui-ux-pro-max (
.opencode/skills/ui-ux-pro-max/) — runpython3 .opencode/skills/ui-ux-pro-max/scripts/search.py "<query>" --design-systemor 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.