placementt-core 1.400.922 → 1.400.923

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -883,6 +883,7 @@ export type InstituteData = {
883
883
  yearGroupsIncluded?: number[];
884
884
  closeAfterDays?: number;
885
885
  };
886
+ destinationsConfig?: DestinationsConfig;
886
887
  acceptingAlumni?: boolean;
887
888
  approveAlumni?: boolean;
888
889
  shareAlumni?: boolean;
@@ -1983,6 +1984,76 @@ export type AspirationCycle = {
1983
1984
  aggregates?: AspirationAggregates;
1984
1985
  emailTemplateId?: string;
1985
1986
  studentSelection?: string;
1987
+ autoProvisioned?: boolean;
1988
+ resolveRecipientsAtSend?: boolean;
1989
+ };
1990
+ /**
1991
+ * Extra recipient constraints beyond "active student in the target year group".
1992
+ * Same shape as a cohortFilters entry. Empty/absent = every active student in the
1993
+ * year group. Stored on DestinationsConfig and re-resolved at each send so the
1994
+ * cohort always reflects the live roster (students roll up a year each September).
1995
+ */
1996
+ export type DestinationsRecipientFilter = {
1997
+ k: string;
1998
+ e?: WhereFilterOp;
1999
+ v: unknown;
2000
+ }[];
2001
+ /** One scheduled survey in a year's aspiration programme. `sendMMDD` is "MM-DD". */
2002
+ export type AspirationSurveySlot = {
2003
+ sendMMDD: string;
2004
+ label?: string;
2005
+ };
2006
+ /**
2007
+ * One-time Destinations setup, saved on institutes/{oId}.destinationsConfig by the
2008
+ * setup wizard. destinationsProvisionCron reads it each year to auto-create that
2009
+ * year's aspiration cycles and leaver groups. All MM-DD strings are zero-padded
2010
+ * (e.g. "09-15"). Recipients are NOT frozen here — only the filter rule is stored;
2011
+ * the actual student list is resolved when each form's emails fire.
2012
+ */
2013
+ export type DestinationsConfig = {
2014
+ aspirations: {
2015
+ enabled: boolean;
2016
+ yearGroups: number[];
2017
+ /** Shared schedule applied to every selected year group (1–3 sends/year). */
2018
+ surveys: AspirationSurveySlot[];
2019
+ /** Optional per-year-group override. When a year group key is present its
2020
+ * schedule REPLACES `surveys` for that year group only. */
2021
+ surveysByYearGroup?: {
2022
+ [yearGroup: string]: AspirationSurveySlot[];
2023
+ };
2024
+ closeAfterDays: number;
2025
+ /** Extra constraints on top of "active Year-N student". Re-resolved each send. */
2026
+ recipientFilters?: DestinationsRecipientFilter;
2027
+ };
2028
+ leavers: {
2029
+ enabled: boolean;
2030
+ yearGroups: number[];
2031
+ intentionsSendMMDD: string;
2032
+ resultsDay: {
2033
+ enabled: boolean;
2034
+ sendMMDD: string;
2035
+ };
2036
+ christmas: {
2037
+ enabled: boolean;
2038
+ sendMMDD: string;
2039
+ };
2040
+ /** true → every student in these groups leaves (no internal sixth form). */
2041
+ allStudentsLeave?: boolean;
2042
+ recipientFilters?: DestinationsRecipientFilter;
2043
+ };
2044
+ alumni: {
2045
+ acceptingAlumni: boolean;
2046
+ approveAlumni: boolean;
2047
+ alumniConversations: boolean;
2048
+ visibleToStudents: boolean;
2049
+ };
2050
+ /** MM-DD on which each new academic year's objects are created. Default "09-01". */
2051
+ provisionMMDD: string;
2052
+ /** e.g. "2026/27" — last academic year the cron provisioned. Guards double-provisioning. */
2053
+ lastProvisionedYear?: string;
2054
+ setupCompletedAt: string;
2055
+ setupBy: string;
2056
+ updatedAt?: string;
1986
2057
  };
