feat: admin user creation, Vite migration, dialog fix, pl24 integration

- Add POST /admin/users endpoint with password hashing and role support
- Add user creation dialog to admin users page
- Migrate web from Next.js to Vite + TanStack Router
- Fix Dialog component positioning for Tailwind CSS v4
- Add @source directive for @sase/ui package scanning
- Add pl24 integration parsers and vehicle decode flow
- Backup old Next.js app to apps/web-nj

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-02-12 14:24:58 +00:00
parent bf7f876abd
commit 996d614d50
211 changed files with 23805 additions and 549 deletions

View File

@@ -1,4 +1,4 @@
import { Controller, Get, Param, Query } from "@nestjs/common";
import { Body, Controller, Get, Param, Post, Query } from "@nestjs/common";
import { AdminService } from "./admin.service";
import { Roles } from "../common/decorators/roles.decorator";
@@ -7,6 +7,13 @@ import { Roles } from "../common/decorators/roles.decorator";
export class AdminController {
constructor(private adminService: AdminService) {}
@Post("users")
async createUser(
@Body() body: { name: string; email: string; password: string; role?: string },
) {
return this.adminService.createUser(body);
}
@Get("dashboard")
async getDashboardStats() {
return this.adminService.getDashboardStats();

View File

@@ -1,14 +1,22 @@
import { Inject, Injectable, Logger, NotFoundException } from "@nestjs/common";
import {
ConflictException,
Inject,
Injectable,
Logger,
NotFoundException,
} from "@nestjs/common";
import { and, count, desc, eq, gte, ilike, inArray, or, sql } from "drizzle-orm";
import { DATABASE, Database } from "../database/database.provider";
import {
users,
accounts,
userSubscriptions,
payments,
queryLogs,
brands,
referrals,
} from "../database/schema/core";
import { hashPassword } from "better-auth/crypto";
@Injectable()
export class AdminService {
@@ -16,6 +24,54 @@ export class AdminService {
constructor(@Inject(DATABASE) private db: Database) {}
async createUser(data: {
name: string;
email: string;
password: string;
role?: string;
}) {
// Check if email already exists
const [existing] = await this.db
.select({ id: users.id })
.from(users)
.where(eq(users.email, data.email))
.limit(1);
if (existing) {
throw new ConflictException("Bu e-posta adresi zaten kullaniliyor");
}
const hashedPassword = await hashPassword(data.password);
// Insert user
const [newUser] = await this.db
.insert(users)
.values({
name: data.name,
email: data.email,
emailVerified: true,
role: data.role || "user",
})
.returning({
id: users.id,
name: users.name,
email: users.email,
role: users.role,
createdAt: users.createdAt,
});
// Insert credential account for better-auth compatibility
await this.db.insert(accounts).values({
id: crypto.randomUUID(),
userId: newUser.id,
accountId: newUser.id,
providerId: "credential",
password: hashedPassword,
});
return newUser;
}
async getDashboardStats() {
const now = new Date();
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);