import { initContract } from '@ts-rest/core'; import { z } from 'zod'; import { registerOwnerAndShopSchema, shopOwnerSchema, shopSchema, shopListItemSchema, addShopSchema, deviceRoleEnum, } from '../schemas/shopkeeper.schemas'; import { errorResponseSchema, successResponseSchema } from '../schemas/common.schemas'; const c = initContract(); export const shopkeeperDeviceContract = c.router({ register: { method: 'POST', path: '/shopkeeper/device/register', body: registerOwnerAndShopSchema, responses: { 201: z.object({ owner: shopOwnerSchema, shop: shopSchema, shops: z.array(shopListItemSchema), ownerToken: z.string(), shopToken: z.string(), refreshToken: z.string(), expiresIn: z.number(), }), 400: errorResponseSchema, 409: errorResponseSchema, }, summary: 'Register new owner, shop, and device', }, login: { method: 'POST', path: '/shopkeeper/device/login', body: z.object({ phone: z.string(), pin: z.string().min(4).max(6), deviceId: z.string(), deviceName: z.string().optional(), role: deviceRoleEnum.default('owner'), osVersion: z.string().optional(), appVersion: z.string().optional(), }), responses: { 200: z.object({ owner: shopOwnerSchema, shops: z.array(shopListItemSchema), ownerToken: z.string(), refreshToken: z.string(), expiresIn: z.number(), }), 401: errorResponseSchema, 404: errorResponseSchema, }, summary: 'Authenticate owner with phone + PIN', }, selectShop: { method: 'POST', path: '/shopkeeper/device/select-shop', body: z.object({ shopId: z.string().uuid() }), responses: { 200: z.object({ shop: shopSchema, shopToken: z.string(), expiresIn: z.number(), }), 401: errorResponseSchema, 403: errorResponseSchema, 404: errorResponseSchema, }, summary: 'Select active shop and get shop-scoped token', }, addShop: { method: 'POST', path: '/shopkeeper/device/shops', body: addShopSchema, responses: { 201: z.object({ shop: shopSchema, shopToken: z.string(), expiresIn: z.number(), }), 400: errorResponseSchema, 401: errorResponseSchema, }, summary: 'Add a new shop to owner account', }, listShops: { method: 'GET', path: '/shopkeeper/device/shops', responses: { 200: z.object({ shops: z.array(shopListItemSchema) }), 401: errorResponseSchema, }, summary: 'List all shops for authenticated owner', }, refresh: { method: 'POST', path: '/shopkeeper/device/refresh', body: z.object({ refreshToken: z.string() }), responses: { 200: z.object({ ownerToken: z.string(), expiresIn: z.number() }), 401: errorResponseSchema, }, summary: 'Refresh owner access token', }, updateDevice: { method: 'PATCH', path: '/shopkeeper/device', body: z.object({ appVersion: z.string().optional(), fcmToken: z.string().optional(), osVersion: z.string().optional(), }), responses: { 200: successResponseSchema, 401: errorResponseSchema, }, summary: 'Update device metadata', }, sendOtp: { method: 'POST', path: '/shopkeeper/device/send-otp', body: z.object({ phone: z.string() }), responses: { 200: z.object({ message: z.string(), expiresIn: z.number() }), 429: errorResponseSchema, }, summary: 'Send OTP to phone number', }, verifyOtp: { method: 'POST', path: '/shopkeeper/device/verify-otp', body: z.object({ phone: z.string(), code: z.string().length(6) }), responses: { 200: z.object({ verified: z.boolean() }), 400: errorResponseSchema, }, summary: 'Verify OTP code', }, resetPin: { method: 'POST', path: '/shopkeeper/device/reset-pin', body: z.object({ phone: z.string(), otpCode: z.string().length(6), newPin: z.string().min(4).max(6), }), responses: { 200: successResponseSchema, 400: errorResponseSchema, 404: errorResponseSchema, }, summary: 'Reset owner PIN using OTP', }, registerStaffProfile: { method: 'POST', path: '/shopkeeper/device/staff/register', body: z.object({ displayName: z.string().min(1).max(80) }), responses: { 201: z.object({ id: z.string().uuid(), displayName: z.string(), isActive: z.boolean(), createdAt: z.coerce.date(), }), 401: errorResponseSchema, 403: errorResponseSchema, }, summary: 'Register a named staff profile on the authenticated device', }, listStaffProfiles: { method: 'GET', path: '/shopkeeper/device/staff', responses: { 200: z.object({ profiles: z.array( z.object({ id: z.string().uuid(), displayName: z.string(), createdAt: z.coerce.date(), }), ), }), 401: errorResponseSchema, 404: errorResponseSchema, }, summary: 'List staff profiles for the authenticated device', }, });