1987
2058
  /**
1988
2059
  * Pre-aggregated leaver response counts on a LeaverGroup — updated atomically via
@@ -3041,6 +3112,11 @@ export type LeaverGroup = {
3041
3112
  * asks "are you staying on?" first, and stayers skip the alumni / consent
3042
3113
  * capture (and aren't seeded as alumni). */
3043
3114
  allStudentsLeave?: boolean;
3115
+ /** Created by destinationsProvisionCron from the institute's DestinationsConfig
3116
+ * (not via the manual New Leaver Group flow). Auto-provisioned groups defer
3117
+ * recipient fan-out: leaverRequests are built from `students` when invite
3118
+ * emails fire, so the cohort is always resolved against the live roster. */
3119
+ autoProvisioned?: boolean;
3044
3120
  /** Post-leaving checkpoint schedule. Absent = checkpoints disabled for this group. */
3045
3121
  checkpointConfig?: {
3046
3122
  resultsDay?: {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "private": false,
3
3
  "name": "placementt-core",
4
4
  "author": "Placementt",
5
- "version": "1.400.922",
5
+ "version": "1.400.923",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
8
8
  "scripts": {
@@ -871,12 +871,17 @@ export type InstituteData = {
871
871
  }
872
872
  },
873
873
  // ASPIRATION CYCLE CONFIGURATION (Form A — annual student intent tracking)
874
+ // @deprecated dead config — never read at runtime. Superseded by destinationsConfig.
874
875
  aspirationCycleConfig?: {
875
876
  autoSend?: boolean, // if true, cron fires each year on scheduledSendMMDD
876
877
  scheduledSendMMDD?: string, // e.g. "09-15" — MM-DD of annual auto-send
877
878
  yearGroupsIncluded?: number[], // which year groups receive Form A; default [7,8,9,10,11]
878
879
  closeAfterDays?: number, // default 21 — link validity window
879
880
  },
881
+ // DESTINATIONS SETUP + ANNUAL AUTO-PROVISIONING (Form A + Form B + checkpoints)
882
+ // Written by the setup wizard (aspirations-saveDestinationsConfig); read by
883
+ // destinationsProvisionCron each September to create that year's surveys/groups.
884
+ destinationsConfig?: DestinationsConfig,
880
885
  acceptingAlumni?: boolean,
881
886
  approveAlumni?: boolean,
882
887
  shareAlumni?: boolean
@@ -1895,7 +1900,68 @@ export type AspirationCycle = {
1895
1900
  reminderSentAt?: string, // ISO — day-14 reminder fire time
1896
1901
  aggregates?: AspirationAggregates, // pre-aggregated response data for dashboard charts
1897
1902
  emailTemplateId?: string, // optional custom email template; falls back to system default
1898
- studentSelection?: string, // JSON-serialised DataViewerSelectionBackend — audit of staff-picked recipients
1903
+ studentSelection?: string, // JSON-serialised DataViewerSelectionBackend — audit of staff-picked recipients (or the rule to re-resolve when resolveRecipientsAtSend)
1904
+ autoProvisioned?: boolean, // created by destinationsProvisionCron from the institute's DestinationsConfig, not by staff
1905
+ resolveRecipientsAtSend?: boolean, // true on auto-provisioned cycles — aspirationRequests are fanned out from studentSelection when emails fire, not at creation
1906
+ }
1907
+
1908
+ /**
1909
+ * Extra recipient constraints beyond "active student in the target year group".
1910
+ * Same shape as a cohortFilters entry. Empty/absent = every active student in the
1911
+ * year group. Stored on DestinationsConfig and re-resolved at each send so the
1912
+ * cohort always reflects the live roster (students roll up a year each September).
1913
+ */
1914
+ export type DestinationsRecipientFilter = {k: string, e?: WhereFilterOp, v: unknown}[];
1915
+
1916
+ /** One scheduled survey in a year's aspiration programme. `sendMMDD` is "MM-DD". */
1917
+ export type AspirationSurveySlot = {sendMMDD: string, label?: string};
1918
+
1919
+ /**
1920
+ * One-time Destinations setup, saved on institutes/{oId}.destinationsConfig by the
1921
+ * setup wizard. destinationsProvisionCron reads it each year to auto-create that
1922
+ * year's aspiration cycles and leaver groups. All MM-DD strings are zero-padded
1923
+ * (e.g. "09-15"). Recipients are NOT frozen here — only the filter rule is stored;
1924
+ * the actual student list is resolved when each form's emails fire.
1925
+ */
1926
+ export type DestinationsConfig = {
1927
+ // ── Aspirations (Form A) ──
1928
+ aspirations: {
1929
+ enabled: boolean,
1930
+ yearGroups: number[], // e.g. [7,8,9,10,11]
1931
+ /** Shared schedule applied to every selected year group (1–3 sends/year). */
1932
+ surveys: AspirationSurveySlot[],
1933
+ /** Optional per-year-group override. When a year group key is present its
1934
+ * schedule REPLACES `surveys` for that year group only. */
1935
+ surveysByYearGroup?: {[yearGroup: string]: AspirationSurveySlot[]},
1936
+ closeAfterDays: number, // default 21
1937
+ /** Extra constraints on top of "active Year-N student". Re-resolved each send. */
1938
+ recipientFilters?: DestinationsRecipientFilter,
1939
+ },
1940
+ // ── Leavers (Form B + checkpoints) ──
1941
+ leavers: {
1942
+ enabled: boolean,
1943
+ yearGroups: number[], // subset of [11, 13]
1944
+ intentionsSendMMDD: string, // Form B, before they leave — default "06-15"
1945
+ resultsDay: {enabled: boolean, sendMMDD: string}, // default "08-29"
1946
+ christmas: {enabled: boolean, sendMMDD: string}, // default "12-08"
1947
+ /** true → every student in these groups leaves (no internal sixth form). */
1948
+ allStudentsLeave?: boolean,
1949
+ recipientFilters?: DestinationsRecipientFilter,
1950
+ },
1951
+ // ── Alumni (mirrors the institute root flags) ──
1952
+ alumni: {
1953
+ acceptingAlumni: boolean,
1954
+ approveAlumni: boolean,
1955
+ alumniConversations: boolean,
1956
+ visibleToStudents: boolean, // default visibility for new alumni records
1957
+ },
1958
+ /** MM-DD on which each new academic year's objects are created. Default "09-01". */
1959
+ provisionMMDD: string,
1960
+ /** e.g. "2026/27" — last academic year the cron provisioned. Guards double-provisioning. */
1961
+ lastProvisionedYear?: string,
1962
+ setupCompletedAt: string, // ISO — stamped server-side on first save
1963
+ setupBy: string, // staff uid — stamped server-side
1964
+ updatedAt?: string,
1899
1965
  }
1900
1966
 
1901
1967
  /**
@@ -3036,6 +3102,12 @@ export type LeaverGroup = {
3036
3102
  * capture (and aren't seeded as alumni). */
3037
3103
  allStudentsLeave?: boolean,
3038
3104
 
3105
+ /** Created by destinationsProvisionCron from the institute's DestinationsConfig
3106
+ * (not via the manual New Leaver Group flow). Auto-provisioned groups defer
3107
+ * recipient fan-out: leaverRequests are built from `students` when invite
3108
+ * emails fire, so the cohort is always resolved against the live roster. */
3109
+ autoProvisioned?: boolean,
3110
+
3039
3111
  /** Post-leaving checkpoint schedule. Absent = checkpoints disabled for this group. */
3040
3112
  checkpointConfig?: {
3041
3113
  resultsDay?: {enabled: boolean, sendAt: string, emailTemplateId?: string}, // ISO datetime