diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..cd3fcde --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,48 @@ +# claude-test + +A Facebook Events replacement webapp for a private friend group. + +## Stack + +- **Backend:** .NET 8 Web API, Clean Architecture, EF Core 8, FluentValidation, JWT auth +- **Database:** MySQL +- **Frontend:** Vue 3 (Vite), Vuetify 3 +- **Version control:** Gitea at https://git.svrcina.eu/martin/claude-test.git + +## Project Structure (planned) + +``` +claude-test/ +├── backend/ +│ ├── ClaudeTest.API/ # Controllers, middleware, DI config +│ ├── ClaudeTest.Application/ # Services, DTOs, validators +│ ├── ClaudeTest.Domain/ # Entities, domain interfaces +│ └── ClaudeTest.Infrastructure/# EF Core, repositories, email +├── frontend/ # Vue 3 + Vuetify 3 app +└── CLAUDE.md +``` + +## Conventions + +- REST API with consistent JSON responses and HTTP status codes +- EF Core code-first migrations (never edit migrations manually) +- DTOs for all API input/output (never expose domain entities directly) +- FluentValidation for all request validation +- Async/await throughout the backend +- Vue 3 Composition API (` + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..a573e85 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,37 @@ +{ + "name": "vuetify-project", + "private": true, + "type": "module", + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force" + }, + "dependencies": { + "@fontsource/roboto": "^5.2.10", + "@mdi/font": "7.4.47", + "vue": "^3.5.30", + "vuetify": "^4.0.2" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.5", + "@types/node": "^24.12.0", + "@vitejs/plugin-vue": "^6.0.5", + "@vue/tsconfig": "^0.9.0", + "npm-run-all2": "^8.0.4", + "sass-embedded": "^1.98.0", + "typescript": "~5.9.3", + "unplugin-fonts": "^1.4.0", + "vite": "^8.0.0", + "vite-plugin-vuetify": "^2.1.3", + "vue-tsc": "^3.2.5" + }, + "overrides": { + "unplugin-fonts": { + "vite": "^8.0.0" + } + } +} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..8fb9f91 Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..e580cac --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,18 @@ + + + diff --git a/frontend/src/assets/logo.png b/frontend/src/assets/logo.png new file mode 100644 index 0000000..a5f23ae Binary files /dev/null and b/frontend/src/assets/logo.png differ diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg new file mode 100644 index 0000000..d57771c --- /dev/null +++ b/frontend/src/assets/logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue new file mode 100644 index 0000000..c9ef8b0 --- /dev/null +++ b/frontend/src/components/HelloWorld.vue @@ -0,0 +1,94 @@ + + + diff --git a/frontend/src/components/README.md b/frontend/src/components/README.md new file mode 100644 index 0000000..d1dc92f --- /dev/null +++ b/frontend/src/components/README.md @@ -0,0 +1,35 @@ +# Components + +Vue template files in this folder are automatically imported. + +## 🚀 Usage + +Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it. + +The following example assumes a component located at `src/components/MyComponent.vue`: + +```vue + + + +``` + +When your template is rendered, the component's import will automatically be inlined, which renders to this: + +```vue + + + +``` diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..f898fe4 --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,23 @@ +/** + * main.ts + * + * Bootstraps Vuetify and other plugins then mounts the App` + */ + +// Composables +import { createApp } from 'vue' + +// Plugins +import { registerPlugins } from '@/plugins' + +// Components +import App from './App.vue' + +// Styles +import 'unfonts.css' + +const app = createApp(App) + +registerPlugins(app) + +app.mount('#app') diff --git a/frontend/src/plugins/README.md b/frontend/src/plugins/README.md new file mode 100644 index 0000000..62201c7 --- /dev/null +++ b/frontend/src/plugins/README.md @@ -0,0 +1,3 @@ +# Plugins + +Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally. diff --git a/frontend/src/plugins/index.ts b/frontend/src/plugins/index.ts new file mode 100644 index 0000000..6b82c74 --- /dev/null +++ b/frontend/src/plugins/index.ts @@ -0,0 +1,15 @@ +/** + * plugins/index.ts + * + * Automatically included in `./src/main.ts` + */ + +// Types +import type { App } from 'vue' + +// Plugins +import vuetify from './vuetify' + +export function registerPlugins (app: App) { + app.use(vuetify) +} diff --git a/frontend/src/plugins/vuetify.ts b/frontend/src/plugins/vuetify.ts new file mode 100644 index 0000000..17ea9aa --- /dev/null +++ b/frontend/src/plugins/vuetify.ts @@ -0,0 +1,19 @@ +/** + * plugins/vuetify.ts + * + * Framework documentation: https://vuetifyjs.com` + */ + +// Composables +import { createVuetify } from 'vuetify' +// Styles +import '@mdi/font/css/materialdesignicons.css' + +import 'vuetify/styles' + +// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides +export default createVuetify({ + theme: { + defaultTheme: 'system', + }, +}) diff --git a/frontend/src/styles/README.md b/frontend/src/styles/README.md new file mode 100644 index 0000000..ea86179 --- /dev/null +++ b/frontend/src/styles/README.md @@ -0,0 +1,3 @@ +# Styles + +This directory is for configuring the styles of the application. diff --git a/frontend/src/styles/settings.scss b/frontend/src/styles/settings.scss new file mode 100644 index 0000000..3e36a27 --- /dev/null +++ b/frontend/src/styles/settings.scss @@ -0,0 +1,10 @@ +/** + * src/styles/settings.scss + * + * Configures SASS variables and Vuetify overwrites + */ + +// https://vuetifyjs.com/features/sass-variables/` +// @use 'vuetify/settings' with ( +// $color-pack: false +// ); diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..5a0c6a5 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/frontend/vite.config.mts b/frontend/vite.config.mts new file mode 100644 index 0000000..83820fb --- /dev/null +++ b/frontend/vite.config.mts @@ -0,0 +1,50 @@ +import { fileURLToPath, URL } from 'node:url' +import Vue from '@vitejs/plugin-vue' +import Fonts from 'unplugin-fonts/vite' +import { defineConfig } from 'vite' +import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + Vue({ + template: { transformAssetUrls }, + }), + // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme + Vuetify({ + autoImport: true, + styles: { + configFile: 'src/styles/settings.scss', + }, + }), + Fonts({ + fontsource: { + families: [ + { + name: 'Roboto', + weights: [100, 300, 400, 500, 700, 900], + styles: ['normal', 'italic'], + }, + ], + }, + }), + ], + define: { 'process.env': {} }, + resolve: { + alias: { + '@': fileURLToPath(new URL('src', import.meta.url)), + }, + extensions: [ + '.js', + '.json', + '.jsx', + '.mjs', + '.ts', + '.tsx', + '.vue', + ], + }, + server: { + port: 3000, + }, +})