Перейти к основному содержимому

Входы

Вход — это одна система с тремя входными дверями: приложение киоска B1Checkin для укомплектованных и самообслуживающихся станций, самостоятельный вход внутри портала членов B1App и посещаемость на стороне администратора в B1Admin. Все три записывают в один модуль посещаемости в ядре Api, а маршрутизация классной комнаты полностью управляется группами — нет отдельной сущности "мест" или "комнат". На вершине находится слой безопасности детей: типы входов для каждого посещения, серверные ворота ёмкости и коэффициента волонтёра, соответствие возраста/класса на стороне киоска, проверка доверенного самовывоза при выезде и пейджинг родителей через поставщика текстовых сообщений церкви. На этой странице сопоставлена модель данных, потоки входа, слой безопасности и конвейер печати этикеток.

Обзор

┌──────────────────────────┐
│ B1Checkin (Expo kiosk) │──┐ ┌──────────────────────────────────────────────┐
│ lookup → household → │ │ │ Api │
│ groups → complete/print │ │ HTTPS │ ┌─ membership module ─────────────────────┐ │
├──────────────────────────┤ ├───────▶ │ │ people · households · groups │ │
│ B1App (self check-in) │──┤ │ └─────────────────────────────────────────┘ │
│ /mobile/checkin screen │ │ │ ┌─ attendance module ─────────────────────┐ │
├──────────────────────────┤ │ │ │ campuses → services → serviceTimes │ │
│ B1Admin (staff) │──┘ │ │ groupServiceTimes (room routing) │ │
│ setup · reports · │ │ │ sessions ← visitSessions → visits │ │
│ label designer │ │ │ labelTemplates │ │
└──────────────────────────┘ │ └─────────────────────────────────────────┘ │
└──────────────────────────────────────────────┘

Путь печати этикеток (киоск только):
POST /attendance/visits/checkin ──▶ { securityCode, streaks }
└▶ LabelHelper (label templates, or bundled HTML fallback)
└▶ LabelRenderer → HTML doc + inline SVG barcodes
└▶ PrintUI: WebView render → ViewShot JPG capture
└▶ printer-helper native module → Brother QL / Zebra
ПоверхностьРепоСтекРоль
КиоскB1CheckinExpo / React Native, маршрутизация файлов expo-router; сборки EAS для Android, Amazon Fire и iOS; обновления OTA через expo-updatesУкомплектованная или самообслуживающаяся станция с печатью этикеток и проверенным выходом
Самостоятельный входB1AppNext.js (портал членов b1.church)Вошедшие члены регистрируют своё домохозяйство из телефона; без печати
AdminB1AdminReact SPAНастраивает структуру служб, назначает группы времени служб, разрабатывает этикетки, записывает ручное посещение, запускает отчёты

Все три вызывают одни и те же два модуля API через ApiHelper: MembershipApi (/membership) для людей, домохозяйств и групп; AttendanceApi (/attendance) для всего остального.

Модель данных (Api/src/modules/attendance)

Сущность / таблицаКлючевые поляЗначение
campusesname, addressУстаревший здесь — кампусы мастеризированы в модуле членства (/membership/campuses); копия посещаемости заморожена только для чтения для устаревших читателей (models/Campus.ts)
servicescampusId, nameПовторное собрание, например "Воскресное утро" (models/Service.ts)
serviceTimesserviceId, nameСлот времени в рамках служения, например "09:00" (models/ServiceTime.ts)
groupServiceTimesgroupId, serviceTimeIdТаблица соединения: какие группы (классные комнаты) встречаются в какие времена служб (models/GroupServiceTime.ts)
sessionsgroupId, serviceTimeId, sessionDateОдно собрание одной группы на одну дату — лениво создано во время входа (models/Session.ts)
visitspersonId, serviceId, visitDate, checkinTime, securityCode, checkinType, checkedInById, checkoutTime, checkedOutBy, checkedOutByIdОдно посещение одного человека в один день (models/Visit.ts). checkinType это member / guest / volunteer (NULL = устаревший член), установленный киоском и потребляемый воротами ёмкости/коэффициента
visitSessionsvisitId, sessionIdКакие сессии охватывает посещение — ребёнок, вошедший в два времени служб, получает две строки (models/VisitSession.ts)
labelTemplatesname, labelType (nametag/pickup), width, height, isDefault, content (JSON blocks)Разработанные макеты этикеток (models/LabelTemplate.ts)

