@ 12- 应用程序/ 临时
无头、有租户范围的工作轮班:工人可选择申请时间 期限由工人关闭,按 上司,或者扫荡 一经关闭、通过港口审计和 由 Prisma 部分加 PostgreSQL 保证支持 .
包拥有机制. 它不拥有任何词汇.
东道国的种类
kind 是一个变化中的字段,其价值描述的是企业而不是
一个工作周期,所以没有默认,也没有内置列表——集合是
需要配置 :
import { createShiftService, defineShiftVocabulary } from '@12-apps/shift';
export const CLINIC_KINDS = ['hygiene', 'surgery', 'reception'] as const;
const service = createShiftService(shiftDb, { kinds: CLINIC_KINDS });
通过一个 as const tumple 和返回服务上的所有输入都缩小到
准确的这些值,所以主机通过自己的单词不断编译时间安全性:
await service.openShift({
clientId, userId, actorUserId,
kind: 'surgery', // ✅ declared
resource: { type: 'operatory-chair', id: 'chair-3', exclusive: true },
});
await service.openShift({ ...input, kind: 'grooming' });
// ✗ compile error, and at runtime a ShiftError('INVALID_SHIFT') naming the
// kinds this service was constructed with.
空的、空白的或重复的条目 ShiftConfigError 在建筑方面
在可以辨认的情况下——而不是在没有人可以进来的要求下.
背书
Shift.kind 是一个 string,因为一行持有 任何在栏。 A 类
宿主想要它的联盟 与后卫缩小 defineShiftVocabulary
返回时,从同一声明中创建该服务
const vocabulary = defineShiftVocabulary(CLINIC_KINDS);
const kind = vocabulary.has(shift.kind) ? shift.kind : null;
// ^? 'hygiene' | 'surgery' | 'reception' | null
一个声明,所以一个服务接受的值和一个主机的值缩小 不能分开.
resourceType 财务报告和审定财务报表 resourceId 一直以这种方式行事:,
与主人拥有他们的意思。 善良只是加入他们.
时间表
转变是一个事实:它开始,它可能已经结束。 A 类 插槽 计划:
从什么时候到何时,应该用哪种方法 他们住在不同的桌子上
(单位:千美元)shift_slots 旁边 shifts)和不同的服务,在同一词汇上:
const schedule = createShiftScheduleService(scheduleDb, { kinds: HOST_KINDS });
await schedule.scheduleSlot({
clientId, userId, kind: 'ward', actorUserId,
startsAt, endsAt,
repeatWeeks: 3, timeZone: 'America/New_York', // this week and the next three
});
- 复有持壁钟. 每份每周副本在同一当地时间登陆
内
timeZone,跨越一时的防日变化: 穿过空隙( 02: 30 变成 03: 30), 重复的时间是第一次 发生。 24小时限时检查每份,所以24小时档 其重复将跨越倒数 重复通话需要已知 区; 单个槽没有. - 每个租户的工人没有重叠整个重复,所有或没有:
SLOT_OVERLAP和没有写。 后入无碍. 主持人lockUserSchedule必须连载同一工人的两个作家(a) postgres 上的交易范围咨询锁定 —— 重复读取仅作为 安全到锁上. - 取消保留行 (单位:千美元)
canceledAt, (中文(简体) ),canceledByUserId, (中文(简体) ),cancelReason)),所以主持人可以说为什么一个插槽被放出.scope: 'following'也取消同系列后期的活槽. 空档已经结束了 无法取消 . slotStanding({ slot, openShift, now })答题canceled, (中文(简体) ),over, (中文(简体) ),on_shift, (中文(简体) ),late(与lateMinutes, (中文(简体) ),due(在窗口前) 启动,默认为15分钟)或later。它相信东道主的openShift数字 : 通过工人的开放式轮班 类型软件包 不决定哪个档次是哪个档次.nextSlots({ clientIds, userId, limit })读取一个人的活槽 横跨租户的HOST允许,在限前过滤. 谁还在工作 宿主的知识在哪里, 所以一个空列表被拒绝 而不是读 像"任何地方"一样.
系列规则和滚动视野
重复也可以是一个 规则 (单位:千美元)shift_slot_series而不是N拷贝:
const { series, slots, change } = await schedule.scheduleSeries({
clientId, userId, kind: 'ward', actorUserId,
weekdays: [1, 3], everyWeeks: 1, // or monthlyNth: 3 with ONE weekday
startMinutes: 22 * 60, endMinutes: 6 * 60, // an end at or before the start is the next day
breakOffsetMinutes: 240, breakMinutes: 30, // optional, from the start, both or neither
timeZone: 'America/New_York', startsOn: '2026-10-26', endsOn: null, // null = no end
});
- 日子的到来 (单位:千美元)
horizonWeeks,默认 12)作为 携带普通插槽seriesId财务报告和审定财务报表seriesDate。 。 。 .extendSeries()正在建设 每个租户的每个公开规则的后几天;materialiseSeries({ until, preview })或列出未来的日子. 两者都有天分: 一天已经有一行规则——取消了, 已搬出或已搬出——从未重建。 一个人已经一天了 被跳过,记录在规则上(skippedDates)并审计过一次—— 一天的时数倒在日出时空 (单位:千美元)scheduleSeries, (中文(简体) ),editSeries, (中文(简体) ),promoteToSeries)拒绝使用WALL_CLOCK_GAP,作为editSlot用于一个插槽. - 这份工作.
@12-apps/shift/jobs声明extend-series(每日租借). 主机绑定extendSeries()a. 对本会议工作的贡献onMaterialised(clientId, slotIds)无论它是否与时间表一致. - 编辑已经到位.
editSlot移动一行(小时或日期)detached或把它交给别人 个人,它从它的系列中取出(seriesId没有,originSeriesId保留);rejoinSeries: true把它放回去,只让规则的人.editSeries({ from })前一天关闭规则from打开 继任者(previousSeriesId;每两周接任一次,任期相同 重复保留旧规则的周数, 已经进行的一行被保留,它的 日出继承人.promoteToSeries转动一个人的单曲 成规而行,复制其时而断其时而拒之INVALID_SLOT(单位:千美元) 一日一日一出,不得犯规;demoteToSlot结束规则为 一个分离的单身. - 一个规则在它的未来被取消时结束.
cancelSlot与following在规则的行 结束规则的前一天;restoreSlot这些行 重新打开它.restoreSlot只清除主机通过取消的原因restorableReasons在尚未结束的档位上,包名没有. - 每个规则都写回一个
ScheduleChange简洁的JSON,和revertScheduleChange在一次交易中撤销,拒绝使用SCHEDULE_CHANGED当一行或规则 它的名字从此移动。 从来没有 摸一行交给另一个人:那行是他们的,规则是: 背负的背负 离开它的一天.cancelSlot继续返回其槽; 变换在阵列上作为.change。 。 。 . allowRunning: true打开scheduleSlot财务报告和审定财务报表editSlot输入插槽 已经在执行中(替代);没有它就拒绝过去的开始.
ShiftScheduleError 携带自己的代码(INVALID_SLOT, (中文(简体) ), SLOT_OVERLAP, (中文(简体) ),
SLOT_NOT_FOUND, (中文(简体) ), SLOT_CANCELED, (中文(简体) ), SLOT_OVER, (中文(简体) ), SLOT_NOT_RESTORABLE, (中文(简体) ),
WALL_CLOCK_GAP, (中文(简体) ), SERIES_NOT_FOUND, (中文(简体) ), SCHEDULE_CHANGED和
SHIFT_SCHEDULE_ERROR_STATUS 将其映射到 HTTP 状态; ShiftError代码
不变,所以一个与它们完全匹配的主机会不断编译.
从3.x升级
createShiftService(db) 不再编译 : options.kinds 需要时间.
- 在主机代码中宣布您的类型为
as const拖住,通过他们. - 替换已删除的类别清单、类型结合和两者的进口 资源类型常数,含有自己的主机常数。 资源类型 值从未被此软件包验证过 比较——所以保留同一字行保留了现有的每行.
- 迁相.
20260821120000_shift_kind_host_vocabulary放弃 CHECK 限制的限制shifts.kind取出源的2个 值,并替换为非空白检查。 现有行满足,所以 没有回填.
没有其他变化:转移的电线形状、审计端口、排他性 规则,扫描 和每个错误代码是原样.
出口
| 导出 | 这是什么 |
|---|---|
createShiftService(db, options) | 服务. options.kinds 需要时间. |
defineShiftVocabulary(kinds) | 验证主机的种类; 返回它们上面的类型守护 . |
createMemoryShiftDb() | 记忆 ShiftDb,用于主机测试. |
createShiftScheduleService(db, options) | 计划档期表. |
createMemoryShiftScheduleDb() | 记忆 ShiftScheduleDb,用于主机测试. |
ShiftScheduleError 编号 : SHIFT_SCHEDULE_ERROR_STATUS | 时刻表拒绝, 及其 HTTP 状态 . |
ShiftError 编号 : ShiftConfigError | 请求结果和线路错误. |
@12-apps/shift/jobs | 自动关闭和扩展系列的蓝图,道克仍然开放. |
@12-apps/shift/manifest | 电线清单及其服务器的一半. |
数据库
普里斯马部分prisma/shift.prisma和迁移情况
prisma/migrations 被贡献给宿主的计策。 租户、用户和
资源标识符按值存储,主机表格中没有外键——
也就是让东道主清理租户 而不给包裹一个意见.