diff --git a/src/routes/(public)/login/+page.server.ts b/src/routes/(public)/login/+page.server.ts
deleted file mode 100644
index 8dcf6ce..0000000
--- a/src/routes/(public)/login/+page.server.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import type { PageServerLoad, Actions } from "./$types.js";
-import { fail } from "@sveltejs/kit";
-import { superValidate } from "sveltekit-superforms";
-import { zod } from "sveltekit-superforms/adapters";
-import { formSchema } from "./schema";
-
-export const load: PageServerLoad = async () => {
- return {
- form: await superValidate(zod(formSchema)),
- };
-};
-
-export const actions: Actions = {
- default: async (event) => {
- const form = await superValidate(event, zod(formSchema));
- if (!form.valid) {
- return fail(400, {
- form,
- });
- }
- return {
- form,
- };
- },
-};
-
-// import { hash, verify } from '@node-rs/argon2';
-// import { encodeBase32LowerCase } from '@oslojs/encoding';
-// import { fail, redirect } from '@sveltejs/kit';
-// import { eq } from 'drizzle-orm';
-// import * as auth from '$lib/server/auth';
-// import { db } from '$lib/server/db';
-// import * as table from '$lib/server/db/schema';
-// import type { Actions, PageServerLoad } from './$types';
-
-// export const load: PageServerLoad = async (event) => {
-// if (event.locals.user) {
-// return redirect(302, '/demo/lucia');
-// }
-// return {};
-// };
-
-// export const actions: Actions = {
-// login: async (event) => {
-// const formData = await event.request.formData();
-// const username = formData.get('username');
-// const password = formData.get('password');
-
-// if (!validateUsername(username)) {
-// return fail(400, { message: 'Invalid username (min 3, max 31 characters, alphanumeric only)' });
-// }
-// if (!validatePassword(password)) {
-// return fail(400, { message: 'Invalid password (min 6, max 255 characters)' });
-// }
-
-// const results = await db
-// .select()
-// .from(table.user)
-// .where(eq(table.user.username, username));
-
-// const existingUser = results.at(0);
-// if (!existingUser) {
-// return fail(400, { message: 'Incorrect username or password' });
-// }
-
-// const validPassword = await verify(existingUser.passwordHash, password, {
-// memoryCost: 19456,
-// timeCost: 2,
-// outputLen: 32,
-// parallelism: 1,
-// });
-// if (!validPassword) {
-// return fail(400, { message: 'Incorrect username or password' });
-// }
-
-// const sessionToken = auth.generateSessionToken();
-// const session = await auth.createSession(sessionToken, existingUser.id);
-// auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
-
-// return redirect(302, '/demo/lucia');
-// },
-// register: async (event) => {
-// const formData = await event.request.formData();
-// const username = formData.get('username');
-// const password = formData.get('password');
-
-// if (!validateUsername(username)) {
-// return fail(400, { message: 'Invalid username' });
-// }
-// if (!validatePassword(password)) {
-// return fail(400, { message: 'Invalid password' });
-// }
-
-// const userId = generateUserId();
-// const passwordHash = await hash(password, {
-// // recommended minimum parameters
-// memoryCost: 19456,
-// timeCost: 2,
-// outputLen: 32,
-// parallelism: 1,
-// });
-
-// try {
-// await db.insert(table.user).values({ id: userId, username, passwordHash });
-
-// const sessionToken = auth.generateSessionToken();
-// const session = await auth.createSession(sessionToken, userId);
-// auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
-// } catch (e) {
-// return fail(500, { message: 'An error has occurred' });
-// }
-// return redirect(302, '/demo/lucia');
-// },
-// };
-
-// function generateUserId() {
-// // ID with 120 bits of entropy, or about the same as UUID v4.
-// const bytes = crypto.getRandomValues(new Uint8Array(15));
-// const id = encodeBase32LowerCase(bytes);
-// return id;
-// }
-
-// function validateUsername(username: unknown): username is string {
-// return (
-// typeof username === 'string' &&
-// username.length >= 3 &&
-// username.length <= 31 &&
-// /^[a-z0-9_-]+$/.test(username)
-// );
-// }
-
-// function validatePassword(password: unknown): password is string {
-// return (
-// typeof password === 'string' &&
-// password.length >= 6 &&
-// password.length <= 255
-// );
-// }
diff --git a/src/routes/(public)/login/login-form.svelte b/src/routes/(public)/login/login-form.svelte
deleted file mode 100644
index 0d0b147..0000000
--- a/src/routes/(public)/login/login-form.svelte
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
diff --git a/src/routes/(public)/login/schema.ts b/src/routes/(public)/login/schema.ts
deleted file mode 100644
index aa1e074..0000000
--- a/src/routes/(public)/login/schema.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { z } from "zod";
-
-export const formSchema = z.object({
- email: z.string().email(),
- password: z.string().min(8),
-});
-
-export type FormSchema = typeof formSchema;
\ No newline at end of file
diff --git a/src/routes/(public)/login/+layout.svelte b/src/routes/login/+layout.svelte
similarity index 100%
rename from src/routes/(public)/login/+layout.svelte
rename to src/routes/login/+layout.svelte
diff --git a/src/routes/login/+page.server.ts b/src/routes/login/+page.server.ts
new file mode 100644
index 0000000..772429e
--- /dev/null
+++ b/src/routes/login/+page.server.ts
@@ -0,0 +1,67 @@
+import {hash, verify} from '@node-rs/argon2';
+import {encodeBase32LowerCase} from '@oslojs/encoding';
+import {redirect} from '@sveltejs/kit';
+import {eq} from 'drizzle-orm';
+import * as auth from '$lib/server/auth';
+import {db} from '$lib/server/db';
+import * as table from '$lib/server/db/schema';
+import type {Actions, PageServerLoad} from './$types';
+import { setError, superValidate , fail} from 'sveltekit-superforms';
+import {zod} from "sveltekit-superforms/adapters";
+import {formSchema} from "./schema";
+
+
+
+export const load: PageServerLoad = async (event) => {
+ if (event.locals.user) {
+ return redirect(302, '/demo/lucia');
+ }
+ return {
+ form: await superValidate(zod(formSchema)),
+ };
+};
+
+export const actions: Actions = {
+ login: async (event) => {
+ const form = await superValidate(event, zod(formSchema));
+ if (!form.valid) {
+ return fail(400, {
+ form,
+ });
+ }
+
+ const userId = form.data.userId;
+ const password = form.data.password;
+
+ const results = await db
+ .select()
+ .from(table.user)
+ .where(eq(table.user.username, userId));
+
+ const existingUser = results.at(0);
+ if (!existingUser) {
+ return setError(form, 'userId', '존재하지 않는 아이디 입니다.');
+ }
+
+ const validPassword = await verify(existingUser.passwordHash, password, {
+ memoryCost: 19456,
+ timeCost: 2,
+ outputLen: 32,
+ parallelism: 1,
+ });
+ if (!validPassword) {
+ return setError(form, 'password', '비밀번호가 일치하지 않습니다.');
+ }
+
+ const sessionToken = auth.generateSessionToken();
+ const session = await auth.createSession(sessionToken, existingUser.id);
+ auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
+
+ return redirect(302, '/demo/lucia');
+
+ },
+};
+
+
+
+
diff --git a/src/routes/(public)/login/+page.svelte b/src/routes/login/+page.svelte
similarity index 81%
rename from src/routes/(public)/login/+page.svelte
rename to src/routes/login/+page.svelte
index 63ad961..cf0bbd7 100644
--- a/src/routes/(public)/login/+page.svelte
+++ b/src/routes/login/+page.svelte
@@ -1,5 +1,5 @@
diff --git a/src/routes/login/login-form.svelte b/src/routes/login/login-form.svelte
new file mode 100644
index 0000000..1ddfdae
--- /dev/null
+++ b/src/routes/login/login-form.svelte
@@ -0,0 +1,81 @@
+
+
+
+
+
+ LOGIN
+
+
+
+
+
+ {#if dev}
+
+ {/if}
+
diff --git a/src/routes/login/schema.ts b/src/routes/login/schema.ts
new file mode 100644
index 0000000..56432a5
--- /dev/null
+++ b/src/routes/login/schema.ts
@@ -0,0 +1,22 @@
+import { z } from "zod";
+
+export const formSchema = z.object({
+ // User ID (formerly 'user')
+ userId: z.string()
+ .min(3, "최소 3자 이상이어야 합니다.") // A common minimum for IDs
+ .max(50, "최대 50자 이하이어야 합니다.") // Reasonable maximum length
+ .regex(/^[a-zA-Z0-9_.-]+$/, "영문, 숫자, '_', '.', '-'만 포함할 수 있습니다.") // Restrict characters
+ .trim(), // Remove leading/trailing whitespace
+
+ // Password
+ password: z.string()
+ .min(8, "최소 8자 이상이어야 합니다.")
+ .max(100, "최대 100자 이하이어야 합니다.") // Reasonable maximum length
+ .regex(/[a-z]/, "최소 하나의 소문자를 포함해야 합니다.")
+ .regex(/[A-Z]/, "최소 하나의 대문자를 포함해야 합니다.")
+ .regex(/[0-9]/, "최소 하나의 숫자를 포함해야 합니다.")
+ .regex(/[^a-zA-Z0-9]/, "최소 하나의 특수문자를 포함해야 합니다.") // For common special characters
+ .trim(),
+});
+
+export type FormSchema = typeof formSchema;
\ No newline at end of file
diff --git a/src/routes/sendmailtest/+page.server.js b/src/routes/sendmailtest/+page.server.ts
similarity index 98%
rename from src/routes/sendmailtest/+page.server.js
rename to src/routes/sendmailtest/+page.server.ts
index a50c564..3dde172 100644
--- a/src/routes/sendmailtest/+page.server.js
+++ b/src/routes/sendmailtest/+page.server.ts
@@ -1,5 +1,5 @@
import { fail } from '@sveltejs/kit';
-import nodemailer from 'nodemailer';
+const nodemailer = require("nodemailer");
import {
BREVO_SMTP_HOST,
BREVO_SMTP_PORT,