Как завершённый вход сохраняется

VisitController.postCheckin (Api/src/modules/attendance/controllers/VisitController.ts) обрабатывает POST /attendance/visits/checkin?serviceId=&peopleIds=. Тело — это массив объектов Visit, каждый несущий visitSessions, чьи встроенные session называют только пару (serviceTimeId, groupId). Сервер затем:

  1. Закрывает ёмкость и коэффициенты перед любой записью. evaluateGates()CheckinGateHelper.evaluate() проверяет ёмкость каждого целевого номера, ёмкость гостя, закрытый флаг и коэффициент волонтёра относительно текущей занятости. postCheckin не является транзакционным, поэтому ворота должны работать перед первой записью — жёсткое нарушение возвращает 409, называя оскорбляющую комнату, и ничто не сохраняется. См. Ворота ёмкости и коэффициента волонтёра.
  2. Лениво разрешает сессии. getSessionId() находит или создаёт строку sessions для (groupId, serviceTimeId, today) — id сессий кэшируются в процессе для каждой даты. Новые сессии выпускают вебхук session.created. Цикл — это ожидаемый for..of — более ранний fire-and-forget forEach(async …) гонял сохранение и писал NULL sessionIds при создании первой сессии (исправлено; отмечено в комментарии кода на цикле).
  3. Заменяет записи дня. Любые существующие посещения для этих людей в этой службе сегодня удаляются вместе с их visitSessions, затем отправленный набор сохраняется. Повторный вход семьи — это идемпотентная операция "это текущее состояние", а не добавление. Передача ?checkDuplicates=true вместо этого возвращает { duplicates: [personId…] } без записи, что является способом киоска предупредить перед перезаписью.
  4. Создаёт один код безопасности за пакет. SecurityCodeHelper.generate() производит 4-символьный код из алфавита 23456789BCDFGHJKLMNPQRSTVWXYZ (без гласных или неоднозначных символов, поэтому коды не могут произносить слова или неправильно читать). Сервер повторяет попытку при столкновении с открытыми посещениями того же дня той же церкви и ставит штамп на код на каждое посещение в пакете.
  5. Возвращает { streaks, securityCode }. streaks отображает personId на счёт посещаемости за несколько недель; киоск отмечает вехи (каждую 5-ю неделю) конфетти.

Каждое сохранённое посещение также выпускает вебхук attendance.recorded. На стороне чтения GET /attendance/visits/checkin возвращает посещения людей из их последней зарегистрированной даты — если это была предыдущая неделя, id удаляются, поэтому клиент получает предварительно заполненную копию выбора комнаты прошлой недели, которая будет сохранена как новые записи.

Выезд

Два конечных пункта завершают цикл (VisitController):

  • GET /attendance/visits/code/:code — текущие посещения, ещё не проверенные, несущие этот код безопасности, с населением сессий.
  • POST /attendance/visits/checkout — тело { visitIds, checkedOutBy?, checkedOutById? }; штампует checkoutTime и кто забрал, и выпускает вебхук attendance.checkout за посещение.

