Skip to content

Commit 2d4dfcb

Browse files
chore: simple working auth
1 parent aa6cd72 commit 2d4dfcb

18 files changed

Lines changed: 1937 additions & 179 deletions

AGENTS.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,19 @@ Any future automated changes (by tools or agents) must respect these rules.
1212
- `(admin)` for the admin interface.
1313
- Data access is via **Drizzle ORM** (`src/server/db.ts`, `src/server/db/schema.ts`) against PostgreSQL with migrations driven by `drizzle.config.ts` and the `drizzle/` directory.
1414
- Application data and metadata shapes live in `src/types/application-data.ts`; prefer these shared `ApplicationData`, `ApplicationMeta`, and `NormalizedApplication` aliases whenever you read or write applicant records so the loose JSON payloads remain typed.
15-
- Application rows now store data and meta in dedicated columns (no JSON `data`/`meta` fields):
15+
- Application rows now store data and meta in dedicated columns (no JSON `data`/`meta` fields), and IDs are generated with **cuid2** (`@paralleldrive/cuid2`):
1616
- Data columns: `first_name`, `last_name`, `birth_date`, `who_are_you`, `phone_numbers`, `country`, `city`, `where_are_you`, `has_id_cart_or_passport`, `id_cart_or_passport_or_receipt`, `high_school_over`, `high_school_gce_ol_probatoir_date`, `high_school_gce_ol_probatoire_certificates`, `high_school_gce_al_bac_date`, `high_school_gce_al_bac_certificates`, `university_student`, `university_start_date`, `university_end_date`, `university_certificates`.
1717
- Meta columns: `meta_invited_statuses`, `meta_document_statuses`, `meta_document_comments`.
1818
- Always convert between DB rows and typed shapes via `src/server/application-normalizer.ts` (`buildApplicationData`, `buildApplicationMeta`, `mapApplicationDataToColumns`); do not reintroduce JSON blobs.
19+
- Application relations are normalized (all PKs use cuid2 defaults):
20+
- `application_program_choice`: program selection, rank, campus/start term/study mode/funding.
21+
- `application_education`: education entries by type (GCE_OL, GCE_AL, BAC, PROBATOIRE, BTS, BACHELOR, OTHER), with session year, candidate number, status, dates, GPA, etc.
22+
- `application_document`: per-document rows with kind, status, reviewer comment; can link to an education row.
23+
- `application_phone`: per phone with kind (PRIMARY/SECONDARY/GUARDIAN/OTHER) and call flags.
24+
- `application_consent`: per-consent records.
25+
- `application_status_history`: status transitions with actor.
26+
- Applicant edit guardrails: applicants may update only when status is `INIT` or `NEED_APPLICANT_INTERVENTION`; other statuses forbid applicant-side updates.
27+
- Application status enum includes `NEED_APPLICANT_INTERVENTION` (surface this in UI/status mapping).
1928
- **tRPC** is the single backend API surface:
2029
- Server router at `src/server/api/*` and `src/app/api/trpc/[trpc]/route.ts`.
2130
- Shared tRPC clients:
@@ -105,4 +114,5 @@ These conventions must be followed for all new or modified code:
105114
## Database & Migrations
106115

107116
- Drizzle migrations live in `drizzle/`; the current migration splitting application JSON fields is `drizzle/0000_expand_application_fields.sql` with journal tracking under `drizzle/meta/_journal.json`.
117+
- Drizzle migration `0001_application_relations.sql` adds the normalized relations above and the new status; journal tracked in `drizzle/meta/_journal.json`.
108118
- Migrations runner container is defined at `companions/migrations/Dockerfile` and `companions/migrations/entrypoint.sh`; it uses `yarn drizzle-kit migrate` (no Prisma) and requires `DATABASE_URL` at runtime. Build with `docker build -f companions/migrations/Dockerfile -t gis-migrations .` and run with `docker run --rm -e DATABASE_URL=... gis-migrations`.

compose.yaml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,8 @@ services:
6565
OTEL_EXPORTER_OTLP_ENDPOINT: "http://tracking:4318"
6666
S3_ENDPOINT: minio
6767
depends_on:
68-
- redis
6968
- postgres
7069
- adminer
7170
- migrations
7271
- minio
73-
74-
redis:
75-
image: bitnami/redis
76-
environment:
77-
ALLOW_EMPTY_PASSWORD: yes
78-
ports:
79-
- "6379:6379"
72+

