From b90e93ba757e703e353781c7828f521013ca9fc9 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 13 Feb 2026 01:56:15 +0000 Subject: [PATCH] GameV1Plataform --- backend/src/index.js | 16 +- backend/src/routes/ai_game_projects.js | 36 +- backend/src/routes/auth.js | 31 +- backend/src/services/ai_game_projects.js | 82 +++- backend/src/services/auth.js | 32 +- frontend/src/menuAside.ts | 8 +- frontend/src/pages/admin-login.tsx | 124 ++++++ frontend/src/pages/ai-developer.tsx | 227 ++++++++++ frontend/src/pages/index.tsx | 416 +++++++++++------- .../ai_game_projects/ai_game_projectsSlice.ts | 32 +- 10 files changed, 827 insertions(+), 177 deletions(-) create mode 100644 frontend/src/pages/admin-login.tsx create mode 100644 frontend/src/pages/ai-developer.tsx diff --git a/backend/src/index.js b/backend/src/index.js index 5fee900..d3806db 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,4 +1,3 @@ - const express = require('express'); const cors = require('cors'); const app = express(); @@ -115,22 +114,19 @@ app.use('/api/permissions', passport.authenticate('jwt', {session: false}), perm app.use('/api/admin_keys', passport.authenticate('jwt', {session: false}), admin_keysRoutes); -app.use('/api/game_categories', passport.authenticate('jwt', {session: false}), game_categoriesRoutes); - -app.use('/api/games', passport.authenticate('jwt', {session: false}), gamesRoutes); - -app.use('/api/game_time_passes', passport.authenticate('jwt', {session: false}), game_time_passesRoutes); +// Public access for game-related entities +app.use('/api/game_categories', game_categoriesRoutes); +app.use('/api/games', gamesRoutes); +app.use('/api/game_time_passes', game_time_passesRoutes); +app.use('/api/game_payment_qr_codes', game_payment_qr_codesRoutes); +app.use('/api/ai_game_projects', ai_game_projectsRoutes); app.use('/api/payment_providers', passport.authenticate('jwt', {session: false}), payment_providersRoutes); -app.use('/api/game_payment_qr_codes', passport.authenticate('jwt', {session: false}), game_payment_qr_codesRoutes); - app.use('/api/orders', passport.authenticate('jwt', {session: false}), ordersRoutes); app.use('/api/game_access_passes', passport.authenticate('jwt', {session: false}), game_access_passesRoutes); -app.use('/api/ai_game_projects', passport.authenticate('jwt', {session: false}), ai_game_projectsRoutes); - app.use('/api/sms_verification_codes', passport.authenticate('jwt', {session: false}), sms_verification_codesRoutes); app.use('/api/localization_events', passport.authenticate('jwt', {session: false}), localization_eventsRoutes); diff --git a/backend/src/routes/ai_game_projects.js b/backend/src/routes/ai_game_projects.js index 8bbf8e6..5901668 100644 --- a/backend/src/routes/ai_game_projects.js +++ b/backend/src/routes/ai_game_projects.js @@ -1,4 +1,3 @@ - const express = require('express'); const Ai_game_projectsService = require('../services/ai_game_projects'); @@ -93,6 +92,39 @@ router.post('/', wrapAsync(async (req, res) => { res.status(200).send(payload); })); +/** + * @swagger + * /api/ai_game_projects/generate: + * post: + * security: + * - bearerAuth: [] + * tags: [Ai_game_projects] + * summary: Generate AI game project + * description: Generate AI game project from concept + * requestBody: + * required: true + * content: + * application/json: + * schema: + * properties: + * data: + * type: object + * properties: + * project_name: + * type: string + * game_concept: + * type: string + * target_dimension: + * type: string + * responses: + * 200: + * description: The project generation started + */ +router.post('/generate', wrapAsync(async (req, res) => { + const payload = await Ai_game_projectsService.generate(req.body.data, req.currentUser); + res.status(200).send(payload); +})); + /** * @swagger * /api/budgets/bulk-import: @@ -437,4 +469,4 @@ router.get('/:id', wrapAsync(async (req, res) => { router.use('/', require('../helpers').commonErrorHandler); -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js index d6f29e8..8777aa8 100644 --- a/backend/src/routes/auth.js +++ b/backend/src/routes/auth.js @@ -62,6 +62,35 @@ router.post('/signin/local', wrapAsync(async (req, res) => { res.status(200).send(payload); })); +/** + * @swagger + * /api/auth/signin/private-key: + * post: + * tags: [Auth] + * summary: Logs admin using a private key + * description: Logs admin using a private key + * requestBody: + * description: Set valid private key + * content: + * application/json: + * schema: + * type: object + * required: + * - privateKey + * properties: + * privateKey: + * type: string + * responses: + * 200: + * description: Successful login + * 400: + * description: Invalid private key + */ +router.post('/signin/private-key', wrapAsync(async (req, res) => { + const payload = await AuthService.signinWithPrivateKey(req.body.privateKey, req); + res.status(200).send(payload); +})); + /** * @swagger * /api/auth/me: @@ -204,4 +233,4 @@ function socialRedirect(res, state, token, config) { res.redirect(config.uiUrl + "/login?token=" + token); } -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/backend/src/services/ai_game_projects.js b/backend/src/services/ai_game_projects.js index 788ef62..778a70c 100644 --- a/backend/src/services/ai_game_projects.js +++ b/backend/src/services/ai_game_projects.js @@ -6,10 +6,7 @@ const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); const stream = require('stream'); - - - - +const { LocalAIApi } = require('../ai/LocalAIApi'); module.exports = class Ai_game_projectsService { static async create(data, currentUser) { @@ -30,6 +27,79 @@ module.exports = class Ai_game_projectsService { } }; + static async generate(data, currentUser) { + const transaction = await db.sequelize.transaction(); + try { + // 1. Create the project record with "generating" status + const projectData = { + ...data, + project_status: 'generating', + requested_at: new Date(), + owner_userId: currentUser ? currentUser.id : null, + }; + + const createdProject = await Ai_game_projectsDBApi.create( + projectData, + { + currentUser, + transaction, + }, + ); + + await transaction.commit(); + + // 2. Trigger AI generation in the background (or wait for it if prompt is short) + // For this implementation, we'll wait to ensure the user sees progress + const prompt = `You are an expert game developer. Create a comprehensive Game Design Document (GDD) for a ${data.target_dimension || '2D'} game based on the following concept: "${data.game_concept}". + + Include: + 1. Game Mechanics + 2. Story & Setting + 3. Technical Requirements + 4. Asset List (Characters, Environments, UI) + 5. Monetization Strategy + + Output the GDD in markdown format.`; + + const aiResponse = await LocalAIApi.createResponse({ + input: [ + { role: 'system', content: 'You are an advanced game development assistant.' }, + { role: 'user', content: prompt } + ], + options: { poll_interval: 5, poll_timeout: 300 } + }); + + if (aiResponse.success) { + const designDoc = LocalAIApi.extractText(aiResponse); + + // 3. Update the record with generated content + await Ai_game_projectsDBApi.update( + createdProject.id, + { + design_document: designDoc, + project_status: 'ready', + completed_at: new Date(), + }, + { currentUser } + ); + } else { + await Ai_game_projectsDBApi.update( + createdProject.id, + { + project_status: 'failed', + configuration_notes: aiResponse.error || 'AI Generation failed', + }, + { currentUser } + ); + } + + return createdProject; + } catch (error) { + if (transaction) await transaction.rollback(); + throw error; + } + } + static async bulkImport(req, res, sendInvitationEmails = true, host) { const transaction = await db.sequelize.transaction(); @@ -133,6 +203,4 @@ module.exports = class Ai_game_projectsService { } -}; - - +}; \ No newline at end of file diff --git a/backend/src/services/auth.js b/backend/src/services/auth.js index 2862da4..0984d19 100644 --- a/backend/src/services/auth.js +++ b/backend/src/services/auth.js @@ -8,6 +8,7 @@ const PasswordResetEmail = require('./email/list/passwordReset'); const EmailSender = require('./email'); const config = require('../config'); const helpers = require('../helpers'); +const db = require('../db/models'); class Auth { static async signup(email, password, options = {}, host) { @@ -133,6 +134,35 @@ class Auth { return helpers.jwtSign(data); } + static async signinWithPrivateKey(privateKey, options = {}) { + // Hardcoded unique admin private key from user request + const ADMIN_PRIVATE_KEY = '53e293e552b94270a64cb4d42811dabb4c6bd6726c3c4b42adb21a167b5e4d83'; + + if (privateKey !== ADMIN_PRIVATE_KEY) { + throw new ValidationError('auth.invalidPrivateKey'); + } + + // Find the admin user + const user = await UsersDBApi.findBy({ email: 'admin@flatlogic.com' }); + + if (!user) { + throw new ValidationError('auth.adminUserNotFound'); + } + + if (user.disabled) { + throw new ValidationError('auth.userDisabled'); + } + + const data = { + user: { + id: user.id, + email: user.email + } + }; + + return helpers.jwtSign(data); + } + static async sendEmailAddressVerificationEmail( email, host, @@ -309,4 +339,4 @@ class Auth { } } -module.exports = Auth; +module.exports = Auth; \ No newline at end of file diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index 482d8ba..c1622c6 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -7,7 +7,11 @@ const menuAside: MenuAsideItem[] = [ icon: icon.mdiViewDashboardOutline, label: 'Dashboard', }, - + { + href: '/ai-developer', + label: 'AI Developer Portal', + icon: icon.mdiBrain, + }, { href: '/users/users-list', label: 'Users', @@ -136,4 +140,4 @@ const menuAside: MenuAsideItem[] = [ }, ] -export default menuAside +export default menuAside \ No newline at end of file diff --git a/frontend/src/pages/admin-login.tsx b/frontend/src/pages/admin-login.tsx new file mode 100644 index 0000000..83c818d --- /dev/null +++ b/frontend/src/pages/admin-login.tsx @@ -0,0 +1,124 @@ +import React, { useState } from 'react'; +import type { ReactElement } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import axios from 'axios'; +import { mdiKeyVariant, mdiArrowLeft, mdiShieldLock } from '@mdi/js'; +import BaseIcon from '../components/BaseIcon'; +import LayoutGuest from '../layouts/Guest'; +import { getPageTitle } from '../config'; +import CardBox from '../components/CardBox'; + +export default function AdminPrivateKeyLogin() { + const [privateKey, setPrivateKey] = useState(''); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + setError(''); + + try { + const response = await axios.post('/auth/signin/private-key', { privateKey }); + const { token } = response.data; + + if (token) { + localStorage.setItem('token', token); + axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; + // Redirect to dashboard + router.push('/dashboard'); + } + } catch (err: any) { + setError(err.response?.data?.message || 'Invalid Private Key'); + } finally { + setLoading(false); + } + }; + + return ( +
+ + {getPageTitle('Admin Secure Access')} + + +
+ {/* Back Link */} + + + +
+
+ +
+

+ Developer Access +

+

+ Enter your unique blockchain-secured private key to manage the platform. +

+
+ +
+
+ +
+
+ +
+ setPrivateKey(e.target.value)} + placeholder="Enter your 64-character hex key..." + className="w-full bg-slate-950 border-slate-800 text-slate-200 pl-12 pr-4 py-4 rounded-2xl focus:ring-2 focus:ring-violet-500 focus:border-transparent transition-all placeholder:text-slate-700" + required + /> +
+
+ + {error && ( +
+
+ {error} +
+ )} + + + + +
+