Разрешения: кески проходят аутентификацию с attendance.checkin, которая предоставляет ровно поверхность входа/выхода/шаблона этикеток; attendance.view/attendance.edit охватывают отчёты и ручную запись; структура (службы, времена служб, назначения групп) требует services.edit. Самостоятельный вход членов (B1App) не требует никакого разрешения вообще: любой аутентифицированный пользователь со связанным человеком в церкви может вызвать GET/POST /attendance/visits/checkin, и сервер ограничивает представленные personIds до своего собственного домохозяйства (403 иначе — этот забор защищает securityCodes других семей нечитаемым). Членство — это грант; видят ли члены функцию, контролируется вкладками навигации B1App церкви. Другие конечные точки входа (code/:code, checkout, guardians, CheckinController) остаются киоском/только персоналом.

Группы управляют маршрутизацией комнаты

Нет сущности комнаты или классной комнаты где-либо в системе. "Комната" — это членская группа с включенным trackAttendance, связанная с одним или несколькими временами служб через groupServiceTimes. Поля группы (на Api/src/modules/membership/models/Group.ts), которые формируют поведение киоска:

ПолеЭффект
trackAttendanceГруппа участвует в посещаемости вообще; дерево установки B1Admin отмечает группы trackAttendance без строки groupServiceTimes как неназначённые
parentPickupПомечает комнату ребёнка: вход в неё делает посещение посещением "ребёнка", которое печатает семейный этикет для пикапа и помещает код безопасности на бирку имени
printNametagВходы ли в эту группу печатают бирку имени вообще
capacity / guestCapacity / checkinClosedОграничения ёмкости комнаты и жёсткий выключатель "закрыто", применяемые сервером воротами входа (редактируется в настройках группы B1Admin под "Ёмкость входа")
volunteerRatio / minVolunteersКоэффициент детей на волонтёра и минимальное количество голов волонтёров, применяемые согласно церковной настройке ratioEnforcement
minAgeMonths / maxAgeMonths / minGrade / maxGradeГраницы соответствия возраста/класса, оценены на стороне киоска для выделения или затемнения комнат

Каждый клиент денормализует одинаково (например B1Checkin/app/services.tsx, B1App/src/app/[sdSlug]/mobile/components/screens/CheckinPage.tsx): загрузите GET /attendance/servicetimes?serviceId=, GET /attendance/groupservicetimes и GET /membership/groups параллельно, затем для каждого времени служения соберите группы, чья строка groupServiceTimes указывает на неё в serviceTime.groups. Этот массив — это то, что показывает выбор комнаты, организованный по categoryName группы.

Назначения редактируются со страницы группы в B1Admin (B1Admin/src/groups/components/ServiceTimesEdit.tsxPOST/DELETE /attendance/groupservicetimes), и всё дерево Campus → Service → Service Time → Group визуализируется в B1Admin/src/attendance/components/AttendanceSetup.tsx через GET /attendance/attendancerecords/tree.

Информация

Поскольку группы — это единственный источник истины, то же членство в группе управляет маршрутизацией киоска, посещаемостью в стиле реестра на страницах групп B1Admin и отчётами о посещаемости — назначение группы времени служения — единственный необходимый шаг для создания пункта входа.

Безопасность детей

Типы входа

Каждое посещение несёт checkinTypemember, guest или volunteer (NULL означает устаревший/член; миграция tools/migrations/attendance/2026-07-03_checkin_type.ts). Тип выбирается на стороне киоска: чипы "Член / Гость / Волонтёр" на расширённой строке члена (B1Checkin/src/components/MemberServiceTimes.tsx), проштампованные на каждое ожидающее посещение при завершении (app/checkinComplete.tsx, по умолчанию member). Сервер потребляет его в ворота — волонтёры считают покрытие коэффициента вместо ёмкости, и гости считают guestCapacity.

Ворота ёмкости и коэффициента волонтёра

