Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9a671b2
refactor(nest-common): extract S3 config token into dedicated file
0-sayed Mar 17, 2026
4787074
feat(guide-booking): add attractions schema, enums, and migration
0-sayed Mar 17, 2026
7f11079
feat(guide-booking): wire app module with auth, S3, Redis, and attrac…
0-sayed Mar 17, 2026
425ac7d
docs: mark T07 Guide-Booking Attractions as complete
0-sayed Mar 17, 2026
ad1043f
fix(guide-booking): harden slug generation and enforce global uniqueness
0-sayed Mar 17, 2026
ac7e497
fix(guide-booking): fix boolean filter parsing and PATCH default over…
0-sayed Mar 17, 2026
0854c87
fix(guide-booking): set updatedAt on soft delete
0-sayed Mar 17, 2026
994836b
fix(guide-booking): add runtime JWT claim validation
0-sayed Mar 17, 2026
6dbaa1a
fix(guide-booking): fail fast on missing AWS credentials
0-sayed Mar 17, 2026
64e0cef
fix(guide-booking): use requireEnv for DATABASE_URL
0-sayed Mar 17, 2026
335a649
build: tighten tsconfig with additional strict compiler options
0-sayed Mar 17, 2026
87dbb00
build: upgrade ESLint to strictTypeChecked and stylisticTypeChecked
0-sayed Mar 17, 2026
4a0f45a
build: add ts-reset, check script, and clean up dependencies
0-sayed Mar 17, 2026
5798450
build: update knip config for stricter analysis
0-sayed Mar 17, 2026
88e81fc
refactor(nest-common): fix type safety for strict TS and ESLint
0-sayed Mar 17, 2026
36b5b1e
refactor(identity): fix type safety for strict TS and ESLint
0-sayed Mar 17, 2026
22e2211
fix: annotate catch parameter as unknown in migrate scripts
0-sayed Mar 17, 2026
895269a
docs: update CLAUDE.md banned behaviors for strict TS rules
0-sayed Mar 17, 2026
14aeabd
fix(identity): validate ms() output for JWT expiry config
0-sayed Mar 17, 2026
afc318f
fix: override fast-xml-parser to >=5.5.6 for CVE-2026-26278
0-sayed Mar 17, 2026
a3016df
fix(guide-booking): align attractions code with strict TS/ESLint rules
0-sayed Mar 17, 2026
a6dabbd
fix(nest-common): reject empty x-request-id before fallback generation
0-sayed Mar 17, 2026
887e2ea
Merge remote-tracking branch 'origin/main' into feat/guide-booking-at…
0-sayed Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/roadmap/BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

