Skip to content

Commit ad72151

Browse files
committed
feat: implement comprehensive meeting attendance tracking system
- Add database schema for meetings, meeting events, and attendance - New enums: meeting_status, meeting_event_type, attendance_event_type, scan_method - All enums use lowercase_snake_case to match project conventions - New tables: meeting, meeting_event, attendance with proper relations - Indexes on meeting_id and user_id for performance - Implement server-side logic - Meeting state management (upcoming/ongoing/recess/finished) - QR token utilities (already from phase 1) - Add admin UI for meetings management - List/create meetings page with status badges - Meeting detail page with event timeline and status transitions - Attendees page with filtering, search, and CSV export - QR code scanner page for check-in/check-out using qr-scanner library - Manual check-in/check-out functionality - Features - Automatic toggle between check_in/check_out based on current status - Meeting recess support with optional bulk check-out - Real-time attendance tracking with timestamps - Export attendance data to CSV - Comprehensive E2E tests for all workflows - Add translations (fi/en) for meetings UI - Add navigation item for Meetings in admin sidebar This is phase 2 of the QR code system - focuses on admin tools for meeting attendance. Phase 1 (member QR verification) already merged. Phase 3 (public attendance sharing) will come later.
1 parent 2005214 commit ad72151

28 files changed

Lines changed: 3586 additions & 4 deletions
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
CREATE TYPE "public"."attendance_event_type" AS ENUM('check_in', 'check_out');--> statement-breakpoint
2+
CREATE TYPE "public"."meeting_event_type" AS ENUM('start', 'recess_start', 'recess_end', 'finish');--> statement-breakpoint
3+
CREATE TYPE "public"."meeting_status" AS ENUM('upcoming', 'ongoing', 'recess', 'finished');--> statement-breakpoint
4+
CREATE TYPE "public"."scan_method" AS ENUM('qr_scan', 'manual');--> statement-breakpoint
5+
CREATE TABLE "attendance" (
6+
"id" text PRIMARY KEY NOT NULL,
7+
"meeting_id" text NOT NULL,
8+
"user_id" text NOT NULL,
9+
"event_type" "attendance_event_type" NOT NULL,
10+
"scan_method" "scan_method" NOT NULL,
11+
"scanned_by" text NOT NULL,
12+
"timestamp" timestamp with time zone DEFAULT now() NOT NULL
13+
);
14+
--> statement-breakpoint
15+
CREATE TABLE "meeting" (
16+
"id" text PRIMARY KEY NOT NULL,
17+
"name" text NOT NULL,
18+
"description" text,
19+
"status" "meeting_status" DEFAULT 'upcoming' NOT NULL,
20+
"started_at" timestamp with time zone,
21+
"finished_at" timestamp with time zone,
22+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
23+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
24+
);
25+
--> statement-breakpoint
26+
CREATE TABLE "meeting_event" (
27+
"id" text PRIMARY KEY NOT NULL,
28+
"meeting_id" text NOT NULL,
29+
"event_type" "meeting_event_type" NOT NULL,
30+
"notes" text,
31+
"timestamp" timestamp with time zone DEFAULT now() NOT NULL
32+
);
33+
--> statement-breakpoint
34+
ALTER TABLE "member" ALTER COLUMN "status" SET DATA TYPE text;--> statement-breakpoint
35+
DROP TYPE "public"."member_status";--> statement-breakpoint
36+
CREATE TYPE "public"."member_status" AS ENUM('awaiting_payment', 'awaiting_approval', 'active', 'expired', 'cancelled');--> statement-breakpoint
37+
ALTER TABLE "member" ALTER COLUMN "status" SET DATA TYPE "public"."member_status" USING "status"::"public"."member_status";--> statement-breakpoint
38+
ALTER TABLE "attendance" ADD CONSTRAINT "attendance_meeting_id_meeting_id_fk" FOREIGN KEY ("meeting_id") REFERENCES "public"."meeting"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
39+
ALTER TABLE "attendance" ADD CONSTRAINT "attendance_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
40+
ALTER TABLE "attendance" ADD CONSTRAINT "attendance_scanned_by_user_id_fk" FOREIGN KEY ("scanned_by") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
41+
ALTER TABLE "meeting_event" ADD CONSTRAINT "meeting_event_meeting_id_meeting_id_fk" FOREIGN KEY ("meeting_id") REFERENCES "public"."meeting"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
42+
CREATE INDEX "idx_attendance_meeting_id" ON "attendance" USING btree ("meeting_id");--> statement-breakpoint
43+
CREATE INDEX "idx_attendance_user_id" ON "attendance" USING btree ("user_id");--> statement-breakpoint
44+
CREATE INDEX "idx_meeting_event_meeting_id" ON "meeting_event" USING btree ("meeting_id");

0 commit comments

Comments
 (0)