CheckinGateHelper.evaluate() (Api/src/modules/attendance/helpers/CheckinGateHelper.ts) работает внутри postCheckin перед любой записью (конечная точка не транзакционна, поэтому ворота-до-записи — это механизм правильности). Она загружает текущую занятость за целевую группу (VisitRepo.countActiveByGroupToday) и конфиг группы через шлюз модуля членства, затем классифицирует нарушения:

  • Жёсткое (всегда блок): checkinClosed, current + incoming > capacity, счёт гостя над guestCapacity. Пакет отклоняется с 409 { error: "capacity", groups: [{ groupId, groupName, reason }] } — киоск показывает названную комнату.
  • Коэффициент (предупреждение или блок): входящие не-волонтёры в комнату, где volunteers < minVolunteers, нет волонтёров вообще или children > volunteers × volunteerRatio. Серьёзность следует настройке для каждой церкви ratioEnforcement ("warn" по умолчанию / "block", отредактировано в B1Admin Управление церковью → Вход, CheckinSettingsEdit.tsx). Режим предупреждения возвращает 409 { warning: true, error: "ratio", … }, если клиент не переотправляет с acknowledgeWarnings=true — этот переотправ — это подтверждение персонала киоска.

Соответствие возраста/класса (только киоск)

Соответствие комнаты — это консультативный UI, оценённый на киоске, не применяемый сервером. B1Checkin/src/helpers/EligibilityHelper.ts сравнивает дату рождения / класс человека против minAgeMonths/maxAgeMonths/minGrade/maxGrade группы (порядок класса: PreK, K, 1–12, Выпущен) и возвращает eligible / ineligible / unknown — отсутствие данных даёт unknown и никогда не скрывает комнату. Возрасты и классы вычисляются состояние на дату повышения класса церкви (gradePromotionDate настройка, "MM-DD", отредактировано в B1Admin/src/settings/components/GradePromotionSettingsEdit.tsx); киоск получает это от GET /attendance/checkin/settings, и resolveAsOfDate выбирает самое недавнее событие в или перед сегодня. Выбор киоска выделяет подходящие комнаты и затемняет несоответствующие; выбор затемнённой комнаты требует подтверждения персонала.

Доверенная и неавторизованная комплектация

Люди комплектации — это сущность членства по домохозяйству: householdPickupPeople (Api/src/modules/membership/models/HouseholdPickupPerson.ts — householdId, опционально personId, name, photoUrl, relationship, status trusted / notAuthorized, notes). CRUD это GET /membership/householdpickup/:householdId (любой аутентифицированный пользователь церкви, поэтому кески могут читать это) плюс POST / DELETE контролируемые people.edit. Персонал управляет списком на странице человека карточкой Пикап (B1Admin/src/people/components/PickupPeople.tsx) — фото, отношение и фишка статуса "Доверено/Не авторизовано".

При выезде (B1Checkin/app/checkout.tsx) киоск загружает список пикапа домохозяйства: записи trusted отображаются как щелчки карточек пикапа рядом с семейной сеткой фотографий взрослых, и произвольно напечатанное имя "Другое" нечётко совпадает (Levenshtein, src/helpers/PickupMatchHelper.ts) с записями notAuthorized — совпадение блокирует выезд с листом предупреждения и кнопкой персонала Переопределить. Переопределение регистрируется на самом посещении: оно почтовое отделение checkedOutBy как "OVERRIDE: {name}" через обычный POST /attendance/visits/checkout, поэтому оно приземляется в записи посещаемости и вебхук attendance.checkout вместо отдельной таблицы аудита.

Пейджинг родителя и экстренная трансляция

CheckinController (Api/src/modules/attendance/controllers/CheckinController.ts, /attendance/checkin) раскрывает две конечные точки SMS:

  • POST /page{ visitId, message }: странички опекуны одного вошедшего ребёнка (экран выхода киоска, управляемый режим).
  • POST /broadcast{ serviceId, message }: тексты каждого домохозяйства, вошедшего в службу взрослых (параметры администратора киоска, за листом типа EMERGENCY-for-confirm в B1Checkin/app/adminSettings.tsx).