drizzle/0000_lying_sharon_carter.sql

Lines changed: 0 additions & 93 deletions
This file was deleted.
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
CREATE TYPE "public"."ApplicationDocumentKind" AS ENUM('ID', 'GCE_OL_CERT', 'PROBATOIRE_CERT', 'GCE_AL_CERT', 'BAC_CERT', 'UNIVERSITY_CERT', 'RECOMMENDATION', 'MOTIVATION', 'CV', 'TRANSCRIPT', 'OTHER');--> statement-breakpoint
2+
CREATE TYPE "public"."ApplicationDocumentStatus" AS ENUM('approved', 'rejected', 'pending');--> statement-breakpoint
3+
CREATE TYPE "public"."ApplicationEducationStatus" AS ENUM('IN_PROGRESS', 'COMPLETED');--> statement-breakpoint
4+
CREATE TYPE "public"."ApplicationEducationType" AS ENUM('GCE_OL', 'GCE_AL', 'BAC', 'PROBATOIRE', 'BTS', 'BACHELOR', 'OTHER');--> statement-breakpoint
5+
CREATE TYPE "public"."ApplicationPhoneKind" AS ENUM('PRIMARY', 'SECONDARY', 'GUARDIAN', 'OTHER');--> statement-breakpoint
6+
CREATE TYPE "public"."ApplicationStatus" AS ENUM('INIT', 'PHONE_INTERVIEW_PHASE', 'ONSITE_INTERVIEW_PHASE', 'ACCEPTED', 'REJECTED', 'NEED_APPLICANT_INTERVENTION');--> statement-breakpoint
7+
CREATE TABLE "account" (
8+
"id" text PRIMARY KEY NOT NULL,
9+
"account_id" text NOT NULL,
10+
"provider_id" text NOT NULL,
11+
"user_id" text NOT NULL,
12+
"access_token" text,
13+
"refresh_token" text,
14+
"id_token" text,
15+
"access_token_expires_at" timestamp,
16+
"refresh_token_expires_at" timestamp,
17+
"scope" text,
18+
"password" text,
19+
"created_at" timestamp DEFAULT now() NOT NULL,
20+
"updated_at" timestamp NOT NULL
21+
);
22+
--> statement-breakpoint
23+
CREATE TABLE "application_consent" (
24+
"id" text PRIMARY KEY NOT NULL,
25+
"application_id" text NOT NULL,
26+
"consent_type" text NOT NULL,
27+
"value" boolean NOT NULL,
28+
"granted_at" timestamp DEFAULT now() NOT NULL,
29+
"version" text
30+
);
31+
--> statement-breakpoint
32+
CREATE TABLE "application_document" (
33+
"id" text PRIMARY KEY NOT NULL,
34+
"application_id" text NOT NULL,
35+
"education_id" text,
36+
"kind" "ApplicationDocumentKind" NOT NULL,
37+
"name" text NOT NULL,
38+
"public_url" text NOT NULL,
39+
"status" "ApplicationDocumentStatus" DEFAULT 'pending' NOT NULL,
40+
"reviewer_comment" text,
41+
"created_at" timestamp DEFAULT now() NOT NULL,
42+
"updated_at" timestamp DEFAULT now() NOT NULL
43+
);
44+
--> statement-breakpoint
45+
CREATE TABLE "application_education" (
46+
"id" text PRIMARY KEY NOT NULL,
47+
"application_id" text NOT NULL,
48+
"type" "ApplicationEducationType" NOT NULL,
49+
"school_name" text NOT NULL,
50+
"city" text,
51+
"country" text,
52+
"field_of_study" text,
53+
"start_date" date,
54+
"end_date" date,
55+
"completion_date" date,
56+
"status" "ApplicationEducationStatus" DEFAULT 'IN_PROGRESS',
57+
"gpa" text,
58+
"candidate_number" text,
59+
"session_year" integer,
60+
"created_at" timestamp DEFAULT now() NOT NULL,
61+
"updated_at" timestamp DEFAULT now() NOT NULL
62+
);
63+
--> statement-breakpoint
64+
CREATE TABLE "application_phone" (
65+
"id" text PRIMARY KEY NOT NULL,
66+
"application_id" text NOT NULL,
67+
"phone_number" text NOT NULL,
68+
"whatsapp_call" boolean DEFAULT false NOT NULL,
69+
"normal_call" boolean DEFAULT false NOT NULL,
70+
"kind" "ApplicationPhoneKind" DEFAULT 'PRIMARY' NOT NULL,
71+
"created_at" timestamp DEFAULT now() NOT NULL
72+
);
73+
--> statement-breakpoint
74+
CREATE TABLE "application_program_choice" (
75+
"id" text PRIMARY KEY NOT NULL,
76+
"application_id" text NOT NULL,
77+
"rank" integer DEFAULT 1 NOT NULL,
78+
"program_code" text NOT NULL,
79+
"campus" text,
80+
"start_term" text,
81+
"study_mode" text,
82+
"funding_type" text,
83+
"created_at" timestamp DEFAULT now() NOT NULL,
84+
"updated_at" timestamp DEFAULT now() NOT NULL
85+
);
86+
--> statement-breakpoint
87+
CREATE TABLE "application_status_history" (
88+
"id" text PRIMARY KEY NOT NULL,
89+
"application_id" text NOT NULL,
90+
"status" "ApplicationStatus" NOT NULL,
91+
"changed_at" timestamp DEFAULT now() NOT NULL,
92+
"changed_by_id" text,
93+
"note" text
94+
);
95+
--> statement-breakpoint
96+
CREATE TABLE "application" (
97+
"id" text PRIMARY KEY NOT NULL,
98+
"created_at" timestamp DEFAULT now() NOT NULL,
99+
"updated_at" timestamp DEFAULT now() NOT NULL,
100+
"createdById" text,
101+
"first_name" text NOT NULL,
102+
"last_name" text NOT NULL,
103+
"birth_date" date NOT NULL,
104+
"who_are_you" text,
105+
"phone_numbers" jsonb DEFAULT '[]'::jsonb NOT NULL,
106+
"country" text NOT NULL,
107+
"city" text NOT NULL,
108+
"where_are_you" text,
109+
"has_id_cart_or_passport" boolean DEFAULT false NOT NULL,
110+
"id_cart_or_passport_or_receipt" jsonb DEFAULT '[]'::jsonb NOT NULL,
111+
"high_school_over" boolean DEFAULT false NOT NULL,
112+
"high_school_gce_ol_probatoir_date" date,
113+
"high_school_gce_ol_probatoire_certificates" jsonb DEFAULT '[]'::jsonb NOT NULL,
114+
"high_school_gce_al_bac_date" date,
115+
"high_school_gce_al_bac_certificates" jsonb DEFAULT '[]'::jsonb NOT NULL,
116+
"university_student" boolean DEFAULT false NOT NULL,
117+
"university_start_date" date,
118+
"university_end_date" date,
119+
"university_certificates" jsonb DEFAULT '[]'::jsonb NOT NULL,
120+
"meta_invited_statuses" jsonb DEFAULT '{}'::jsonb NOT NULL,
121+
"meta_document_statuses" jsonb DEFAULT '{}'::jsonb NOT NULL,
122+
"meta_document_comments" jsonb DEFAULT '{}'::jsonb NOT NULL,
123+
"status" "ApplicationStatus" DEFAULT 'INIT' NOT NULL,
124+
"email" text NOT NULL
125+
);
126+
--> statement-breakpoint
127+
CREATE TABLE "session" (
128+
"id" text PRIMARY KEY NOT NULL,
129+
"expires_at" timestamp NOT NULL,
130+
"token" text NOT NULL,
131+
"created_at" timestamp DEFAULT now() NOT NULL,
132+
"updated_at" timestamp NOT NULL,
133+
"ip_address" text,
134+
"user_agent" text,
135+
"user_id" text NOT NULL,
136+
"impersonated_by" text,
137+
CONSTRAINT "session_token_unique" UNIQUE("token")
138+
);
139+
--> statement-breakpoint
140+
CREATE TABLE "user" (
141+
"id" text PRIMARY KEY NOT NULL,
142+
"name" text NOT NULL,
143+
"email" text NOT NULL,
144+
"email_verified" boolean DEFAULT false NOT NULL,
145+
"image" text,
146+
"created_at" timestamp DEFAULT now() NOT NULL,
147+
"updated_at" timestamp DEFAULT now() NOT NULL,
148+
"banned" boolean DEFAULT false,
149+
"ban_reason" text,
150+
"ban_expires" timestamp,
151+
"role" text DEFAULT 'user' NOT NULL,
152+
CONSTRAINT "user_email_unique" UNIQUE("email")
153+
);
154+
--> statement-breakpoint
155+
CREATE TABLE "verification" (
156+
"id" text PRIMARY KEY NOT NULL,
157+
"identifier" text NOT NULL,
158+
"value" text NOT NULL,
159+
"expires_at" timestamp NOT NULL,
160+
"created_at" timestamp DEFAULT now() NOT NULL,
161+
"updated_at" timestamp DEFAULT now() NOT NULL
162+
);
163+
--> statement-breakpoint
164+
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
165+
ALTER TABLE "application_consent" ADD CONSTRAINT "application_consent_application_id_application_id_fk" FOREIGN KEY ("application_id") REFERENCES "public"."application"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
166+
ALTER TABLE "application_document" ADD CONSTRAINT "application_document_application_id_application_id_fk" FOREIGN KEY ("application_id") REFERENCES "public"."application"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
167+
ALTER TABLE "application_document" ADD CONSTRAINT "application_document_education_id_application_education_id_fk" FOREIGN KEY ("education_id") REFERENCES "public"."application_education"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
168+
ALTER TABLE "application_education" ADD CONSTRAINT "application_education_application_id_application_id_fk" FOREIGN KEY ("application_id") REFERENCES "public"."application"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
169+
ALTER TABLE "application_phone" ADD CONSTRAINT "application_phone_application_id_application_id_fk" FOREIGN KEY ("application_id") REFERENCES "public"."application"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
170+
ALTER TABLE "application_program_choice" ADD CONSTRAINT "application_program_choice_application_id_application_id_fk" FOREIGN KEY ("application_id") REFERENCES "public"."application"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
171+
ALTER TABLE "application_status_history" ADD CONSTRAINT "application_status_history_application_id_application_id_fk" FOREIGN KEY ("application_id") REFERENCES "public"."application"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
172+
ALTER TABLE "application_status_history" ADD CONSTRAINT "application_status_history_changed_by_id_user_id_fk" FOREIGN KEY ("changed_by_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
173+
ALTER TABLE "application" ADD CONSTRAINT "application_createdById_user_id_fk" FOREIGN KEY ("createdById") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
174+
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
175+
CREATE INDEX "account_userId_idx" ON "account" USING btree ("user_id");--> statement-breakpoint
176+
CREATE INDEX "application_consent_application_idx" ON "application_consent" USING btree ("application_id");--> statement-breakpoint
177+
CREATE INDEX "application_document_application_idx" ON "application_document" USING btree ("application_id");--> statement-breakpoint
178+
CREATE INDEX "application_document_education_idx" ON "application_document" USING btree ("education_id");--> statement-breakpoint
179+
CREATE INDEX "application_document_status_idx" ON "application_document" USING btree ("status");--> statement-breakpoint
180+
CREATE INDEX "application_document_kind_idx" ON "application_document" USING btree ("kind");--> statement-breakpoint
181+
CREATE INDEX "application_education_application_idx" ON "application_education" USING btree ("application_id");--> statement-breakpoint
182+
CREATE INDEX "application_education_type_idx" ON "application_education" USING btree ("type");--> statement-breakpoint
183+
CREATE INDEX "application_phone_application_idx" ON "application_phone" USING btree ("application_id");--> statement-breakpoint
184+
CREATE INDEX "application_program_choice_application_idx" ON "application_program_choice" USING btree ("application_id");--> statement-breakpoint
185+
CREATE INDEX "application_status_history_application_idx" ON "application_status_history" USING btree ("application_id");--> statement-breakpoint
186+
CREATE INDEX "application_created_by_id_idx" ON "application" USING btree ("createdById");--> statement-breakpoint
187+
CREATE INDEX "session_userId_idx" ON "session" USING btree ("user_id");--> statement-breakpoint
188+
CREATE INDEX "verification_identifier_idx" ON "verification" USING btree ("identifier");

0 commit comments

Comments
 (0)