diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 53e336e04..9118452ad 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -1,58 +1,58 @@ -# Auto-Admin Frontend Development Guide +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## ๐Ÿš€ Project Overview This is the frontend for Auto-Admin, a database administration tool built with Angular 19. The application provides a comprehensive interface for managing database connections, tables, and data with customizable widgets and user permissions. -## ๐Ÿ›  Technologies & Frameworks - -### Core Technologies -- **Angular**: v19.0.4 (Latest with standalone components) -- **TypeScript**: v5.6.0 (ES2022 target) -- **RxJS**: v7.4.0 (Reactive programming) -- **Node.js**: Modern versions supported - -### UI/UX Stack -- **Angular Material**: v19.0.3 (Primary UI library) -- **Angular CDK**: v19.0.3 (Component Development Kit) -- **@brumeilde/ngx-theme**: v1.2.1 (Custom theming) -- **SCSS**: Material Design theming -- **ngx-bootstrap**: v19.0.2 (Additional components) +## ๐Ÿ”ง Development Commands -### Additional Libraries -- **@ngstack/code-editor**: v9.0.0 (Code editing) -- **ngx-markdown**: v19.0.0 (Markdown rendering) -- **ngx-stripe**: v19.0.0 (Payment integration) -- **angulartics2**: v14.1.0 (Analytics) -- **@sentry/angular-ivy**: v7.116.0 (Error monitoring) +### Build & Development +```bash +yarn start # Start development server (ng serve) +yarn build # Production build (ng build) +yarn build --configuration=development # Development build +yarn build --configuration=saas # SaaS build +yarn build --configuration=saas-production # SaaS production build +yarn build:stats # Build with webpack bundle analyzer stats +yarn analyze # Analyze bundle size +``` -## ๐Ÿ“ Project Structure +### Testing +```bash +yarn test # Run tests in watch mode (ng test) +yarn test:ci # Run tests once for CI (--watch=false --browsers=ChromeHeadlessCustom) +yarn test --browsers=ChromeHeadlessCustom --no-watch --no-progress # Run tests headlessly without watch +``` +### Linting +```bash +yarn lint # Run TSLint (deprecated - needs ESLint migration) +ng lint # Alternative lint command ``` -src/app/ -โ”œโ”€โ”€ components/ -โ”‚ โ”œโ”€โ”€ dashboard/ # Main data interface -โ”‚ โ”œโ”€โ”€ ui-components/ # Reusable UI components -โ”‚ โ”‚ โ”œโ”€โ”€ row-fields/ # Widget components (text, date, select, etc.) -โ”‚ โ”‚ โ”œโ”€โ”€ filter-fields/ # Filter components -โ”‚ โ”‚ โ””โ”€โ”€ alert/ # Common UI elements -โ”‚ โ”œโ”€โ”€ login/ # Authentication -โ”‚ โ”œโ”€โ”€ registration/ # User registration -โ”‚ โ”œโ”€โ”€ connect-db/ # Database connection setup -โ”‚ โ”œโ”€โ”€ company/ # Company management -โ”‚ โ””โ”€โ”€ skeletons/ # Loading placeholders -โ”œโ”€โ”€ services/ # Business logic & API calls -โ”œโ”€โ”€ models/ # TypeScript interfaces -โ”œโ”€โ”€ consts/ # Constants & configurations -โ”œโ”€โ”€ lib/ # Utility functions -โ”œโ”€โ”€ validators/ # Form validation -โ””โ”€โ”€ directives/ # Custom directives + +### Package Management +```bash +yarn add package-name # Add dependency +yarn add -D package-name # Add dev dependency +yarn install # Install dependencies ``` -## ๐Ÿ— Architecture Patterns +## ๐Ÿ— Architecture Overview -### Standalone Components -Uses Angular 19's standalone component architecture: +### Core Technologies +- **Angular 19** with standalone components architecture +- **TypeScript 5.6** targeting ES2022 +- **Angular Material 19** for UI components +- **RxJS 7.4** for reactive programming +- **SCSS** with Material Design theming +- **Jasmine/Karma** for testing + +### Key Architecture Patterns + +#### Standalone Components +Uses Angular 19's standalone component architecture without NgModules: ```typescript @Component({ @@ -66,8 +66,8 @@ export class ExampleComponent implements OnInit { } ``` -### Service-Based State Management -No NgRx - uses BehaviorSubject pattern for state: +#### Service-Based State Management +No NgRx - uses BehaviorSubject pattern for state management: ```typescript @Injectable({ providedIn: 'root' }) @@ -81,21 +81,64 @@ export class DataService { } ``` -### Dynamic Widget System -Highly flexible widget system for different data types: +#### Multi-Environment Support +The app supports multiple deployment environments: +- `environment.ts` - Development +- `environment.prod.ts` - Production +- `environment.saas.ts` - SaaS development +- `environment.saas-prod.ts` - SaaS production + +Each environment uses different file replacements and build configurations. -```typescript -export const UIwidgets = { - String: TextRowComponent, - Number: NumberRowComponent, - Date: DateRowComponent, - Boolean: BooleanRowComponent, - Phone: PhoneRowComponent, - // ... more widgets -}; +### Project Structure + +``` +src/app/ +โ”œโ”€โ”€ components/ +โ”‚ โ”œโ”€โ”€ dashboard/ # Main data interface +โ”‚ โ”œโ”€โ”€ ui-components/ # Reusable UI components +โ”‚ โ”œโ”€โ”€ login/ # Authentication +โ”‚ โ”œโ”€โ”€ registration/ # User registration +โ”‚ โ”œโ”€โ”€ connect-db/ # Database connection setup +โ”‚ โ”œโ”€โ”€ company/ # Company management +โ”‚ โ””โ”€โ”€ skeletons/ # Loading placeholders +โ”œโ”€โ”€ services/ # Business logic & API calls +โ”‚ โ”œโ”€โ”€ auth.service.ts # Authentication service +โ”‚ โ”œโ”€โ”€ connections.service.ts # Database connections +โ”‚ โ”œโ”€โ”€ tables.service.ts # Table operations +โ”‚ โ””โ”€โ”€ user.service.ts # User management +โ”œโ”€โ”€ models/ # TypeScript interfaces +โ”œโ”€โ”€ consts/ # Constants & configurations +โ”‚ โ”œโ”€โ”€ databases.ts # Supported databases config +โ”‚ โ””โ”€โ”€ plans.ts # Subscription plans +โ”œโ”€โ”€ lib/ # Utility functions +โ”œโ”€โ”€ validators/ # Form validation +โ””โ”€โ”€ directives/ # Custom directives ``` -## ๐Ÿ“ Code Style & Conventions +### Database Support + +The application supports multiple database types: +- MySQL +- PostgreSQL +- MongoDB +- DynamoDB +- Cassandra +- OracleDB +- MSSQL +- IBM DB2 + +Database configurations are defined in `src/app/consts/databases.ts`. + +### Authentication & User Management + +- JWT token-based authentication with expiration handling +- Google OAuth integration +- Demo account functionality +- Session restoration on app initialization +- Automatic logout on token expiration + +## ๐Ÿ“ Code Conventions ### Naming Conventions - **Files**: `kebab-case.component.ts` @@ -106,6 +149,18 @@ export const UIwidgets = { - **Private members**: Prefixed with `_` (e.g., `_privateMethod`) - **Selectors**: `app-` prefix with kebab-case +### Import Organization +```typescript +// External libraries first +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { CommonModule } from '@angular/common'; + +// Internal imports second +import { BaseRowFieldComponent } from '../base-row-field/base-row-field.component'; +import { DataService } from 'src/app/services/data.service'; +``` + ### Component Structure ```typescript @Component({ @@ -142,59 +197,12 @@ export class WidgetNameComponent implements OnInit { } ``` -### Import Organization -```typescript -// External libraries first -import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { CommonModule } from '@angular/common'; - -// Internal imports second -import { BaseRowFieldComponent } from '../base-row-field/base-row-field.component'; -import { DataService } from 'src/app/services/data.service'; -``` - -## ๐ŸŽจ Styling Guidelines +## ๐Ÿงช Testing Configuration -### Material Design Implementation -- Uses Material Design 2 (M2) APIs -- Custom theme with light/dark mode support -- Noto Sans font family - -### SCSS Structure -```scss -// Component-specific styles -.component-name { - &__element { - // BEM methodology - } - - &--modifier { - // State variations - } -} - -// Use Material Design spacing -.mat-form-field { - width: 100%; - margin-bottom: 16px; -} -``` - -### Theme Configuration -```scss -$custom-palette-primary: mat.m2-define-palette(mat.$m2-blue-palette); -$custom-light-theme: mat.m2-define-light-theme(( - color: ( - primary: $custom-palette-primary, - accent: $custom-palette-accent, - warn: $custom-palette-warn, - ), - density: -3, -)); -``` - -## ๐Ÿงช Testing Guidelines +### Test Framework +- **Jasmine** as testing framework +- **Karma** as test runner +- **ChromeHeadless** for CI environments ### Test Structure ```typescript @@ -215,195 +223,76 @@ describe('ComponentName', () => { it('should create', () => { expect(component).toBeTruthy(); }); - - it('should handle user input', () => { - // Test user interactions - }); }); ``` -### Test Commands -```bash -npm test # Run tests in watch mode -npm run test:ci # Run tests once for CI -``` +### Karma Configuration +Custom launcher `ChromeHeadlessCustom` is configured for CI with flags `--no-sandbox --disable-gpu`. -## ๐Ÿ”ง Development Workflow - -### Development Commands -```bash -npm start # Start development server -npm run build # Build for production -npm test # Run tests -npm run lint # Run linting (TSLint - needs ESLint migration) -``` - -### Environment Configuration -- `environment.ts` - Development -- `environment.prod.ts` - Production -- `environment.saas.ts` - SaaS development -- `environment.saas-prod.ts` - SaaS production - -## ๐ŸŽฏ Widget Development Guide - -### Creating New Widgets - -1. **Create Component Files**: -```bash -mkdir src/app/components/ui-components/row-fields/your-widget -``` - -2. **Extend Base Component**: -```typescript -export class YourWidgetComponent extends BaseRowFieldComponent { - @Input() value: any; - static type = 'your-widget'; - - // Widget-specific logic -} -``` - -3. **Add to Widget Registry**: -```typescript -// In src/app/consts/field-types.ts -export const UIwidgets = { - // ... existing widgets - YourWidget: YourWidgetComponent, -}; -``` +## ๐ŸŽจ Styling & Theming -4. **Add to Enums**: -```typescript -// Backend: src/enums/widget-type.enum.ts -// Shared: shared-code/src/data-access-layer/shared/enums/table-widget-type.enum.ts -export enum WidgetTypeEnum { - // ... existing types - YourWidget = 'YourWidget', -} -``` - -5. **Configure Default Parameters**: -```typescript -// In db-table-widgets.component.ts -public defaultParams = { - // ... existing params - YourWidget: `// Widget configuration documentation -{ - "param1": "value1", - "param2": true -}`, -}; -``` - -## ๐Ÿšจ Common Patterns & Best Practices +### Material Design +- Uses Material Design 2 (M2) APIs +- Custom theme with light/dark mode support +- SCSS preprocessing with Material theme presets +- Custom theme files: `src/custom-theme.scss`, `src/styles.scss` -### Error Handling -```typescript -this.service.getData().subscribe({ - next: (data) => { - // Handle success - }, - error: (error) => { - console.error('Error occurred:', error); - // Show user-friendly error message +### SCSS Structure +```scss +// Component-specific styles using BEM methodology +.component-name { + &__element { + // Element styles } -}); -``` - -### Loading States -```typescript -export class ExampleComponent { - public loading = false; - async loadData() { - this.loading = true; - try { - const data = await this.service.getData().toPromise(); - // Process data - } finally { - this.loading = false; - } + &--modifier { + // State variations } } ``` -### Form Validation -```typescript -// Use Angular's reactive forms with Material Design -import { FormBuilder, Validators } from '@angular/forms'; +## ๐Ÿ“ฆ Third-Party Integrations -constructor(private fb: FormBuilder) { - this.form = this.fb.group({ - field: ['', [Validators.required, Validators.minLength(3)]] - }); -} -``` +### Analytics & Monitoring +- **Angulartics2** with Amplitude integration +- **@sentry/angular-ivy** for error monitoring +- **Hotjar** for user behavior tracking (demo accounts) +- **Intercom** for customer support -## ๐Ÿ“ฆ Package Management +### Payment Processing +- **@stripe/stripe-js** and **ngx-stripe** for payment processing -### Using Yarn -```bash -yarn add package-name # Add dependency -yarn add -D package-name # Add dev dependency -yarn install # Install dependencies -``` +### Additional Libraries +- **@ngstack/code-editor** for code editing capabilities +- **ngx-markdown** for markdown rendering +- **libphonenumber-js** for phone number handling +- **date-fns** for date manipulation +- **lodash** for utility functions -### Important: Peer Dependencies -When adding new packages, check for peer dependency warnings and install missing dependencies: -```bash -yarn add ngx-intl-tel-input intl-tel-input google-libphonenumber -``` +## ๐Ÿ”ง Build Configuration -## ๐Ÿ”„ Migration Notes +### Angular Build Targets +- **Default**: Development configuration +- **Production**: Optimized build with source maps +- **Development**: Explicit development configuration +- **SaaS/SaaS-Production**: Specialized SaaS builds with different index files -### Recommended Upgrades -- **TSLint โ†’ ESLint**: Current linting setup uses deprecated TSLint -- **Material Design 3**: Consider upgrading from M2 to M3 APIs -- **Standalone Migration**: Already using standalone components (โœ…) +### Bundle Size Limits +- Initial bundle: Warning at 2MB, error at 5MB +- Component styles: Warning at 6KB, error at 10KB -### Breaking Changes to Watch -- Angular Material API changes between versions -- RxJS operator deprecations -- TypeScript strict mode compliance +## ๐Ÿšจ Important Notes -## ๐ŸŽฏ Performance Considerations +### Migration Recommendations +- **TSLint โ†’ ESLint**: Current linting uses deprecated TSLint +- **Material Design 3**: Consider upgrading from M2 to M3 APIs -### Bundle Optimization +### Performance Considerations - Tree-shaking enabled in production builds - Lazy loading for route-based features -- OnPush change detection where applicable - -### Memory Management -```typescript -export class ExampleComponent implements OnDestroy { - private destroy$ = new Subject(); - - ngOnInit() { - this.service.data$.pipe( - takeUntil(this.destroy$) - ).subscribe(data => { - // Handle data - }); - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } -} -``` - ---- - -## ๐Ÿค Contributing - -When contributing to this project: - -1. Follow the established naming conventions -2. Extend `BaseRowFieldComponent` for new widgets -3. Add comprehensive tests for new features -4. Update this CLAUDE.md file when adding new patterns -5. Ensure builds pass with `npm run build` -6. Follow the widget development guide for UI components +- Memory leak prevention with proper subscription management using `takeUntil` pattern -For questions about implementation patterns, refer to existing similar components in the codebase as examples. \ No newline at end of file +### Security +- Token-based authentication with automatic expiration +- XSS protection through Angular's built-in sanitization +- Sentry integration for error monitoring and security alerts \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile index ad6fcc46a..6bb2029b1 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,9 +1,19 @@ FROM public.ecr.aws/docker/library/node:18-alpine as builder +ARG VERSION WORKDIR /app COPY package.json yarn.lock ./ RUN yarn global add @angular/cli && yarn install COPY angular.json browserslist tsconfig.app.json tsconfig.json tslint.json ./ +COPY scripts ./scripts/ COPY src ./src/ + +# Update version if VERSION build arg is provided +RUN if [ -n "$VERSION" ]; then \ + echo "Updating package.json version to $VERSION" && \ + npm version $VERSION --no-git-tag-version && \ + yarn update-version; \ + fi + RUN ng build --configuration=production FROM public.ecr.aws/docker/library/nginx:alpine diff --git a/frontend/package.json b/frontend/package.json index 27aaf2d84..d9e5ba978 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,16 +1,17 @@ { "name": "dissendium-v0", - "version": "0.0.0", + "version": "1.0.0", "scripts": { "ng": "ng", - "start": "ng serve", - "build": "ng build", + "start": "node scripts/update-version.js && ng serve", + "build": "node scripts/update-version.js && ng build", "test": "ng test", "test:ci": "ng test --watch=false --browsers=ChromeHeadlessCustom", "lint": "ng lint", "e2e": "ng e2e", "analyze": "webpack-bundle-analyzer dist/dissendium-v0/stats.json", - "build:stats": "ng build --stats-json" + "build:stats": "node scripts/update-version.js && ng build --stats-json", + "update-version": "node scripts/update-version.js" }, "private": true, "dependencies": { diff --git a/frontend/scripts/update-version.js b/frontend/scripts/update-version.js new file mode 100644 index 000000000..efb0b39eb --- /dev/null +++ b/frontend/scripts/update-version.js @@ -0,0 +1,16 @@ +const fs = require('fs'); +const path = require('path'); + +// Read package.json to get the version +const packageJsonPath = path.join(__dirname, '..', 'package.json'); +const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); +const version = packageJson.version; + +// Update the version.ts file +const versionTsPath = path.join(__dirname, '..', 'src', 'app', 'version.ts'); +const versionTsContent = `// This file is auto-generated during build +export const version = '${version}'; +`; + +fs.writeFileSync(versionTsPath, versionTsContent); +console.log(`Updated version.ts with version ${version}`); \ No newline at end of file diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 6f0dde1f8..4b6e4f98a 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -29,6 +29,7 @@ import { UserDeletedSuccessComponent } from './components/user-deleted-success/u import { UserSettingsComponent } from './components/user-settings/user-settings.component'; import { UsersComponent } from './components/users/users.component'; import { ZapierComponent } from './components/zapier/zapier.component'; +import { SsoComponent } from './components/sso/sso.component'; const routes: Routes = [ {path: '', redirectTo: '/connections-list', pathMatch: 'full'}, @@ -46,6 +47,7 @@ const routes: Routes = [ // company routes have to be in this specific order {path: 'company/:company-id/verify/:verification-token', pathMatch: 'full', component: CompanyMemberInvitationComponent, title: 'Invitation | Rocketadmin'}, {path: 'company', pathMatch: 'full', component: CompanyComponent, canActivate: [AuthGuard]}, + {path: 'sso/:company-id', pathMatch: 'full', component: SsoComponent, canActivate: [AuthGuard]}, {path: 'change-password', component: PasswordChangeComponent, canActivate: [AuthGuard]}, {path: 'upgrade', component: UpgradeComponent, canActivate: [AuthGuard], title: 'Upgrade | Rocketadmin'}, {path: 'upgrade/payment', component: PaymentFormComponent, canActivate: [AuthGuard], title: 'Payment | Rocketadmin'}, diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index b87357d03..7e19e03a0 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -220,7 +220,7 @@ diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index a0e7c2d36..1d1b031d0 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -29,6 +29,7 @@ import { UserService } from './services/user.service'; import amplitude from 'amplitude-js'; import { differenceInMilliseconds } from 'date-fns'; import { environment } from '../environments/environment'; +import { version } from './version'; //@ts-ignore window.amplitude = amplitude; @@ -58,6 +59,7 @@ amplitude.getInstance().init("9afd282be91f94da735c11418d5ff4f5"); export class AppComponent { public isSaas = (environment as any).saas; + public appVersion = version; userActivity; userInactive: Subject = new Subject(); currentFeatureNotificationId: string = 'saved-filters'; diff --git a/frontend/src/app/components/company/company.component.css b/frontend/src/app/components/company/company.component.css index 6ed6fcb27..ea18f5bb7 100644 --- a/frontend/src/app/components/company/company.component.css +++ b/frontend/src/app/components/company/company.component.css @@ -77,7 +77,9 @@ } } -.tableHeader__button { +.tableHeader__actions { + display: flex; + gap: 8px; margin-bottom: 16px; } diff --git a/frontend/src/app/components/company/company.component.html b/frontend/src/app/components/company/company.component.html index dde5f5a43..92240981f 100644 --- a/frontend/src/app/components/company/company.component.html +++ b/frontend/src/app/components/company/company.component.html @@ -57,22 +57,35 @@