Оба разрешают взрослых домохозяйства через шлюз членства, затем рука доставляет MessagingModuleGateway.sendBulkText (Api/src/shared/modules/MessagingModuleGateway.ts) — дверь между модулями в настроенный поставщик текстовых сообщений церкви (@churchapps/texting: TextInChurch, Clearstream или MutualMinistry; там нет встроенного отправителя SMS). Шлюз регистрирует строку sentText плюс за получателем записи deliveryLog и предпочитает пакет 500 получателям; без настроенного поставщика возвращает no_provider, которые поверхности киоска как "SMS поставщик не настроен". Диспетчер контроллера dispatch() деидентифицирует телефонные номера и пропускает людей без мобильного или набора optedOut, возвращая { sent, failed, skippedOptedOut, skippedNoPhone }, поэтому киоск может показать то, что было пропущено.

Киоск (B1Checkin)

Экраны — это файлы expo-router под B1Checkin/app/; состояние между экранами находится в статическом классе CachedData (src/helpers/CachedData.ts), не состояние React.

index (boot/auto-login) → selectChurch → services ──▶ lookup ──▶ household ──▶ checkinComplete
│ │ ▲ │ │ │
loads serviceTimes, groups, │ │ └─────────┘ └▶ addGuest └▶ print labels,
groupServiceTimes, │ └▶ checkout (manned) auto-return
labelTemplates │ to lookup
  1. Поиск (app/lookup.tsx) — поиск по телефону (GET /membership/people/search/phone?number=, последние-4 или полные) или по имени (GET /membership/people/search?term=). Выбор совпадения загружает домохозяйство (GET /membership/people/household/{householdId}) и существующие посещения (GET /attendance/visits/checkin), семя pendingVisits с выбором последней недели.
  2. Обзор домохозяйства (app/household.tsx, src/components/MemberList.tsx) — каждая строка члена показывает уже зарегистрированный значок, бирку аллергии/nametagNotes, и текущие фишки комнаты. Расширение члена выводит список каждого времени служения с кнопкой комнаты плюс чипы типа входа "Член / Гость / Волонтёр" (MemberServiceTimes.tsx).
  3. Назначение группы (app/selectGroup.tsx) — дерево категорий, построенное из serviceTime.groups, с комнатами, подходящими возрасту/классу, выделены и неподходящие затемнены позади подтверждения персонала (см. Соответствие возраста/класса); выбор комнаты записывает { session: { serviceTimeId, groupId } } visitSession в ожидающее посещение этого человека (src/helpers/VisitSessionHelper.ts). "Нет" очищает это.
  4. Завершите (app/checkinComplete.tsx) — POST /attendance/visits/checkin с pendingVisits (каждый проштампован его checkinType), затем печать этикеток, если принтер настроен, и автоматический возврат к поиску. 409 ответ ёмкости показывает названную полную/закрытую комнату; предупреждение коэффициента предлагает подтверждение персонала, которое переотправляет с acknowledgeWarnings=true.

Экран выезда (app/checkout.tsx) принимает 4-символьный код безопасности через автоматически сфокусированный ввод — поэтому USB/Bluetooth клавиатурные сканеры штрих-кода работают без камеры — или на экранная клавиатура, используя тот же алфавит, автоотправка в 4 символов. Это смотрит вверх код, показывает забираемых детей и представляет доверенных людей комплектации домохозяйства как щелчковые карточки рядом с сеткой фотографий взрослых домохозяйства (плюс опция свободного текста "Другое", которая нечётко проверяется против неавторизованных имён — см. Доверено и не авторизовано комплектовать), затем почтовое отделение POST /attendance/visits/checkout с именем/id выбора. В управляемом режиме экран также предлагает Пейджинг родителя (POST /attendance/checkin/page) и переиздание этикета безопасностиreprint() перестраивает этикеты семьи с LabelHelper.getAllLabelsFor(...) и передает их через то же конвейер PrintUI, что и вход.

