mirror of
https://git.meshkee.com/Meshkee/backend.git
synced 2026-08-11 22:30:59 +04:30
Initial commit: Meshkee CMS API
NestJS backend with Prisma, Docker Compose for Postgres/Redis, and deploy docs for the production VM.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
---
|
||||
description: Business-scoped RBAC and permission patterns
|
||||
globs: src/**/*.controller.ts,src/**/*.service.ts
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Business RBAC
|
||||
|
||||
## Permission slugs
|
||||
|
||||
Format: `resource.action` — e.g. `products.read`, `categories.update`, `business.team.invite`
|
||||
|
||||
Content resources: `products.*`, `categories.*`, `media.*`, `business.team.*`
|
||||
|
||||
## Who gets access
|
||||
|
||||
- `super_admin` → all permissions (bypasses business guard)
|
||||
- Business owner (`isOwner=true`) → `business_owner` role permissions
|
||||
- Team member → permissions from `business_users.role_id` (admin/editor/viewer)
|
||||
|
||||
## Adding a business-scoped endpoint
|
||||
|
||||
1. Route: `businesses/:businessId/<resource>`
|
||||
2. `@UseGuards(JwtAuthGuard, BusinessPermissionGuard)`
|
||||
3. `@RequireBusinessPermission('resource.action')` on handler
|
||||
4. `assertPermission()` again inside the service
|
||||
|
||||
## Platform-only endpoints
|
||||
|
||||
Super-admin routes (`/users`, `/businesses`, `/domains`) check `permissions.isSuperAdmin()` in the service — no `BusinessPermissionGuard`.
|
||||
|
||||
## New permissions
|
||||
|
||||
Add `INSERT INTO permissions` + `role_permissions` in a SQL migration, then assign to relevant team roles.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: SQL migration and Prisma schema workflow
|
||||
globs: database/**/*,prisma/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Database Workflow
|
||||
|
||||
## Migrations
|
||||
|
||||
- Raw SQL in `database/migrations/` — numbered files (e.g. `012_feature.sql`)
|
||||
- Apply: `./database/migrate.sh` or `docker exec` into `meshkee-postgres`
|
||||
- Docker auto-runs migrations only on **first** Postgres volume init
|
||||
|
||||
## After schema change
|
||||
|
||||
```bash
|
||||
npm run prisma:pull
|
||||
npm run prisma:generate
|
||||
```
|
||||
|
||||
Never edit `prisma/schema.prisma` without a corresponding SQL migration (except post-pull formatting).
|
||||
|
||||
## Conventions in SQL
|
||||
|
||||
- `set_updated_at()` triggers on mutable tables
|
||||
- `BIGINT GENERATED BY DEFAULT AS IDENTITY` for PKs
|
||||
- Foreign keys with explicit `ON DELETE` (Cascade for owned data, Restrict/SetNull where appropriate)
|
||||
- Seed permissions in the same migration when adding new resources
|
||||
|
||||
## Prisma relations
|
||||
|
||||
Keep relation names aligned with existing schema style. `businessId` maps to `business_id`, enums use `@@map` for snake_case DB names.
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
description: Meshkee CMS API project context and architecture essentials
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Meshkee CMS API
|
||||
|
||||
Read `docs/PROJECT_CONTEXT.md` for full reference before large changes.
|
||||
|
||||
## Stack
|
||||
|
||||
NestJS 11 + TypeScript + Prisma 6 + PostgreSQL 16 + Redis + S3 (Parmin).
|
||||
|
||||
API prefix: `/api/v1`. Package name: `meshkee-cms-api`.
|
||||
|
||||
## Architecture
|
||||
|
||||
- Multi-tenant: `Business` is the tenant root; routes are `businesses/:businessId/...`
|
||||
- **Content Category** (`categories`) ≠ **Business Category** (`business_categories`) — do not confuse them
|
||||
- **Location Cities** (`cities`) — system reference tree (country → province → city) for address forms; not business-scoped. Distinct from **Addresses** (`addresses`) which store user/business street addresses
|
||||
- Blogs/portfolios exist in DB + permissions but have no Prisma models or API modules yet
|
||||
|
||||
## Schema changes
|
||||
|
||||
1. Add SQL file in `database/migrations/`
|
||||
2. Apply via `./database/migrate.sh`
|
||||
3. Run `npm run prisma:pull` then `npm run prisma:generate`
|
||||
|
||||
Do **not** use Prisma Migrate. SQL migrations are authoritative.
|
||||
|
||||
## Scope discipline
|
||||
|
||||
- Minimize diff scope; match existing module patterns
|
||||
- Reuse existing services/guards instead of reimplementing
|
||||
- No commits unless explicitly requested
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
description: NestJS module, controller, service, and DTO conventions
|
||||
globs: src/**/*.ts
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# NestJS Module Pattern
|
||||
|
||||
Each feature: `*.module.ts` → `*.controller.ts` → `*.service.ts` → `dto/`
|
||||
|
||||
## Controllers
|
||||
|
||||
```typescript
|
||||
@Controller('businesses/:businessId/products')
|
||||
@UseGuards(JwtAuthGuard, BusinessPermissionGuard)
|
||||
export class ProductsController {
|
||||
@Get()
|
||||
@RequireBusinessPermission('products.read')
|
||||
list(@Param('businessId') businessId: string, @CurrentUser() user: AuthUser) {
|
||||
return this.service.list(businessId, user);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Services
|
||||
|
||||
- Convert route IDs with `BigInt(idRaw)`
|
||||
- Inject `PrismaService` + `PermissionsService`
|
||||
- Add private `assertPermission(businessId, userId, 'slug')` (defense in depth)
|
||||
- Use `$transaction` for multi-step writes
|
||||
- Private `serialize()` methods; return IDs as strings
|
||||
|
||||
## DTOs
|
||||
|
||||
- `class-validator` on all request bodies and query params
|
||||
- `@Type(() => Number)` for query coercion
|
||||
- Slug: `^[a-z0-9]+(?:-[a-z0-9]+)*$`
|
||||
- Cell: E.164 `^\+[1-9]\d{6,14}$`
|
||||
|
||||
## Nested replace resources
|
||||
|
||||
For sub-resources like variations or technical forms: `GET` returns state, `PUT` validates → delete-all → recreate in transaction. See `CategoryVariationsService`.
|
||||
|
||||
## Errors
|
||||
|
||||
Use Nest exceptions: `NotFoundException`, `ForbiddenException`, `BadRequestException`, `ConflictException`.
|
||||
Reference in New Issue
Block a user