- [X] **T05** Identity: Auth Core · M · ← T01
- [X] **T06** Market: Core CRUD · M · ← T01, T03
- [ ] **T07** Guide-Booking: Attractions · M · ← T01, T04
- [x] **T07** Guide-Booking: Attractions · M · ← T01, T04
- [ ] **T08** RAG: Ingestion Pipeline · M · ← T02, T02a
- [ ] **F01** Frontend Foundation · M · ← F00
- [ ] **F12** Error Handling + Loading States · S · ← F01
Expand Down
4 changes: 2 additions & 2 deletions knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const config: KnipConfig = {
'services/guide-booking': {
entry: ['src/main.ts', 'src/db/migrate.ts'],
project: ['src/**/*.ts'],
// @hena-wadeena/types will be used as guide-booking features are built out
ignoreDependencies: ['@hena-wadeena/types', '@nestjs/testing'],
// drizzle-zod: planned for DTO generation; @hena-wadeena/types will be used as features are built out
ignoreDependencies: ['drizzle-zod', '@hena-wadeena/types', '@nestjs/testing'],
},
'services/map': {
entry: ['src/main.ts', 'src/db/migrate.ts'],
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,10 @@
"typescript-eslint": "^8.20.0",
"unplugin-swc": "^1.5.9",
"vitest": "^3.0.0"
},
"pnpm": {
"overrides": {
"fast-xml-parser": ">=5.5.6"
}
}
}
3 changes: 2 additions & 1 deletion packages/nest-common/src/modules/logger/logger.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export class LoggerModule {
: undefined,
genReqId: (req: IncomingMessage) => {
const headerId = req.headers['x-request-id'];
return (typeof headerId === 'string' ? headerId : null) ?? generateId();
const normalizedId = typeof headerId === 'string' ? headerId.trim() : '';
return normalizedId.length > 0 ? normalizedId : generateId();
},
Comment thread
idris-builds marked this conversation as resolved.
customProps: () => ({
service: serviceName,
Expand Down
1 change: 1 addition & 0 deletions packages/nest-common/src/modules/s3/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './s3.tokens';
export * from './s3.module';
export * from './s3.service';
export * from './s3.tokens';
3 changes: 2 additions & 1 deletion packages/nest-common/src/modules/s3/s3.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { DynamicModule, Global, Module } from '@nestjs/common';

import { S3Service } from './s3.service';
import { S3_CONFIG, S3ModuleOptions } from './s3.tokens';
import { S3_CONFIG } from './s3.tokens';
import type { S3ModuleOptions } from './s3.tokens';

export { S3_CONFIG };
export type { S3ModuleOptions };
Expand Down
3 changes: 2 additions & 1 deletion packages/nest-common/src/modules/s3/s3.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { Inject, Injectable, Logger } from '@nestjs/common';

import { S3_CONFIG, S3ModuleOptions } from './s3.tokens';
import { S3_CONFIG } from './s3.tokens';
import type { S3ModuleOptions } from './s3.tokens';

export interface PresignedUploadOptions {
key: string;
Expand Down
36 changes: 36 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
CREATE TYPE "guide_booking"."attraction_area" AS ENUM('kharga', 'dakhla', 'farafra', 'baris', 'balat');--> statement-breakpoint
CREATE TYPE "guide_booking"."attraction_type" AS ENUM('attraction', 'historical', 'natural', 'festival', 'adventure');--> statement-breakpoint
CREATE TYPE "guide_booking"."best_season" AS ENUM('winter', 'summer', 'spring', 'all_year');--> statement-breakpoint
CREATE TYPE "guide_booking"."best_time_of_day" AS ENUM('morning', 'evening', 'any');--> statement-breakpoint
CREATE TYPE "guide_booking"."difficulty" AS ENUM('easy', 'moderate', 'hard');--> statement-breakpoint
CREATE TABLE "guide_booking"."attractions" (
"id" uuid PRIMARY KEY NOT NULL,
"name_ar" text NOT NULL,
"name_en" text,
"slug" text NOT NULL,
Comment thread
idris-builds marked this conversation as resolved.
"type" "guide_booking"."attraction_type" NOT NULL,
"area" "guide_booking"."attraction_area" NOT NULL,
"description_ar" text,
"description_en" text,
"history_ar" text,
"best_season" "guide_booking"."best_season",
"best_time_of_day" "guide_booking"."best_time_of_day",
"entry_fee" jsonb,
"opening_hours" text,
"duration_hours" real,
"difficulty" "guide_booking"."difficulty",
"tips" text[],
"nearby_slugs" text[],
"location" geometry(point),
"images" text[],
"thumbnail" text,
"is_active" boolean DEFAULT true NOT NULL,
"is_featured" boolean DEFAULT false NOT NULL,
"rating_avg" real,
"review_count" integer DEFAULT 0,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
"deleted_at" timestamp with time zone,
CONSTRAINT "chk_attractions_duration_positive" CHECK ("guide_booking"."attractions"."duration_hours" > 0),
CONSTRAINT "chk_attractions_review_count_non_neg" CHECK ("guide_booking"."attractions"."review_count" >= 0),
Comment thread
idris-builds marked this conversation as resolved.
CONSTRAINT "chk_attractions_rating_avg_range" CHECK ("guide_booking"."attractions"."rating_avg" IS NULL OR ("guide_booking"."attractions"."rating_avg" >= 0 AND "guide_booking"."attractions"."rating_avg" <= 5))
);
--> statement-breakpoint
CREATE UNIQUE INDEX "attractions_slug_active_unique" ON "guide_booking"."attractions" USING btree ("slug") WHERE "guide_booking"."attractions"."deleted_at" IS NULL;--> statement-breakpoint
CREATE INDEX "idx_attractions_location" ON "guide_booking"."attractions" USING gist ("location");--> statement-breakpoint
CREATE INDEX "idx_attractions_type" ON "guide_booking"."attractions" USING btree ("type");--> statement-breakpoint
CREATE INDEX "idx_attractions_area" ON "guide_booking"."attractions" USING btree ("area");--> statement-breakpoint
CREATE INDEX "idx_attractions_is_active" ON "guide_booking"."attractions" USING btree ("is_active");--> statement-breakpoint
CREATE INDEX "idx_attractions_is_featured" ON "guide_booking"."attractions" USING btree ("is_featured");--> statement-breakpoint
CREATE INDEX "idx_attractions_created_at" ON "guide_booking"."attractions" USING btree ("created_at" DESC NULLS LAST);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP INDEX "guide_booking"."attractions_slug_active_unique";--> statement-breakpoint
ALTER TABLE "guide_booking"."attractions" ALTER COLUMN "review_count" SET NOT NULL;--> statement-breakpoint
CREATE UNIQUE INDEX "attractions_slug_unique" ON "guide_booking"."attractions" USING btree ("slug");
Loading
Loading