Личность станции — флаг AsyncStorage @StationMode ("self" | "manned", переключено в app/adminSettings.tsx). Управляемый режим добавляет точку входа выезда на экран поиска и редактирование профиля каждого члена (POST /membership/people) с экрана домохозяйства. Киоск закаливание встроено: дополнительный PIN (app/setPin.tsx, src/components/PinEntryModal.tsx) закрывает администратора и экраны принтера, экран администратора открывается только через 7 быстрых касаний логотипа заголовка, и привлекающий экран неактивности (src/hooks/useInactivityTimer.ts) берёт на себя между семьями.

Самостоятельный вход (B1App)

Члены входят из портала b1.church на экран /mobile/checkin (маршрутизируется B1App/src/app/[sdSlug]/mobile/components/ScreenRouter.tsx на screens/CheckinPage.tsx). Требуется вошедший пользователь и проходит те же четыре шага, что и киоск — службы → домохозяйство → группы → завершите — против идентичных конечных точек, с состоянием, удерживаемым в B1App/src/helpers/CheckinHelper.ts. Различия от киоска: домохозяйство происходит из вошедшего пользователя householdId (нет шага поиска), и печать этикета отсутствует — вместо этого экран завершения показывает пакет securityCode как QR (qrcode.react) с подсказкой "покажи это на станции входа". Если домохозяйство уже вошло при загрузке страницы, кнопка "Показать код входа" повторно отображает QR из существующего посещения securityCode. Вход записывается немедленно во время отправки (состояние ожидания отсутствует); QR только управляет печатью этикета на киоске.

Печать этикета от телефона к киоску (B1Checkin/app/scan.tsx, достигнуто с кнопки "Сканировать код" на экране поиска): киоск открывает expo-camera CameraView (по умолчанию обращенный вперёд, переворачиваемый), сканируя QR коды. Сканированный полезный груз принят, когда это простой 4-символьный код в алфавите кода безопасности, поэтому оба работают QR B1App и QR блок на печатном этикете. Экран затем следует переиздать пути выезда — GET /attendance/visits/code/{code}GET /membership/people/idsLabelHelper.getAllLabelsFor(visits, people, code)PrintUI — и возвращается к поиску. Никакой записи посещения не происходит во время сканирования; этикеты только. Коды без активных посещений, станции без принтера и группы без этикеток каждая поверхность тоста и возврат к поиску.

Типы и ApiHelper/ArrayHelper происходят от @churchapps/helpers и @churchapps/apphelper; компоненты React не разделяются с B1Admin.

Посещаемость на стороне администратора (B1Admin)

  • Установка/attendance (B1Admin/src/attendance/AttendancePage.tsx) отображает дерево структуры и создаёт службы (ServiceEdit.tsx) и времена служб (ServiceTimeEdit.tsx). Данные кампуса поступают из членства через крючок useCampuses().
  • Ручная посещаемость находится на стороне групп, не на стороне посещаемости: B1Admin/src/groups/components/GroupSessionsTab.tsx создаёт сессии (POST /attendance/sessions) и помечает людей присутствующих через POST /attendance/visitsessions/log, что находит или создаёт посещение для этого человека и сессии. Лидеры групп могут записывать посещаемость для своих групп без разрешения attendance.edit — контроллеры проверяют au.leaderGroupIds.
  • Отчёты — тренд посещаемости и посещаемость группы являются определёнными сервером отчётами (B1Admin/src/components/reporting/ReportWithFilter.tsx против ReportingApi); история за человека это GET /attendance/attendancerecords?personId= (B1Admin/src/people/components/PersonAttendance.tsx).

Печать этикеток

Шаблоны и дизайнер

