Deliver the demo-ready feature set and seed data so the live site can be presented end to end: - Winner archive: ArchivedWinner domain, admin CRUD endpoints/view/manager and public archive surface, backed by AddArchivedWinners migration. - Host presentation: host image upload and artist name on SiteSettings with public image endpoint and supporting migrations. - Clip submissions: idempotent table-ensure migration plus current-season demo clips for review workflows. - Demo seed data: sponsors, share links and 2025 archived winners, with a guarded RemoveDemoSeasons cleanup; all seeds guard against real data. - EnsureRuntimeSchemaParity migration to align runtime schema defensively. - Admin/home UI refinements; remove unused team role permissions modal and dead share-quick-links code. All seed and schema migrations are idempotent (IF NOT EXISTS / ON CONFLICT) and skip when real season data is present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.3 KiB
Architecture
This document describes the structure, boundaries, flows, and technical rules of the VTuber Star Awards system. For project facts, see PROJECT.md. For coding standards, see CONVENTIONS.md. For recorded trade-offs, see DECISIONS.md.
High-Level Overview
VTuber Star Awards is a production monorepo with a Vue/Vite frontend, an ASP.NET Core 8 minimal API backend, and a PostgreSQL database managed by EF Core migrations.
flowchart LR
Public["Public users"]
Team["Team/admin users"]
Frontend["Vue/Vite frontend"]
Api["ASP.NET Core API"]
Domain["Domain models and services"]
Database["PostgreSQL"]
Twitch["Twitch OAuth"]
CI["Gitea Actions"]
Public --> Frontend
Team --> Frontend
Frontend --> Api
Api --> Domain
Domain --> Database
Api --> Twitch
CI --> Api
CI --> Frontend
CI --> Database
The frontend is the user interface. The backend is the source of truth for season state, content, team permissions, moderation, workflow rules, and public overview data.
Architecture Style
| Field | Value |
|---|---|
| Style | Layered modular monolith |
| Runtime shape | One frontend app, one backend API, one PostgreSQL database |
| Primary reason | Keep deployment simple while preserving clearer internal feature boundaries. |
| Main trade-off | Boundaries depend on code organization and review discipline rather than service isolation. |
Repository Structure
VTubeAwards/
frontend/
src/
views/
components/
stores/
lib/
types/
Backend/
Common/
Configuration/
Contracts/
Data/
Domain/
Endpoints/
Extensions/
Migrations/
Repositories/
Security/
Services/
docs/
.gitea/workflows/
| Folder | Responsibility |
|---|---|
frontend/src/views |
Route-level Vue views. |
frontend/src/components |
Reusable public/admin UI components and composables. |
frontend/src/lib |
API clients, HTTP helpers, formatting, and shared frontend utilities. |
frontend/src/types |
TypeScript contract and payload types. |
Backend/Endpoints |
Minimal API endpoint groups and endpoint-specific mapping helpers. |
Backend/Contracts |
Request and response DTOs. |
Backend/Domain |
Persistent domain entities and core business concepts. |
Backend/Data |
EF Core DbContext, seed/bootstrap code, and design-time setup. |
Backend/Repositories |
Domain-specific persistence boundaries. |
Backend/Services |
Use-case, audit, session, risk, and workflow services. |
Backend/Security |
Session filters, role/permission catalog, and security middleware. |
docs |
Durable project, architecture, workflow, and decision documentation. |
Backend Flow
sequenceDiagram
participant Client as Frontend or API client
participant Endpoint as Minimal API endpoint
participant Filter as Admin/session filter
participant Service as Service or repository
participant Db as EF Core/PostgreSQL
Client->>Endpoint: HTTP request
Endpoint->>Filter: Auth and permission checks when required
Endpoint->>Service: Validate intent and execute use case
Service->>Db: Query or persist through DbContext/repository
Db-->>Service: Domain data
Service-->>Endpoint: Contract DTO
Endpoint-->>Client: JSON response or problem result
Endpoint files should stay focused on transport concerns, authorization, mapping, and orchestration. Domain rules and cross-endpoint behavior belong in services, repositories, or domain-specific helpers.
Frontend Flow
flowchart TD
Route["Vue route/view"]
Components["Focused components"]
Composables["Composables and stores"]
ApiClient["frontend/src/lib/api"]
Backend["Backend API"]
Route --> Components
Components --> Composables
Composables --> ApiClient
ApiClient --> Backend
Public pages should render backend/admin truth. Admin pages should favor clear workspace structure, permission-aware controls, explicit loading/error states, and smaller Vue files split by feature.
Data Ownership
| Data | Owner | Notes |
|---|---|---|
| Seasons, categories, candidates, winners, archived winners | Backend | Public and admin views read from canonical backend state; historical archive winners are managed separately from current season winner publication. |
| Nominations and clip submissions | Backend | Public writes are validated and reviewed through admin workflows. |
| Site settings, landing content, footer links, showacts, sponsors | Backend | Content hub/admin settings own public presentation data. |
| Team members, roles, permissions, sessions | Backend | UI may hide controls, but API authorization is authoritative. |
| Risk flags and audit entries | Backend | Used for admin review, diagnostics, and accountability. |
| Frontend interaction state | Frontend | Local state is allowed only for view state and unsaved form state. |
Persistence Boundary
The backend uses EF Core with PostgreSQL. Domain-specific repositories exist for
session, risk flag, and audit behavior. Direct AwardsDbContext use is still
acceptable inside endpoint groups or services when the operation is simple and
local to one feature, but repeated or cross-feature persistence behavior should
move behind a repository or focused service.
Production migrations are applied by the Gitea deploy workflow. Development can auto-apply migrations during API startup.
Authentication And Authorization
- Team/admin authentication is session-based.
- Twitch OAuth is handled through backend auth endpoints.
- Admin endpoints use session/permission checks at the trusted backend boundary.
- The frontend should reflect permissions to improve UX, but never be the only authorization layer.
creatoris not a normal assignable role in team management.
Security Posture
| Area | Policy |
|---|---|
| CORS | Non-development environments require explicit configured frontend origins. |
| Public writes | Rate-limited and validated server-side. |
| Secrets | Environment variables only; no checked-in production credentials. |
| Demo data | Controlled by seed/demo environment flags. Production defaults must remain safe. |
| Headers | Security headers are applied by backend middleware. |
| Audit | Admin-relevant changes should emit useful audit records where supported. |
Deployment Flow
flowchart LR
Push["Push to main or manual dispatch"]
Verify["Build, typecheck, hygiene"]
Sync["Sync code to production host"]
Backup["Predeploy PostgreSQL backup"]
Migrate["Apply EF Core migrations"]
Restart["Recreate api and web services"]
Smoke["Health, database, and asset checks"]
Push --> Verify
Verify --> Sync
Sync --> Backup
Backup --> Migrate
Migrate --> Restart
Restart --> Smoke
The production deploy path is encoded in .gitea/workflows/ci.yaml.
Known Constraints
- There is no dedicated checked-in test project yet.
- Build/type checks and targeted manual verification are currently required for most changes.
- Production database migration rollback must be considered before risky schema changes; the pipeline writes backups but does not make destructive migrations automatically safe.
- Large admin and public Vue surfaces should continue to be split as they grow.