1. 공교육 교무실과 군 연구실의 일정 관리 딜레마: "빅테크 클라우드 동기화와 폐쇄망 고립의 갈림길"
현대 공공 교육과 국방 행정 현장에서 일정 관리 소프트웨어는 필수적이지만, 다음과 같은 보안 및 운영상 장벽이 상존합니다:
- 국가 정보보안 지침과 클라우드 일정 업로드 금지: 공공기관 PC에서 생성된 주요 업무 일정을 민간 퍼블릭 클라우드에 연동하는 것은 공공 데이터 외부 유출 규정에 저촉될 수 있습니다.
- 물리적 망분리 환경에서의 일정 백지화: 폐쇄망 인트라넷 PC에서는 인터넷 접속이 불가능하므로, 교사나 지휘관이 본인의 주요 업무 일정을 확인하기 위해 개인 스마트폰을 뒤적이거나 탁상 달력에 수기로 메모하는 비효율이 반복됩니다.
- 복잡한 기업용 그룹웨어의 조작 피로: 교육행정정보시스템(NEIS)이나 온-나라 시스템의 일정 관리 기능은 페이지 로딩이 느리고 조작이 번거로워 일상적인 업무 흐름 속에서 즉시 열어보기가 어렵습니다.
2. 상용 클라우드 캘린더(Google/Outlook)의 구조적 한계: "계정 강제, 로컬 오프라인 부재, 데이터 유출 위험"
빅테크가 제공하는 범용 캘린더 서비스들은 다음과 같은 구조적 제약을 지닙니다:
- 개인 구글/MS 계정 로그인 강제: 공용 PC나 전산실 단말기에서 개인 계정으로 로그인해야 하므로 자동 로그인으로 인한 타인의 계정 무단 도용 위험이 매우 큽니다.
- 과도한 웹 런타임 메모리 소모: 브라우저 탭 하나를 띄워두는 것만으로 200MB 이상의 메모리를 점유하여 저사양 행정용 PC의 속도를 저하시킵니다.
- 서버 장애 시 업무 마비: 2024년 글로벌 클라우드 서비스 중단 사태처럼 외부 데이터센터에 장애가 발생하면 즉시 전산실 전체의 일정 조회가 마비됩니다.
3. 42셀(6주 × 7일) 가변 월력 동적 매트릭스 렌더링 알고리즘
달력의 시작 요일은 매달 달라지며, 한 달이 5주로 끝나는 경우도 있고 6주에 걸치는 경우도 있습니다. ZeliCal은 UI 그리드의 크기가 덜컹거리며 변하는 현상을 원천 방지하기 위해 고정형 42셀(6 × 7) 매트릭스 구조를 채택하였습니다.
해당 월의 1일이 시작하는 요일(DayOfWeek)을 구한 뒤, 음수 오프셋(-startDayOfWeek)을 더해 첫 번째 일요일 날짜(startDate)를 산출하고 42회 연속 루프를 수행합니다:
private void RenderCalendar()
{
MonthYearText.Text = string.Format(Loc.Get("Cal_MonthYear"), _currentDate.Year, _currentDate.Month);
// 1. 당월 1일의 요일 오프셋 계산 (0 = 일요일, 6 = 토요일)
var firstDayOfMonth = new DateTime(_currentDate.Year, _currentDate.Month, 1);
int startDayOfWeek = (int)firstDayOfMonth.DayOfWeek;
// 2. 캘린더 첫 번째 칸에 표시될 시작 날짜 산출 (이전 달의 마지막 일요일)
var startDate = firstDayOfMonth.AddDays(-startDayOfWeek);
// 3. 당월 등록된 전체 일정 로컬 캐시에서 조회
var schedules = CalendarService.GetItemsForMonth(_currentDate.Year, _currentDate.Month);
// 4. 42개 셀(6주 x 7일) 순차 렌더링
for (int i = 0; i < 42; i++)
{
var currentDate = startDate.AddDays(i);
var cell = _cells[i];
_cellDates[cell] = currentDate;
bool isCurrentMonth = currentDate.Month == _currentDate.Month;
bool isToday = currentDate.Date == DateTime.Now.Date;
bool isSunday = currentDate.DayOfWeek == DayOfWeek.Sunday;
bool isSaturday = currentDate.DayOfWeek == DayOfWeek.Saturday;
// 오늘 날짜 젤리 그린(#300EA76C) 하이라이트
cell.Background = isToday
? new SolidColorBrush(Color.FromArgb(0x30, 0x0E, 0xA7, 0x6C))
: new SolidColorBrush(Color.FromArgb(0x10, 0xFF, 0xFF, 0xFF));
// 날짜 텍스트 투명도 자동 계층화 (당월 1.0 vs 전달/다음달 0.3)
var dateText = new TextBlock
{
Text = currentDate.Day.ToString(),
FontSize = 14,
FontWeight = FontWeights.SemiBold,
Opacity = isCurrentMonth ? 1.0 : 0.3
};
if (isSunday) dateText.Foreground = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0x55, 0x55));
if (isSaturday) dateText.Foreground = new SolidColorBrush(Color.FromArgb(0xFF, 0x55, 0xAA, 0xFF));
// ... 날짜별 일정 칩(Chip) 바인딩
}
}
이 알고리즘을 통해 전월과 차월의 경계 날짜들이 자연스러운 투명도(Opacity 0.3)로 블러링되어, 사용자는 월을 넘나드는 연휴나 시험 기간을 단 0.1초 만에 인지할 수 있습니다.
4. CalendarService 로컬 샌드박스 영속화 파이프라인 (인메모리 캐시 & Indented JSON)
ZeliCal의 데이터 관리를 담당하는 CalendarService는 윈도우 OS의 표준 로컬 데이터 저장소인 %LocalAppData%\ZeliDesk\Calendar\schedules.json을 사용합니다.
자주 발생하는 월 전환 및 조회 작업에서 디스크 I/O 병목을 제거하기 위해 인메모리 정적 캐시(Static Cache)를 유지하며, 수정이 발생할 때만 읽기 쉬운 포맷(Indented JSON)으로 디스크에 커밋합니다:
public static class CalendarService
{
private static readonly string _filePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"ZeliDesk", "Calendar", "schedules.json");
private static List<CalendarItem> _cache = null;
public static List<CalendarItem> LoadAll()
{
if (_cache != null) return _cache; // 메모리 캐시 즉각 반환 (0ms)
if (!File.Exists(_filePath)) return _cache = new List<CalendarItem>();
try
{
var json = File.ReadAllText(_filePath);
_cache = JsonSerializer.Deserialize<List<CalendarItem>>(json) ?? new();
}
catch { _cache = new(); }
return _cache;
}
public static void SaveAll(List<CalendarItem> items)
{
_cache = items;
try
{
var json = JsonSerializer.Serialize(_cache, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(_filePath, json);
}
catch { }
}
public static List<CalendarItem> GetItemsForMonth(int year, int month)
{
return LoadAll().Where(x => x.Date.Year == year && x.Date.Month == month).ToList();
}
}
5. Cell_Tapped 대화형 모달(ContentDialog)과 원터치 일정 CRUD 거버넌스
기존 캘린더 프로그램들은 일정을 하나 등록하려면 별도의 거대한 입력 폼 창이 열리거나 새 탭으로 이동해야 했습니다.
ZeliCal은 사용자가 특정 날짜의 셀을 가볍게 클릭(Tapped)하는 순간, WinUI 3 ContentDialog 인플레이스 모달을 띄워 제목과 메모를 즉시 작성·수정·삭제할 수 있는 원터치 CRUD 환경을 제공합니다:
6. TextTrimming 말줄임 칩 렌더링 및 휴일·주말(토/일) 고대비 시각화
교무 일정은 "1학기 방과후학교 수강신청 안내문 발송 및 행정실 정산 보고"처럼 제목이 긴 경우가 많습니다. 셀 크기를 벗어나는 긴 텍스트가 줄바꿈되어 캘린더 그리드가 세로로 깨지는 문제를 방지하기 위해, ZeliCal은 하드웨어 가속 말줄임표(CharacterEllipsis) 칩 렌더링을 적용하였습니다:
- 자동 말줄임 처리:
TextTrimming = TextTrimming.CharacterEllipsis를 통해 셀 너비를 초과하는 긴 텍스트를"1학기 방과후학교..."형태로 단정하게 축약합니다. - 고대비 주말 및 휴일 식별: 일요일은 명확한 적색(
#FF5555), 토요일은 청색(#55AAFF), 평일은 백색(#FFFFFF)으로 텍스트 색상을 분리하여 직관적인 요일 구분을 보장합니다. - 포인터 호버 피드백: 마우스 커서가 올라간 셀은
PointerEntered이벤트를 통해 은은한 글라스모피즘 하이라이트(#25FFFFFF)가 활성화되어 정밀한 클릭을 돕습니다.
7. 캘린더 솔루션 비교 분석 (Google Calendar vs Outlook vs 종이 달력 vs ZeliCal)
| 비교 항목 | 구글 캘린더 (Google Calendar) | MS 아웃룩 (Outlook Calendar) | 탁상용 종이 달력 | ZeliDesk ZeliCal 온디바이스 |
|---|---|---|---|---|
| 데이터 저장 위치 | 구글 클라우드 해외 서버 | MS 클라우드 해외 서버 | 오프라인 실물 | 완전 격리 로컬 OS 샌드박스 (JSON) |
| 폐쇄망 / Air-Gap 구동 | 불가 (인터넷 필수) | 오프라인 제한적 (계정 동기화 필요) | 완벽 구동 | 100% 오프라인 Zero-Telemetry |
| 계정 로그인 요구 | Google 계정 필수 | Microsoft 계정 필수 | 없음 | 로그인 0회 / Zero-Config |
| 그리드 레이아웃 구조 | 동적 반응형 (주/월 변환) | 고정 데스크톱 뷰 | 고정 인쇄면 | 42셀 동적 매트릭스 고정 그리드 |
| 메모리 점유율 (RAM) | 250MB ~ 500MB (웹 탭) | 300MB ~ 800MB | 0MB | 초경량 15MB 이하 (WinUI 3) |
| Always-On-Top 플로팅 | 불가 (창 뒤로 숨음) | 불가 | 책상 위 상시 비치 | WindowKit 하드웨어 가속 원터치 핀 |
8. 결론: "외부 서버 연결 0바이트, 신뢰할 수 있는 공교육·국방 온디바이스 학사 거버넌스"
학사 일정과 군사 훈련 계획은 단순한 날짜의 나열이 아니라, 한 학기와 한 해의 조직 운영을 이끄는 핵심 나침반입니다. 이러한 중요한 정보를 다루는 도구가 클라우드 접속 장애나 계정 관리 실수로 흔들려서는 안 됩니다.
ZeliDesk의 ZeliCal은 복잡한 설치나 회원가입 절차 없이, 단 0초 만에 42셀의 미려한 매트릭스를 펼쳐 교원과 연구원의 일정을 완벽하게 보호합니다. 가장 순수하고 독립적인 온디바이스 기술로 완성된 ZeliCal과 함께, 대한민국의 스마트 교실과 국방 교육 현장은 흔들림 없는 시간과 일정의 주권을 확립하게 되었습니다.