feat: add City10 platform with Laravel 13, AI agents, 3D viewer, and LGPD compliance
Initial commit of the complete City10 virtual city simulation platform. Backend (Laravel 13): - REST API with Sanctum tokens and session-based web authentication - Role-based access control (admin/user) with middleware protection - AI agent CRUD with OpenRouter.ai integration restricted to free models - Store management with 3D coordinates and AI shopkeeper assignment - Versioned legal documents (Terms, Privacy, Cookies) with LGPD audit trail - Math CAPTCHA on public forms and multi-language support (pt_BR, en, es) Frontend: - Responsive Blade templates with Tailwind CSS v4 - Three.js 3D city viewer with SSE chat streaming to AI agents - Admin panel for store and user administration Infrastructure: - MariaDB/MySQL database with comprehensive migrations - Database seeders for demo content and test accounts - PHPUnit test suite and Laravel Pint code styling - Vite build configuration with hot reload
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Aceite dos Termos')
|
||||
|
||||
@section('content')
|
||||
<div style="max-width: 820px; margin: 0 auto;">
|
||||
<div class="card">
|
||||
<h1 style="margin-top:0; color:#fff;">📄 Aceite dos Termos de Uso e Política de Privacidade</h1>
|
||||
<p style="color:var(--muted);">
|
||||
Antes de acessar a plataforma, você precisa ler e aceitar os documentos legais abaixo.
|
||||
Este registro é auditável (data, hora, versão e endereço IP), conforme a LGPD.
|
||||
</p>
|
||||
|
||||
<form method="POST" action="{{ route('terms.accept.store') }}">
|
||||
@csrf
|
||||
|
||||
@foreach ($documents as $doc)
|
||||
<section style="margin: 1.5rem 0; padding: 1rem; border:1px solid var(--border); border-radius:.8rem; background:#0b1220;">
|
||||
<h3 style="margin:0 0 .75rem; color:#fff;">{{ $doc['title'] }} <span style="color:var(--muted); font-weight:400; font-size:.85rem;">(v{{ $doc['version'] }})</span></h3>
|
||||
|
||||
<div style="max-height: 260px; overflow-y:auto; padding-right:.5rem; color:var(--text); line-height:1.6; font-size:.92rem;">
|
||||
{!! \Illuminate\Support\Str::markdown($doc['body'], ['html_input' => 'escape', 'allow_unsafe_links' => false]) !!}
|
||||
</div>
|
||||
|
||||
<label style="display:flex; align-items:flex-start; gap:.6rem; margin-top:.9rem; font-size:.92rem; cursor:pointer;">
|
||||
<input type="checkbox" name="accepted_{{ $doc['type'] }}" value="1" required style="margin-top:.2rem;">
|
||||
<span>Li e aceito o documento <strong>{{ $doc['title'] }}</strong> (versão {{ $doc['version'] }}).</span>
|
||||
</label>
|
||||
@error('accepted_' . $doc['type'])<div class="error">{{ $message }}</div>@enderror
|
||||
</section>
|
||||
@endforeach
|
||||
|
||||
<button type="submit" class="btn btn-primary" style="padding:.8rem 1.6rem;">Aceitar e Continuar</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,41 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Histórico de Consentimentos')
|
||||
|
||||
@section('content')
|
||||
<div style="max-width: 820px; margin: 0 auto;">
|
||||
<div class="card">
|
||||
<h1 style="margin-top:0; color:#fff;">🗂️ Histórico de Consentimentos</h1>
|
||||
<p style="color:var(--muted);">Registro auditável de todas as versões dos documentos legais que você aceitou.</p>
|
||||
|
||||
@if ($history->isEmpty())
|
||||
<p style="color:var(--muted);">Nenhum consentimento registrado ainda.</p>
|
||||
@else
|
||||
<div style="overflow-x:auto;">
|
||||
<table style="width:100%; border-collapse:collapse; font-size:.9rem;">
|
||||
<thead>
|
||||
<tr style="text-align:left; color:var(--muted); border-bottom:1px solid var(--border);">
|
||||
<th style="padding:.6rem .4rem;">Documento</th>
|
||||
<th style="padding:.6rem .4rem;">Versão</th>
|
||||
<th style="padding:.6rem .4rem;">Aceito em</th>
|
||||
<th style="padding:.6rem .4rem;">IP</th>
|
||||
<th style="padding:.6rem .4rem;">Canal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($history as $entry)
|
||||
<tr style="border-bottom:1px solid var(--border);">
|
||||
<td style="padding:.6rem .4rem;">{{ $entry->document?->type }}</td>
|
||||
<td style="padding:.6rem .4rem;">{{ $entry->document?->version }}</td>
|
||||
<td style="padding:.6rem .4rem;">{{ $entry->accepted_at?->format('d/m/Y H:i:s') }}</td>
|
||||
<td style="padding:.6rem .4rem;">{{ $entry->ip_address }}</td>
|
||||
<td style="padding:.6rem .4rem;">{{ $entry->source }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,16 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', $title)
|
||||
|
||||
@section('content')
|
||||
<article class="card" style="max-width: 820px; margin: 0 auto;">
|
||||
<header style="margin-bottom: 1rem;">
|
||||
<h1 style="margin:0 0 .35rem; color:#fff;">{{ $title }}</h1>
|
||||
<p style="margin:0; color:var(--muted); font-size:.85rem;">Versão {{ $document->version }} — Vigente desde {{ $document->published_at?->format('d/m/Y H:i') }}</p>
|
||||
</header>
|
||||
|
||||
<div class="legal-body" style="color:var(--text); line-height:1.65; font-size:.98rem;">
|
||||
{!! \Illuminate\Support\Str::markdown($body, ['html_input' => 'escape', 'allow_unsafe_links' => false]) !!}
|
||||
</div>
|
||||
</article>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user