Members (max 3)

-
- +
+ +
+ +
+
diff --git a/frontend/src/app/components/company/company.component.spec.ts b/frontend/src/app/components/company/company.component.spec.ts index e734a7f7d..13c2becc2 100644 --- a/frontend/src/app/components/company/company.component.spec.ts +++ b/frontend/src/app/components/company/company.component.spec.ts @@ -16,6 +16,7 @@ import { SubscriptionPlans } from 'src/app/models/user'; import { UserService } from 'src/app/services/user.service'; import { of } from 'rxjs'; import { provideHttpClient } from '@angular/common/http'; +import { provideRouter } from '@angular/router'; describe('CompanyComponent', () => { let component: CompanyComponent; @@ -128,6 +129,7 @@ describe('CompanyComponent', () => { CompanyComponent ], providers: [ + provideRouter([]), provideHttpClient(), { provide: CompanyService, useValue: fakeCompanyService }, { provide: UserService, useValue: fakeUserService } diff --git a/frontend/src/app/components/connect-db/connect-db.component.html b/frontend/src/app/components/connect-db/connect-db.component.html index 1a98bd37b..dba77f8cb 100644 --- a/frontend/src/app/components/connect-db/connect-db.component.html +++ b/frontend/src/app/components/connect-db/connect-db.component.html @@ -2,7 +2,7 @@
-

{{ connectionID ? 'Edit credentials' : 'Connect database' }} diff --git a/frontend/src/app/components/login/login.component.html b/frontend/src/app/components/login/login.component.html index 567c4893e..2fce0b124 100644 --- a/frontend/src/app/components/login/login.component.html +++ b/frontend/src/app/components/login/login.component.html @@ -82,13 +82,13 @@

-