Церкви разрабатывают свои собственные этикетки в B1Admin в /mobile/checkin/labels (B1Admin/src/attendance/LabelsPage.tsx + components/LabelEditor.tsx, достигнуто со страницы параметров входа). Шаблон — это строка labelTemplates, чьё content — это массив блоков JSON — text, field, barcode, qrcode или box — каждый позиционирован в процентных координатах с шрифтом, выравниванием, символогией (code39/code128/qr), и опциональными условиями видимости (например только отображать аллергию коробка когда person.nametagNotes не пусто). Два labelTypes существуют: nametag (один на вошедшего человека; поля как person.displayName, sessions, securityCode) и pickup (один на семью; поля как children, childrenAllergies). Сервер применяет один по умолчанию за тип за церковь (LabelTemplateController.save). Дизайнер поставляет стартовые шаблоны, отражающие встроенные этикетки киоска и предварительно просматривающие примеры данных.

Отображение и печать на киоске

При завершении входа B1Checkin/src/helpers/LabelHelper.ts решает, что печатать из флагов группы на каждом ожидающем посещении: этикеты для printNametag групп, плюс одна этикета пикапа семьи, если какое-либо посещение попало в parentPickup группу. Код безопасности из ответа входа идёт на детские этикеты и этикету пикапа; этикеты взрослых печатаются без кода. Если церковь имеет шаблоны, LabelRenderer (src/helpers/LabelRenderer.ts) поворачивает блоки + контекст поля в независимый документ HTML; в противном случае встроенные этикеты HTML в B1Checkin/assets/labels/ используются с заменой заполнителя.

Штрих-коды генерируются как встроенный SVG кодерами чистого TypeScript в B1Checkin/src/helpers/barcode.ts — таблицы шаблонов Code 39 и Code 128 (набор кода B с checksum mod-103) таблицы ширины, плюс QR через пакет qrcode. Эти кодеры намеренно дублируются в B1Admin (LabelEditor.tsx встраивает те же таблицы, отмеченные в комментарии кода), поэтому предварительные просмотры дизайнера пиксельно-верны выходу киоска; изменение в один должен быть отражен в другом.

Конвейер печати (src/components/PrintUI.tsx) отображает каждый этикет HTML в WebView, захватывает его в JPG через react-native-view-shot, и вручает URI изображения нативному модулю printer-helper Expo (B1Checkin/modules/printer-helper/). Модуль раскрывает scan(), checkInit(), printUris() и события статуса, с поставщиком за бренд на обеих платформах:

БрендAndroidiOSПримечания
BrotherBrotherProvider.kt (SDK печати Brother)BrotherProvider.swift (BRLMPrinterKit.xcframework)Сетевые принтеры серии QL (QL-800/810W/820NWB/1100/1110NWB…), этикеты die-cut 29×90, рекомендуемый по умолчанию
ZebraZebraProvider.kt (SDK Link-OS)ZebraProvider.swift + ZebraBridgeСетевое обнаружение + печать изображения TCP/ZPL

Выбор принтера находится в app/printers.tsx (сетевое сканирование возвращает записи brand~model~ip; выбор остаётся в AsyncStorage), и src/helpers/PrinterLog.ts сохраняет диагностический журнал на устройстве, выраженный через живую точку статуса в заголовке киоска.

Регистрация гостя

Два пути создают человека во время входа:

  • На киоске — экран домохозяйства "Добавить гостя" открывает B1Checkin/app/addGuest.tsx, который первый поиск GET /membership/people/search?term= для существующего не-члена совпадают и в противном случае создаёт один с POST /membership/people, прилагаемый к текущему домохозяйству. Гость затем течет через назначение группы как любой член.
  • Самостоятельно через QR — когда настройка церкви enableQRGuestRegistration включена (настроена в параметрах входа B1Admin, читается с GET /membership/settings/public/{churchId}), экран поиска киоска показывает QR код, связывающий https://{subdomain}.b1.church/guest-register?serviceId=. Эта страница B1App (src/app/[sdSlug]/(public)/guest-register/page.tsx) позволяет семье посетителей регистрировать себя на своём собственном телефоне через анонимную конечную точку POST /membership/people/guest-register, держа линию киоска в движении.

Связанные страницы