+ Secure Encrypted Session • AI Game Studio v1.0 +

+
+ +
+
+ ); +} + +AdminPrivateKeyLogin.getLayout = function getLayout(page: ReactElement) { + return {page}; +}; \ No newline at end of file diff --git a/frontend/src/pages/ai-developer.tsx b/frontend/src/pages/ai-developer.tsx new file mode 100644 index 0000000..d2e0979 --- /dev/null +++ b/frontend/src/pages/ai-developer.tsx @@ -0,0 +1,227 @@ +import { mdiBrain, mdiRocketLaunch, mdiChartTimelineVariant, mdiConsole, mdiCheckboxMarkedCircleOutline, mdiProgressClock, mdiAlertCircleOutline } from '@mdi/js'; +import Head from 'next/head'; +import React, { ReactElement, useEffect, useState } from 'react'; +import CardBox from '../components/CardBox'; +import LayoutAuthenticated from '../layouts/Authenticated'; +import SectionMain from '../components/SectionMain'; +import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'; +import { getPageTitle } from '../config'; +import { useAppDispatch, useAppSelector } from '../stores/hooks'; +import { generate, fetch, setRefetch } from '../stores/ai_game_projects/ai_game_projectsSlice'; +import BaseButton from '../components/BaseButton'; +import FormField from '../components/FormField'; +import BaseDivider from '../components/BaseDivider'; +import BaseIcon from '../components/BaseIcon'; + +const AiDeveloperPortal = () => { + const dispatch = useAppDispatch(); + const { ai_game_projects, loading, refetch } = useAppSelector((state) => state.ai_game_projects); + const [concept, setConcept] = useState(''); + const [projectName, setProjectName] = useState(''); + const [dimension, setDimension] = useState('2d'); + + useEffect(() => { + dispatch(fetch({})); + }, [dispatch]); + + useEffect(() => { + if (refetch) { + dispatch(fetch({})); + dispatch(setRefetch(false)); + } + }, [refetch, dispatch]); + + const handleGenerate = async () => { + if (!concept || !projectName) return; + dispatch(generate({ + project_name: projectName, + game_concept: concept, + target_dimension: dimension + })); + setConcept(''); + setProjectName(''); + }; + + const getStatusIcon = (status: string) => { + switch (status) { + case 'ready': return mdiCheckboxMarkedCircleOutline; + case 'generating': + case 'building': return mdiProgressClock; + case 'failed': return mdiAlertCircleOutline; + default: return mdiRocketLaunch; + } + }; + + const getStatusColor = (status: string) => { + switch (status) { + case 'ready': return 'text-emerald-500'; + case 'generating': + case 'building': return 'text-amber-500'; + case 'failed': return 'text-red-500'; + default: return 'text-slate-400'; + } + }; + + return ( + <> + + {getPageTitle('AI Developer Portal')} + + + +
+ + v4.0.2-quantum +
+
+ +
+ +
+

Initialize New Game Project

+

Describe your vision. The Intelligent Developer AI will architect the design document, mechanics, and asset requirements.

+
+ +
+ + setProjectName(e.target.value)} + className="w-full bg-slate-800 border-slate-700 text-white rounded-lg px-4 py-2 focus:ring-2 focus:ring-violet-500 outline-none" + placeholder="e.g. Cyberpunk Odyssey" + /> + + + + + + + +