generated from corrad-software/corrad-af-2024
967 lines
29 KiB
Markdown
967 lines
29 KiB
Markdown
# Electronic Document Management System (EDMS) - Technical Guide
|
|
|
|
## Table of Contents
|
|
1. [System Overview](#system-overview)
|
|
2. [Architecture](#architecture)
|
|
3. [Technology Stack](#technology-stack)
|
|
4. [Database Schema](#database-schema)
|
|
5. [Installation & Setup](#installation--setup)
|
|
6. [Development Environment](#development-environment)
|
|
7. [Component Structure](#component-structure)
|
|
8. [API & Data Management](#api--data-management)
|
|
9. [Security & Authentication](#security--authentication)
|
|
10. [Deployment](#deployment)
|
|
11. [Maintenance & Monitoring](#maintenance--monitoring)
|
|
12. [Extension & Customization](#extension--customization)
|
|
|
|
## System Overview
|
|
|
|
The Electronic Document Management System (EDMS) is a modern web application built with Nuxt.js 3 and Vue.js 3, designed to provide a comprehensive document management solution for organizations. The system implements a hierarchical document organization structure with role-based access control (RBAC) and supports integration with external authentication providers like Authentik.
|
|
|
|
### Key Technical Features
|
|
- **Modern Frontend**: Vue.js 3 with Composition API and script setup syntax
|
|
- **SSR/SPA Support**: Nuxt.js 3 for optimal performance and SEO
|
|
- **Database**: Prisma ORM with MySQL/PostgreSQL support and migrations
|
|
- **Styling**: TailwindCSS with custom component system
|
|
- **State Management**: Pinia for reactive state management with persistence
|
|
- **Authentication**: Flexible authentication with JWT tokens and RBAC
|
|
- **File Management**: Server-side file handling with metadata and versioning
|
|
- **Real-time Features**: Vue reactivity for live updates and notifications
|
|
- **Responsive Design**: Mobile-first approach with adaptive layouts
|
|
|
|
## Architecture
|
|
|
|
### System Architecture
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ Frontend │ │ Backend │ │ Database │
|
|
│ (Nuxt.js) │◄──►│ (Server API) │◄──►│ (MySQL/PG) │
|
|
│ │ │ │ │ │
|
|
│ • Vue.js 3 │ │ • Prisma ORM │ │ • User Data │
|
|
│ • TailwindCSS │ │ • File System │ │ • Documents │
|
|
│ • Pinia Store │ │ • Authentication│ │ • Permissions │
|
|
│ • Components │ │ • API Routes │ │ • Audit Logs │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
│ │ │
|
|
│ ┌─────────────────┐ │
|
|
│ │ File Storage │ │
|
|
└──────────────►│ • Documents │◄────────────┘
|
|
│ • Versions │
|
|
│ • Thumbnails │
|
|
│ • Temp Files │
|
|
└─────────────────┘
|
|
```
|
|
|
|
### Application Flow
|
|
1. **Authentication**: User authenticates via configured authentication provider
|
|
2. **Authorization**: System validates user permissions against RBAC rules
|
|
3. **Navigation**: User navigates document hierarchy with tree-based structure
|
|
4. **Data Fetching**: Pinia store manages API calls with caching and error handling
|
|
5. **Rendering**: Vue components render UI with reactive updates
|
|
6. **File Operations**: Server handles secure file upload/download/preview
|
|
7. **Access Control**: System enforces granular document permissions
|
|
8. **Audit Trail**: All actions are logged for compliance and security
|
|
|
|
## Technology Stack
|
|
|
|
### Frontend Dependencies
|
|
```json
|
|
{
|
|
"core": {
|
|
"nuxt": "^3.6.5",
|
|
"vue": "^3.x",
|
|
"@pinia/nuxt": "^0.4.11",
|
|
"@pinia-plugin-persistedstate/nuxt": "^1.1.1"
|
|
},
|
|
"styling": {
|
|
"@nuxtjs/tailwindcss": "^6.8.0",
|
|
"sass": "^1.62.0",
|
|
"postcss-import": "^15.1.0"
|
|
},
|
|
"forms": {
|
|
"@formkit/nuxt": "^1.0.0",
|
|
"@formkit/themes": "^1.0.0",
|
|
"@formkit/addons": "^1.0.0",
|
|
"@formkit/pro": "^0.115.3"
|
|
},
|
|
"ui": {
|
|
"apexcharts": "^3.36.0",
|
|
"vue3-apexcharts": "^1.4.1",
|
|
"@vueuse/core": "^9.5.0",
|
|
"@vueuse/nuxt": "^9.5.0",
|
|
"floating-vue": "^2.0.0-beta.24",
|
|
"vue3-dropzone": "^2.0.1"
|
|
},
|
|
"utilities": {
|
|
"luxon": "^3.1.0",
|
|
"uuid": "^10.0.0",
|
|
"crypto-js": "^4.1.1",
|
|
"@shimyshack/uid": "^0.1.7"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Backend Dependencies
|
|
```json
|
|
{
|
|
"database": {
|
|
"@prisma/client": "^5.1.1",
|
|
"prisma": "^5.1.1"
|
|
},
|
|
"authentication": {
|
|
"jsonwebtoken": "^8.5.1"
|
|
},
|
|
"file-handling": {
|
|
"jspdf": "^2.5.1"
|
|
},
|
|
"security": {
|
|
"nuxt-security": "^0.13.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Development Tools
|
|
- **ESLint**: Code linting with Vue.js specific rules
|
|
- **TypeScript**: Type safety with Nuxt TypeScript integration
|
|
- **Prettier**: Consistent code formatting
|
|
- **Vite**: Lightning-fast build tool and HMR
|
|
- **PostCSS**: Advanced CSS processing with plugins
|
|
|
|
## Database Schema
|
|
|
|
### Core Models
|
|
|
|
#### User Management
|
|
```prisma
|
|
model user {
|
|
userID Int @id @default(autoincrement())
|
|
userSecretKey String? @db.VarChar(255)
|
|
userUsername String? @unique @db.VarChar(255)
|
|
userPassword String? @db.VarChar(255)
|
|
userFullName String? @db.VarChar(255)
|
|
userEmail String? @unique @db.VarChar(255)
|
|
userPhone String? @db.VarChar(255)
|
|
userStatus String? @db.VarChar(255)
|
|
userCreatedDate DateTime? @default(now()) @db.DateTime(0)
|
|
userModifiedDate DateTime? @updatedAt @db.DateTime(0)
|
|
|
|
// Relationships
|
|
userrole userrole[]
|
|
accessRequests AccessRequest[]
|
|
permissions AccessPermission[]
|
|
documents Document[] @relation("DocumentCreator")
|
|
cabinets Cabinet[] @relation("CabinetCreator")
|
|
drawers Drawer[] @relation("DrawerCreator")
|
|
folders Folder[] @relation("FolderCreator")
|
|
subfolders Subfolder[] @relation("SubfolderCreator")
|
|
}
|
|
|
|
model role {
|
|
roleID Int @id @default(autoincrement())
|
|
roleName String @unique @db.VarChar(255)
|
|
roleDescription String? @db.Text
|
|
rolePermissions Json? // Flexible permissions structure
|
|
roleCreatedDate DateTime @default(now()) @db.DateTime(0)
|
|
roleModifiedDate DateTime @updatedAt @db.DateTime(0)
|
|
|
|
userrole userrole[]
|
|
permissions AccessPermission[]
|
|
}
|
|
```
|
|
|
|
#### Document Hierarchy
|
|
```prisma
|
|
// Cabinet → Drawer → Folder → Subfolder → Document
|
|
|
|
model Cabinet {
|
|
id Int @id @default(autoincrement())
|
|
name String @db.VarChar(255)
|
|
description String? @db.Text
|
|
metadata Json? // Flexible metadata storage
|
|
createdAt DateTime @default(now()) @db.DateTime(0)
|
|
updatedAt DateTime @updatedAt @db.DateTime(0)
|
|
createdBy Int
|
|
status String @default("active") @db.VarChar(50)
|
|
|
|
user user @relation("CabinetCreator", fields: [createdBy], references: [userID])
|
|
drawers Drawer[]
|
|
permissions AccessPermission[]
|
|
|
|
@@index([createdBy])
|
|
@@index([status])
|
|
}
|
|
|
|
model Document {
|
|
id Int @id @default(autoincrement())
|
|
name String @db.VarChar(255)
|
|
description String? @db.Text
|
|
fileSize Int @default(0)
|
|
fileType String @db.VarChar(100)
|
|
fileExtension String @db.VarChar(20)
|
|
filePath String @db.VarChar(500)
|
|
thumbnailPath String? @db.VarChar(500)
|
|
checksum String? @db.VarChar(64)
|
|
version Int @default(1)
|
|
isTemplate Boolean @default(false)
|
|
isPublic Boolean @default(false)
|
|
metadata Json? // Custom metadata fields
|
|
tags String? @db.Text
|
|
folderId Int?
|
|
subfolderId Int?
|
|
createdAt DateTime @default(now()) @db.DateTime(0)
|
|
updatedAt DateTime @updatedAt @db.DateTime(0)
|
|
createdBy Int
|
|
status String @default("active") @db.VarChar(50)
|
|
|
|
folder Folder? @relation("FolderDocuments", fields: [folderId], references: [id], onDelete: SetNull)
|
|
subfolder Subfolder? @relation("SubfolderDocuments", fields: [subfolderId], references: [id], onDelete: SetNull)
|
|
user user @relation("DocumentCreator", fields: [createdBy], references: [userID])
|
|
accessRequests AccessRequest[]
|
|
permissions AccessPermission[]
|
|
versions DocumentVersion[]
|
|
|
|
@@index([folderId])
|
|
@@index([subfolderId])
|
|
@@index([createdBy])
|
|
@@index([fileType])
|
|
@@index([status])
|
|
@@fulltext([name, description, tags])
|
|
}
|
|
```
|
|
|
|
#### Access Control & Workflow
|
|
```prisma
|
|
model AccessPermission {
|
|
id Int @id @default(autoincrement())
|
|
userId Int?
|
|
roleId Int?
|
|
documentId Int?
|
|
cabinetId Int?
|
|
drawerId Int?
|
|
folderId Int?
|
|
subfolderId Int?
|
|
permissionLevel String @db.VarChar(50) // view, download, print, edit, full, admin
|
|
conditions Json? // Additional permission conditions
|
|
createdAt DateTime @default(now()) @db.DateTime(0)
|
|
updatedAt DateTime @updatedAt @db.DateTime(0)
|
|
expiresAt DateTime? @db.DateTime(0)
|
|
createdBy Int?
|
|
|
|
user user? @relation(fields: [userId], references: [userID], onDelete: SetNull)
|
|
role role? @relation(fields: [roleId], references: [roleID], onDelete: SetNull)
|
|
document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
|
cabinet Cabinet? @relation(fields: [cabinetId], references: [id], onDelete: Cascade)
|
|
drawer Drawer? @relation(fields: [drawerId], references: [id], onDelete: Cascade)
|
|
folder Folder? @relation(fields: [folderId], references: [id], onDelete: Cascade)
|
|
subfolder Subfolder? @relation(fields: [subfolderId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([roleId])
|
|
@@index([documentId])
|
|
@@index([expiresAt])
|
|
}
|
|
|
|
model AccessRequest {
|
|
id Int @id @default(autoincrement())
|
|
documentId Int
|
|
userId Int
|
|
requestedLevel String @db.VarChar(50) // view, download, print, edit, full
|
|
duration String? @db.VarChar(50) // 7d, 14d, 30d, 60d, 90d, permanent
|
|
justification String? @db.Text
|
|
status String @default("pending") @db.VarChar(50) // pending, approved, rejected, expired
|
|
responseNote String? @db.Text
|
|
requestedAt DateTime @default(now()) @db.DateTime(0)
|
|
respondedAt DateTime? @db.DateTime(0)
|
|
respondedBy Int?
|
|
expiresAt DateTime? @db.DateTime(0)
|
|
|
|
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
|
user user @relation(fields: [userId], references: [userID])
|
|
|
|
@@index([documentId])
|
|
@@index([userId])
|
|
@@index([status])
|
|
}
|
|
```
|
|
|
|
## Installation & Setup
|
|
|
|
### Prerequisites
|
|
- Node.js 18+ and npm/yarn/pnpm
|
|
- MySQL 8.0+ or PostgreSQL 13+
|
|
- Git for version control
|
|
- Optional: Docker for containerized deployment
|
|
|
|
### Installation Steps
|
|
|
|
1. **Clone Repository**
|
|
```bash
|
|
git clone <repository-url>
|
|
cd edms
|
|
```
|
|
|
|
2. **Install Dependencies**
|
|
```bash
|
|
# Using npm
|
|
npm install
|
|
|
|
# Using yarn
|
|
yarn install
|
|
|
|
# Using pnpm
|
|
pnpm install
|
|
```
|
|
|
|
3. **Environment Configuration**
|
|
Create `.env` file:
|
|
```env
|
|
# Database Configuration
|
|
DATABASE_URL="mysql://username:password@localhost:3306/edms_db"
|
|
# For PostgreSQL: DATABASE_URL="postgresql://username:password@localhost:5432/edms_db"
|
|
|
|
# Authentication
|
|
JWT_SECRET="your-jwt-secret-key-min-256-bits"
|
|
SESSION_SECRET="your-session-secret-key"
|
|
|
|
# External Authentication (Optional)
|
|
AUTHENTIK_BASE_URL="https://auth.yourdomain.com"
|
|
AUTHENTIK_CLIENT_ID="your-client-id"
|
|
AUTHENTIK_CLIENT_SECRET="your-client-secret"
|
|
|
|
# File Storage
|
|
UPLOAD_PATH="/var/uploads/edms"
|
|
TEMP_PATH="/var/tmp/edms"
|
|
MAX_FILE_SIZE="104857600" # 100MB in bytes
|
|
ALLOWED_FILE_TYPES="pdf,doc,docx,xls,xlsx,ppt,pptx,txt,jpg,jpeg,png,gif"
|
|
|
|
# Application Configuration
|
|
NUXT_SECRET_KEY="your-nuxt-app-secret"
|
|
BASE_URL="http://localhost:3000"
|
|
NODE_ENV="development"
|
|
|
|
# Security
|
|
CORS_ORIGIN="http://localhost:3000"
|
|
RATE_LIMIT_MAX="100" # requests per window
|
|
RATE_LIMIT_WINDOW="15" # minutes
|
|
|
|
# Monitoring & Logging
|
|
LOG_LEVEL="info"
|
|
LOG_FILE="/var/log/edms/app.log"
|
|
```
|
|
|
|
4. **Database Setup**
|
|
```bash
|
|
# Generate Prisma client
|
|
npx prisma generate
|
|
|
|
# Run database migrations
|
|
npx prisma db push
|
|
|
|
# Seed initial data (optional)
|
|
npx prisma db seed
|
|
|
|
# View database in Prisma Studio (optional)
|
|
npx prisma studio
|
|
```
|
|
|
|
5. **Development Server**
|
|
```bash
|
|
# Start development server
|
|
npm run dev
|
|
|
|
# Access application at http://localhost:3000
|
|
```
|
|
|
|
## Development Environment
|
|
|
|
### Project Structure
|
|
```
|
|
edms/
|
|
├── components/ # Vue components
|
|
│ ├── dms/ # DMS-specific components
|
|
│ │ ├── explorer/ # Document explorer interface
|
|
│ │ ├── dialogs/ # Modal dialogs and forms
|
|
│ │ ├── viewers/ # Document preview components
|
|
│ │ └── navigation/ # Tree and breadcrumb navigation
|
|
│ ├── layouts/ # Layout components
|
|
│ ├── formkit/ # FormKit custom components
|
|
│ └── [Rs*].vue # Reusable UI components (RsButton, RsCard, etc.)
|
|
├── pages/ # Nuxt pages (file-based routing)
|
|
│ ├── dms/ # DMS-related pages
|
|
│ ├── dashboard/ # Dashboard and analytics
|
|
│ ├── login/ # Authentication pages
|
|
│ └── index.vue # Homepage
|
|
├── stores/ # Pinia state stores
|
|
│ ├── dms.js # Document management store
|
|
│ ├── auth.js # Authentication store
|
|
│ └── app.js # Global application store
|
|
├── middleware/ # Route middleware
|
|
│ ├── auth.js # Authentication middleware
|
|
│ └── rbac.js # Role-based access control
|
|
├── layouts/ # Nuxt layouts
|
|
│ ├── default.vue # Default application layout
|
|
│ └── auth.vue # Authentication layout
|
|
├── server/ # Server-side code
|
|
│ ├── api/ # API routes
|
|
│ └── middleware/ # Server middleware
|
|
├── prisma/ # Database configuration
|
|
│ ├── schema.prisma # Database schema
|
|
│ └── migrations/ # Database migrations
|
|
├── public/ # Static assets
|
|
├── assets/ # Build-time assets
|
|
├── plugins/ # Nuxt plugins
|
|
├── composables/ # Vue composables
|
|
└── utils/ # Utility functions
|
|
```
|
|
|
|
### Component Architecture
|
|
|
|
#### Core EDMS Components
|
|
1. **DMSExplorer.vue**: Main document browser with tree navigation, content views, and details panel
|
|
2. **DMSTreeView.vue**: Recursive tree navigation for hierarchical structure
|
|
3. **DMSDocumentViewer.vue**: Multi-format document viewer with zoom and controls
|
|
4. **DMSAccessRequestDialog.vue**: Access request form with approval workflow
|
|
5. **DMSUploadDialog.vue**: File upload interface with metadata assignment
|
|
|
|
#### Custom UI Components (Rs Prefix)
|
|
- **RsButton.vue**: Standardized button component with variants
|
|
- **RsCard.vue**: Container component with consistent styling
|
|
- **RsModal.vue**: Modal dialog base component
|
|
- **RsInput.vue**: Standardized input field component
|
|
- **RsSelect.vue**: Standardized dropdown/select component
|
|
- **RsTextarea.vue**: Standardized textarea component
|
|
- **RsTable.vue**: Data table with sorting and filtering
|
|
- **RsDropdown.vue**: Dropdown menu component
|
|
|
|
## Design System
|
|
|
|
### Overview
|
|
The EDMS implements a comprehensive design system built on a standardized component library with the "Rs" prefix (Reusable System). This ensures consistency, maintainability, and accessibility across the entire application.
|
|
|
|
### Design Principles
|
|
- **🎯 Consistency**: All components follow unified design patterns and naming conventions
|
|
- **🔧 Modularity**: Components are reusable and composable for complex interfaces
|
|
- **🌙 Dark Mode**: Universal support for both light and dark themes via CSS variables
|
|
- **📱 Responsive**: Mobile-first approach with adaptive layouts
|
|
- **♿ Accessibility**: WCAG-compliant with proper ARIA attributes and keyboard navigation
|
|
|
|
### Component Library
|
|
|
|
#### Form Components
|
|
|
|
##### RsInput.vue
|
|
```vue
|
|
<rs-input
|
|
v-model="value"
|
|
label="Field Label"
|
|
placeholder="Enter text..."
|
|
:required="true"
|
|
:error="validationError"
|
|
size="md"
|
|
:disabled="false"
|
|
/>
|
|
```
|
|
|
|
**Props:**
|
|
- `modelValue`: String/Number - Input value
|
|
- `label`: String - Field label
|
|
- `placeholder`: String - Placeholder text
|
|
- `type`: String - Input type (text, email, password, etc.)
|
|
- `required`: Boolean - Required field indicator
|
|
- `error`: String - Error message
|
|
- `size`: String - Size variant (sm, md, lg)
|
|
- `disabled`: Boolean - Disabled state
|
|
|
|
##### RsSelect.vue
|
|
```vue
|
|
<rs-select
|
|
v-model="selectedValue"
|
|
:options="optionsList"
|
|
label="Select Option"
|
|
placeholder="Choose..."
|
|
:multiple="false"
|
|
:required="true"
|
|
/>
|
|
```
|
|
|
|
**Props:**
|
|
- `modelValue`: String/Number/Array - Selected value(s)
|
|
- `options`: Array - Options list (objects with value/label or simple strings)
|
|
- `label`: String - Field label
|
|
- `placeholder`: String - Placeholder text
|
|
- `multiple`: Boolean - Multiple selection support
|
|
- `required`: Boolean - Required field indicator
|
|
- `error`: String - Error message
|
|
- `disabled`: Boolean - Disabled state
|
|
|
|
##### RsTextarea.vue
|
|
```vue
|
|
<rs-textarea
|
|
v-model="content"
|
|
label="Message"
|
|
placeholder="Enter message..."
|
|
:rows="4"
|
|
resize="vertical"
|
|
:required="true"
|
|
/>
|
|
```
|
|
|
|
**Props:**
|
|
- `modelValue`: String - Textarea content
|
|
- `label`: String - Field label
|
|
- `placeholder`: String - Placeholder text
|
|
- `rows`: Number - Number of visible rows
|
|
- `resize`: String - Resize behavior (none, both, horizontal, vertical)
|
|
- `required`: Boolean - Required field indicator
|
|
- `error`: String - Error message
|
|
- `disabled`: Boolean - Disabled state
|
|
|
|
#### UI Components
|
|
|
|
##### RsButton.vue
|
|
```vue
|
|
<rs-button
|
|
variant="primary"
|
|
size="md"
|
|
:disabled="false"
|
|
@click="handleClick"
|
|
>
|
|
Button Text
|
|
</rs-button>
|
|
```
|
|
|
|
**Variants:**
|
|
- `primary`: Blue primary button
|
|
- `secondary`: Gray secondary button
|
|
- `info`: Blue info button
|
|
- `success`: Green success button
|
|
- `warning`: Yellow warning button
|
|
- `danger`: Red danger button
|
|
- `primary-outline`: Outlined primary button
|
|
- `secondary-outline`: Outlined secondary button
|
|
- `primary-text`: Text-only primary button
|
|
|
|
**Sizes:**
|
|
- `sm`: Small button (padding: 0.25rem 0.75rem)
|
|
- `md`: Medium button (padding: 0.5rem 1rem)
|
|
- `lg`: Large button (padding: 0.75rem 1.25rem)
|
|
|
|
##### RsCard.vue
|
|
```vue
|
|
<rs-card>
|
|
<template #header>
|
|
Card Header
|
|
</template>
|
|
<template #body>
|
|
Card content goes here
|
|
</template>
|
|
<template #footer>
|
|
Card footer with actions
|
|
</template>
|
|
</rs-card>
|
|
```
|
|
|
|
##### RsModal.vue
|
|
```vue
|
|
<rs-modal :visible="showModal" @close="closeModal" size="md">
|
|
<template #header>
|
|
Modal Title
|
|
</template>
|
|
<template #body>
|
|
Modal content
|
|
</template>
|
|
<template #footer>
|
|
<rs-button variant="secondary" @click="closeModal">Cancel</rs-button>
|
|
<rs-button variant="primary" @click="confirm">Confirm</rs-button>
|
|
</template>
|
|
</rs-modal>
|
|
```
|
|
|
|
**Sizes:**
|
|
- `sm`: 300px width
|
|
- `md`: 500px width
|
|
- `lg`: 800px width
|
|
- `xl`: 1000px width
|
|
- `full`: Full screen width
|
|
|
|
### Color System
|
|
|
|
The design system uses CSS custom properties for consistent theming:
|
|
|
|
```css
|
|
:root {
|
|
/* Primary Colors */
|
|
--color-primary: 59 130 246; /* Blue */
|
|
--color-secondary: 100 116 139; /* Gray */
|
|
--color-info: 14 165 233; /* Sky Blue */
|
|
--color-success: 34 197 94; /* Green */
|
|
--color-warning: 251 191 36; /* Yellow */
|
|
--color-danger: 239 68 68; /* Red */
|
|
|
|
/* Background Colors */
|
|
--bg-1: 248 250 252; /* Light Gray */
|
|
--bg-2: 255 255 255; /* White */
|
|
|
|
/* Text Colors */
|
|
--text-color: 15 23 42; /* Slate 900 */
|
|
--text-muted: 100 116 139; /* Slate 500 */
|
|
|
|
/* Border Colors */
|
|
--border-color: 226 232 240; /* Slate 200 */
|
|
--fk-border-color: 209 213 219; /* Gray 300 */
|
|
}
|
|
```
|
|
|
|
### Typography Scale
|
|
|
|
```css
|
|
/* Font Sizes */
|
|
.text-xs { font-size: 0.75rem; } /* 12px */
|
|
.text-sm { font-size: 0.875rem; } /* 14px */
|
|
.text-base { font-size: 1rem; } /* 16px */
|
|
.text-lg { font-size: 1.125rem; } /* 18px */
|
|
.text-xl { font-size: 1.25rem; } /* 20px */
|
|
.text-2xl { font-size: 1.5rem; } /* 24px */
|
|
.text-3xl { font-size: 1.875rem; } /* 30px */
|
|
|
|
/* Font Weights */
|
|
.font-light { font-weight: 300; }
|
|
.font-normal { font-weight: 400; }
|
|
.font-medium { font-weight: 500; }
|
|
.font-semibold { font-weight: 600; }
|
|
.font-bold { font-weight: 700; }
|
|
```
|
|
|
|
### Spacing Scale
|
|
|
|
```css
|
|
/* Spacing (padding/margin) */
|
|
.p-1 { padding: 0.25rem; } /* 4px */
|
|
.p-2 { padding: 0.5rem; } /* 8px */
|
|
.p-3 { padding: 0.75rem; } /* 12px */
|
|
.p-4 { padding: 1rem; } /* 16px */
|
|
.p-6 { padding: 1.5rem; } /* 24px */
|
|
.p-8 { padding: 2rem; } /* 32px */
|
|
```
|
|
|
|
### Usage Guidelines
|
|
|
|
#### ✅ Best Practices
|
|
1. **Always use Rs components** for UI elements instead of custom styling
|
|
2. **Use semantic variants** (primary, secondary, danger) rather than color names
|
|
3. **Follow consistent spacing** using the predefined scale
|
|
4. **Use CSS variables** for colors instead of hardcoded values
|
|
5. **Test in both themes** (light and dark mode)
|
|
6. **Maintain accessibility** with proper labels and ARIA attributes
|
|
|
|
#### ❌ Anti-patterns
|
|
1. **Don't use manual Tailwind classes** for buttons (e.g., `px-4 py-2 bg-blue-500`)
|
|
2. **Don't create custom input styling** without extending Rs components
|
|
3. **Don't hardcode colors** or spacing values
|
|
4. **Don't mix different component styling approaches**
|
|
5. **Don't forget dark mode** support in custom components
|
|
|
|
### FormKit Integration
|
|
|
|
The design system integrates with FormKit for advanced form handling:
|
|
|
|
```javascript
|
|
// FormKit theme configuration
|
|
export default {
|
|
global: {
|
|
label: "formkit-label-global",
|
|
outer: "formkit-outer-global",
|
|
wrapper: "formkit-wrapper-global",
|
|
},
|
|
button: {
|
|
wrapper: "formkit-wrapper-button",
|
|
input: "formkit-input-button",
|
|
},
|
|
text: {
|
|
label: "formkit-outer-text",
|
|
inner: "formkit-inner-text",
|
|
input: "formkit-input-text",
|
|
}
|
|
}
|
|
```
|
|
|
|
### Component Registration
|
|
|
|
All Rs components are globally registered via the component index:
|
|
|
|
```javascript
|
|
// pages/devtool/code-playground/index.js
|
|
export {
|
|
RsAlert,
|
|
RsBadge,
|
|
RsButton,
|
|
RsCard,
|
|
RsInput,
|
|
RsModal,
|
|
RsSelect,
|
|
RsTextarea,
|
|
RsTable,
|
|
// ... other components
|
|
};
|
|
```
|
|
|
|
### Design System Documentation
|
|
|
|
Access the interactive design system documentation at `/dms/design-system` to:
|
|
- View all components with live examples
|
|
- Test different variants and states
|
|
- Copy code snippets for implementation
|
|
- Understand usage guidelines and best practices
|
|
|
|
### Future Enhancements
|
|
|
|
Planned design system improvements:
|
|
- **Animation Library**: Consistent micro-interactions and transitions
|
|
- **Icon System**: Standardized icon library with consistent sizing
|
|
- **Layout Components**: Grid and flexbox utilities
|
|
- **Advanced Form Components**: Date pickers, multi-select, autocomplete
|
|
- **Data Visualization**: Chart and graph components
|
|
- **Notification System**: Toast and alert components
|
|
|
|
## API & Data Management
|
|
|
|
### Server API Routes
|
|
|
|
#### Document Management
|
|
```javascript
|
|
// server/api/dms/documents/[id].get.js
|
|
export default defineEventHandler(async (event) => {
|
|
const id = getRouterParam(event, 'id')
|
|
// Fetch document with access control
|
|
})
|
|
|
|
// server/api/dms/upload.post.js
|
|
export default defineEventHandler(async (event) => {
|
|
// Handle file upload with validation
|
|
})
|
|
|
|
// server/api/dms/search.get.js
|
|
export default defineEventHandler(async (event) => {
|
|
const query = getQuery(event)
|
|
// Perform document search
|
|
})
|
|
```
|
|
|
|
#### Access Control
|
|
```javascript
|
|
// server/api/dms/access-request.post.js
|
|
export default defineEventHandler(async (event) => {
|
|
// Process access requests
|
|
})
|
|
|
|
// server/api/dms/permissions/[id].get.js
|
|
export default defineEventHandler(async (event) => {
|
|
// Get user permissions for item
|
|
})
|
|
```
|
|
|
|
### Data Validation
|
|
|
|
#### Prisma Schema Validation
|
|
- Field constraints and types
|
|
- Relationship integrity
|
|
- Index optimization
|
|
|
|
#### Frontend Validation
|
|
```javascript
|
|
// FormKit validation rules
|
|
const documentValidation = {
|
|
title: 'required|length:3,255',
|
|
description: 'length:0,1000',
|
|
fileType: 'required|in:pdf,doc,docx,xls,xlsx,jpg,png',
|
|
accessLevel: 'required|in:public,private,personal'
|
|
}
|
|
```
|
|
|
|
## Security & Authentication
|
|
|
|
### Authentication Flow
|
|
1. **User Login**: Redirect to Authentik
|
|
2. **Token Exchange**: Receive JWT token
|
|
3. **Token Validation**: Verify on each request
|
|
4. **Session Management**: Store in secure cookie
|
|
5. **Token Refresh**: Automatic renewal
|
|
|
|
### Authorization Levels
|
|
- **System Admin**: Full system access
|
|
- **Department Admin**: Department-wide permissions
|
|
- **Document Owner**: Full access to owned documents
|
|
- **User**: Access based on granted permissions
|
|
|
|
### File Security
|
|
- **Path Traversal Protection**: Validate file paths
|
|
- **File Type Validation**: Whitelist allowed formats
|
|
- **Size Limits**: Prevent large file uploads
|
|
- **Virus Scanning**: Optional integration
|
|
- **Access Logging**: Track file access
|
|
|
|
### Data Protection
|
|
- **SQL Injection Prevention**: Parameterized queries via Prisma
|
|
- **XSS Protection**: Input sanitization
|
|
- **CSRF Protection**: Token validation
|
|
- **Secure Headers**: Security-focused HTTP headers
|
|
|
|
## Deployment
|
|
|
|
### Production Build
|
|
```bash
|
|
# Build for production
|
|
npm run build
|
|
|
|
# Generate static files (if needed)
|
|
npm run generate
|
|
|
|
# Preview production build
|
|
npm run preview
|
|
```
|
|
|
|
### Environment Configuration
|
|
|
|
#### Production Environment Variables
|
|
```env
|
|
NODE_ENV=production
|
|
DATABASE_URL="mysql://prod_user:password@db.server:3306/edms_prod"
|
|
NUXT_SECRET_KEY="production-secret-key"
|
|
BASE_URL="https://dms.jkr-kotabharu.gov.my"
|
|
```
|
|
|
|
#### Docker Deployment
|
|
```dockerfile
|
|
FROM node:18-alpine
|
|
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci --only=production
|
|
|
|
COPY . .
|
|
RUN npm run build
|
|
|
|
EXPOSE 3000
|
|
CMD ["npm", "run", "start"]
|
|
```
|
|
|
|
### Nginx Configuration
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name dms.jkr-kotabharu.gov.my;
|
|
|
|
location / {
|
|
proxy_pass http://localhost:3000;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
}
|
|
|
|
location /uploads/ {
|
|
alias /var/www/uploads/;
|
|
expires 1y;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Maintenance & Monitoring
|
|
|
|
### Database Maintenance
|
|
```sql
|
|
-- Regular maintenance queries
|
|
OPTIMIZE TABLE document;
|
|
ANALYZE TABLE access_permission;
|
|
|
|
-- Cleanup old access requests
|
|
DELETE FROM access_request
|
|
WHERE status = 'rejected'
|
|
AND requested_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
|
|
```
|
|
|
|
### Backup Strategy
|
|
- **Database Backups**: Daily automated backups
|
|
- **File Storage Backups**: Incremental file backups
|
|
- **Configuration Backups**: Version control for configs
|
|
|
|
### Monitoring
|
|
- **Application Performance**: Response times, error rates
|
|
- **Database Performance**: Query performance, connection counts
|
|
- **File Storage**: Disk usage, file integrity
|
|
- **Security Events**: Failed logins, access violations
|
|
|
|
### Logging
|
|
```javascript
|
|
// Server-side logging
|
|
import { createLogger } from 'winston'
|
|
|
|
const logger = createLogger({
|
|
level: 'info',
|
|
format: winston.format.json(),
|
|
transports: [
|
|
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
|
new winston.transports.File({ filename: 'combined.log' })
|
|
]
|
|
})
|
|
```
|
|
|
|
## Extension & Customization
|
|
|
|
### Adding New Document Types
|
|
1. Update Prisma schema with new file types
|
|
2. Add validation rules for the file type
|
|
3. Implement viewer component for the format
|
|
4. Update upload dialog to support the type
|
|
|
|
### Custom Access Control
|
|
1. Extend AccessPermission model
|
|
2. Implement custom permission logic
|
|
3. Update UI to reflect new permissions
|
|
4. Add admin interface for permission management
|
|
|
|
### Integration Points
|
|
- **External Authentication**: LDAP/Active Directory
|
|
- **Document Processing**: OCR, text extraction
|
|
- **Workflow Systems**: Approval workflows
|
|
- **Notification Systems**: Email/SMS notifications
|
|
- **Analytics**: Document usage analytics
|
|
|
|
### API Extensions
|
|
```javascript
|
|
// Custom API endpoint example
|
|
// server/api/custom/analytics.get.js
|
|
export default defineEventHandler(async (event) => {
|
|
// Custom analytics logic
|
|
return {
|
|
totalDocuments: count,
|
|
storageUsed: size,
|
|
activeUsers: userCount
|
|
}
|
|
})
|
|
```
|
|
|
|
### Theme Customization
|
|
```javascript
|
|
// tailwind.config.js extensions
|
|
module.exports = {
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: {
|
|
50: '#eff6ff',
|
|
500: '#3b82f6',
|
|
900: '#1e3a8a'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
**Document Version**: 2.0
|
|
**Last Updated**: December 2024
|
|
**System Version**: EDMS v1.0
|
|
**Technology Stack**: Nuxt.js 3, Vue.js 3, Prisma, TailwindCSS
|
|
**Database**: MySQL/PostgreSQL
|
|
**Authentication**: JWT with optional external providers |