Synaplan
기업을 위한 오픈소스 AI 플랫폼
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗個別指導塾向けのシフト管理システム。 講師・教室長がスマホ / PC から使える Web アプリです。
UI 仕様書は docs/shift-manager_UI仕様書.pdf にあります。
docs/design/ui-refresh/。| 層 | 採用 |
|---|---|
| フレームワーク | Next.js 16 (App Router, TypeScript, Turbopack) |
| UI | Tailwind CSS v4 + shadcn/ui (new-york) + lucide-react |
| フォーム / バリデーション | react-hook-form + zod |
| 認証 / ストレージ | Supabase (Auth + Storage + Postgres) |
| DB アクセス | Drizzle ORM (postgres-js driver) |
| 確定シフト取り込み | csv-parse / iconv-lite(文字コード変換) |
| 日付 | date-fns / date-fns-tz(JST 固定) |
npm install
Northeast Asia (Tokyo) 推奨)https://<project-ref>.supabase.co
⚠️ 末尾の /rest/v1/ を含めない(含めると Auth が PostgREST に流れて 404 になる)cp .env.local.example .env.local
.env.local を編集して上記 4 つの値を設定。DATABASE_URL のプレースホルダ <project-ref> を実際のプロジェクト ref に、<password> を実際の DB パスワードに置換するのを忘れずに。
Next.js も Drizzle CLI も
.env.localを読みます。.envではないので注意。
# スキーマから SQL を生成(既に generate 済みなら不要)
npm run db:generate
# 適用
npm run db:migrate
Supabase ダッシュボードの SQL Editor で実行:
insert into slot_definitions (slot_number, label, start_time, end_time) values
(1, '1限', '09:30', '10:55'),
(2, '2限', '11:00', '12:25'),
(3, '3限', '12:30', '13:55'),
(4, '4限', '14:00', '15:25'),
(5, '5限', '15:30', '16:55'),
(6, '6限', '17:00', '18:25'),
(7, '7限', '18:30', '19:55'),
(8, '8限', '20:00', '21:25');
admin ユーザーは Authentication > Users > Add user(Auto Confirm User を ON)で作成し、
表示される User UID を控えて profiles に対応行を追加:
-- roles は user_role[] 配列(#111 で旧 role 単一列から移行)。
-- 教室長兼講師にする場合は '{admin,tutor}' のように複数指定する。
insert into profiles (id, display_name, roles, email) values
('<コピーした User UID>', '教室長', '{admin}', '[email protected]');
テスト用に CSV の講師名を一括登録したい場合は
scripts/README.md の seed-stub-tutors.ts を参照。
npm run dev
http://localhost:3000 を開くと /login にリダイレクトされます。
Supabase Auth で作成したユーザーに対し、profiles テーブルへ
roles に 'admin' を含めて手動登録するとダッシュボードに入れます。
src/
├─ app/ # Next.js App Router
│ ├─ login/ # ログイン画面
│ ├─ auth/signout/ # POST /auth/signout でサインアウト
│ ├─ tutor/ # 講師用ページ (layout でガード)
│ │ ├─ fixed-shifts/ # 固定シフト登録
│ │ ├─ training/ # 講習期間の日別希望提出
│ │ ├─ absences/ # 欠勤申請
│ │ ├─ swaps/ # 交代申請
│ │ └─ open-swaps/ # 代講募集・応募
│ └─ admin/ # 教室長用ページ (layout でガード)。/admin = ダッシュボード
│ ├─ periods/ # 講習期間と締切の管理
│ ├─ submission-periods/ # 月別提出期間
│ ├─ regular-periods/ # レギュラー(期)提出期間
│ ├─ fixed-shifts/ # 固定シフト俯瞰
│ ├─ tutors/ # 講師管理・招待・連携
│ ├─ admins/ # 教室長管理
│ ├─ training/ # 講習希望の俯瞰(ヒートマップ)
│ ├─ weekly/ # 週次シフト表
│ ├─ uploads/ # 確定シフト CSV アップロード・公開
│ └─ requests/ # 欠勤・交代申請の承認(Tabs)
├─ components/
│ ├─ admin-shell.tsx # 教室長(PC)シェル: ヘッダー + 横ナビ
│ ├─ tutor-shell.tsx # 講師(スマホ)シェル: ヘッダー + 下部タブ
│ ├─ segmented-nav.tsx # グループ内サブナビ(セグメント)
│ ├─ admin-section-nav.tsx # 教室長グループのサブナビ定義
│ ├─ tutor-requests-nav.tsx # 講師「申請」グループのサブナビ定義
│ └─ ui/ # shadcn/ui プリミティブ
├─ db/
│ ├─ client.ts # Drizzle + postgres-js
│ └─ schema.ts # 全テーブル定義
├─ lib/
│ ├─ auth.ts # requireSession / requireRole(roles contains 判定)
│ ├─ profile-active.ts # 有効/無効切替の共有ガード(最後の admin 保護)
│ ├─ supabase/ # ブラウザ / サーバー / middleware クライアント
│ ├─ week.ts # JST 週・日付ユーティリティ(固定 +9h)
│ ├─ shift-constants.ts # 曜日・コマ定義
│ ├─ slot-meta.ts # コマ定義の取得
│ ├─ tutor-schedule.ts # 講師の確定シフト集計
│ ├─ admin-schedule.ts # 教室長向け週次スケジュール
│ ├─ training.ts # 講習期間・日別希望
│ ├─ training-overview.ts # 講習希望の俯瞰
│ ├─ absences.ts # 欠勤申請ロジック
│ ├─ swaps.ts # 交代・代講ロジック
│ ├─ shift-csv-parser.ts # 確定シフト CSV のパース
│ ├─ upload-commit.ts # 確定シフト CSV の取り込み確定
│ ├─ mapping-validation.ts # CSV 上の講師名 ↔ profiles マッピング検証
│ ├─ period-status.ts # 期間バッジ色・受付状態トークン
│ ├─ avatar.ts # アバター色・頭文字ヘルパ
│ ├─ db-errors.ts # 一意制約違反等の判定
│ └─ utils.ts # cn() ヘルパー
└─ middleware.ts # セッション更新 + 未ログインリダイレクト
profiles.roles(user_role[] = tutor / admin の配列)。
requireRole は「指定ロールを含むか」(contains) で判定するため、{admin,tutor} の兼任が可能(#111)docs/design/dual-role.md(#146 で仕様確定)src/app/{tutor,admin}/layout.tsx 内の requireRole でガードデータアクセスは全て サーバー仲介(Server Component / Server Action が
requireRole で認可 → Drizzle が postgres ロールで実行)。postgres は
BYPASSRLS=true かつ全 public テーブルの owner。一方クライアント側で
公開される anon キーは GoTrue 認証専用で、アプリテーブルを JWT で
直接参照しない。
この構成に対し migration 0007_rls.sql で全 public テーブルに:
ENABLE ROW LEVEL SECURITYREVOKE ALL ... FROM anon, authenticatedを適用。結果:
/rest/v1/...)は
permission denied で完全遮断(公開 anon キー悪用による PII 漏洩を解消)postgres / BYPASSRLS+owner)は無影響auth スキーマ)も無影響여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