Prepare application for production deployment with Docker and PostgreSQL
Integrate PostgreSQL database support, add Docker deployment configurations, and implement health check endpoints. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/ahHWEFX
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# Development files
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
dist
|
||||||
|
.vite
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
README.md
|
||||||
|
docs
|
||||||
|
|
||||||
|
# Test files
|
||||||
|
**/*.test.ts
|
||||||
|
**/*.spec.ts
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp
|
||||||
|
temp
|
||||||
|
*.tmp
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# Database Configuration (Docker Compose)
|
||||||
|
# These are used by docker-compose.yml to create the PostgreSQL container
|
||||||
|
POSTGRES_USER=taskflow
|
||||||
|
POSTGRES_PASSWORD=taskflow_password
|
||||||
|
POSTGRES_DB=taskflow
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
# Database URL (used by the application)
|
||||||
|
# Format: postgresql://user:password@host:port/database
|
||||||
|
# For Docker: use the service name 'postgres' as the host
|
||||||
|
DATABASE_URL=postgresql://taskflow:taskflow_password@postgres:5432/taskflow
|
||||||
|
|
||||||
|
# For external PostgreSQL (non-Docker):
|
||||||
|
# DATABASE_URL=postgresql://user:password@your-db-host:5432/your-db-name
|
||||||
|
|
||||||
|
# Application Port (external mapping)
|
||||||
|
APP_PORT=5000
|
||||||
|
|
||||||
|
# Development Mode (optional)
|
||||||
|
# Set USE_DB=true to use database in development mode
|
||||||
|
# USE_DB=true
|
||||||
@@ -18,6 +18,10 @@ externalPort = 80
|
|||||||
localPort = 35345
|
localPort = 35345
|
||||||
externalPort = 3002
|
externalPort = 3002
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
localPort = 37553
|
||||||
|
externalPort = 4200
|
||||||
|
|
||||||
[[ports]]
|
[[ports]]
|
||||||
localPort = 39063
|
localPort = 39063
|
||||||
externalPort = 3001
|
externalPort = 3001
|
||||||
|
|||||||
+308
@@ -0,0 +1,308 @@
|
|||||||
|
# TaskFlow - Docker Deployment Guide
|
||||||
|
|
||||||
|
This guide explains how to deploy TaskFlow using Docker with a separate PostgreSQL database.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Docker Engine 20.10 or later
|
||||||
|
- Docker Compose 2.0 or later
|
||||||
|
- At least 2GB of available RAM
|
||||||
|
- 10GB of available disk space
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Environment Configuration
|
||||||
|
|
||||||
|
Create a `.env` file in the root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit the `.env` file with your configuration:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
POSTGRES_USER=taskflow
|
||||||
|
POSTGRES_PASSWORD=your_secure_password_here
|
||||||
|
POSTGRES_DB=taskflow
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
# Database URL (update with your credentials)
|
||||||
|
DATABASE_URL=postgresql://taskflow:your_secure_password_here@postgres:5432/taskflow
|
||||||
|
|
||||||
|
# Application Port (external mapping)
|
||||||
|
APP_PORT=5000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:** Change the `POSTGRES_PASSWORD` to a secure password!
|
||||||
|
|
||||||
|
### 2. Start the Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build and start all services
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Check service status
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
The application will be available at `http://localhost:5000`
|
||||||
|
|
||||||
|
### 3. Stop the Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop services
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Stop and remove volumes (WARNING: This will delete all data!)
|
||||||
|
docker-compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### Using Docker Stack (Swarm Mode)
|
||||||
|
|
||||||
|
1. **Initialize Docker Swarm** (if not already done):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker swarm init
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create a production `.env` file**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set secure credentials
|
||||||
|
export POSTGRES_PASSWORD="your_very_secure_password"
|
||||||
|
export POSTGRES_USER="taskflow"
|
||||||
|
export POSTGRES_DB="taskflow"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Deploy the stack**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stack deploy -c docker-compose.yml taskflow
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Check stack status**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stack services taskflow
|
||||||
|
docker stack ps taskflow
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **View logs**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker service logs taskflow_app
|
||||||
|
docker service logs taskflow_postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Remove the stack**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stack rm taskflow
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using External PostgreSQL Database
|
||||||
|
|
||||||
|
If you want to use an external PostgreSQL instance instead of the containerized one:
|
||||||
|
|
||||||
|
1. **Update `.env` file**:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DATABASE_URL=postgresql://username:password@your-db-host:5432/your-db-name
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Modify `docker-compose.yml`** to remove the postgres service:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: production
|
||||||
|
container_name: taskflow-app
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
DATABASE_URL: ${DATABASE_URL}
|
||||||
|
PORT: 5000
|
||||||
|
ports:
|
||||||
|
- "${APP_PORT:-5000}:5000"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Start only the app service**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up app -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Management
|
||||||
|
|
||||||
|
### Backup Database
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create backup
|
||||||
|
docker exec taskflow-db pg_dump -U taskflow taskflow > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||||
|
|
||||||
|
# Or using docker-compose
|
||||||
|
docker-compose exec postgres pg_dump -U taskflow taskflow > backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restore Database
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Restore from backup
|
||||||
|
docker exec -i taskflow-db psql -U taskflow taskflow < backup.sql
|
||||||
|
|
||||||
|
# Or using docker-compose
|
||||||
|
docker-compose exec -T postgres psql -U taskflow taskflow < backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Access Database
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Connect to PostgreSQL shell
|
||||||
|
docker exec -it taskflow-db psql -U taskflow -d taskflow
|
||||||
|
|
||||||
|
# Or using docker-compose
|
||||||
|
docker-compose exec postgres psql -U taskflow -d taskflow
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Migrations
|
||||||
|
|
||||||
|
The application automatically runs database migrations on startup. To manually trigger migrations:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Inside the container
|
||||||
|
docker exec taskflow-app npm run db:push
|
||||||
|
|
||||||
|
# Or rebuild and restart
|
||||||
|
docker-compose up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Maintenance
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
Both services have health checks configured:
|
||||||
|
|
||||||
|
- **App**: `http://localhost:5000/api/health`
|
||||||
|
- **Database**: Automatic PostgreSQL health check
|
||||||
|
|
||||||
|
Check health status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# All services
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Specific service
|
||||||
|
docker-compose logs -f app
|
||||||
|
docker-compose logs -f postgres
|
||||||
|
|
||||||
|
# Last 100 lines
|
||||||
|
docker-compose logs --tail=100 app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Pull latest changes
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# Rebuild and restart
|
||||||
|
docker-compose up --build -d
|
||||||
|
|
||||||
|
# Remove old images
|
||||||
|
docker image prune -f
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Application won't start
|
||||||
|
|
||||||
|
1. Check logs: `docker-compose logs app`
|
||||||
|
2. Verify DATABASE_URL is correct
|
||||||
|
3. Ensure PostgreSQL is healthy: `docker-compose ps`
|
||||||
|
|
||||||
|
### Database connection errors
|
||||||
|
|
||||||
|
1. Verify PostgreSQL is running: `docker-compose ps postgres`
|
||||||
|
2. Check connection string in `.env`
|
||||||
|
3. Ensure network connectivity: `docker network inspect taskflow_taskflow-network`
|
||||||
|
|
||||||
|
### Port already in use
|
||||||
|
|
||||||
|
Change the `APP_PORT` in `.env` file:
|
||||||
|
|
||||||
|
```env
|
||||||
|
APP_PORT=8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Then restart: `docker-compose up -d`
|
||||||
|
|
||||||
|
### Out of disk space
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove unused images
|
||||||
|
docker image prune -a
|
||||||
|
|
||||||
|
# Remove unused volumes
|
||||||
|
docker volume prune
|
||||||
|
|
||||||
|
# Remove unused networks
|
||||||
|
docker network prune
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
1. **Change default passwords** in `.env` file
|
||||||
|
2. **Use environment variables** for sensitive data
|
||||||
|
3. **Enable SSL/TLS** for production databases
|
||||||
|
4. **Restrict network access** using firewall rules
|
||||||
|
5. **Regular backups** of database
|
||||||
|
6. **Keep Docker images updated** regularly
|
||||||
|
7. **Use secrets management** for production (Docker Secrets, Vault, etc.)
|
||||||
|
|
||||||
|
## Performance Tuning
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
|
||||||
|
Edit `docker-compose.yml` to add PostgreSQL configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
postgres:
|
||||||
|
command: postgres -c max_connections=200 -c shared_buffers=256MB
|
||||||
|
```
|
||||||
|
|
||||||
|
### Application
|
||||||
|
|
||||||
|
Scale the application service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d --scale app=3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues and questions:
|
||||||
|
- Check logs first: `docker-compose logs`
|
||||||
|
- Review this guide
|
||||||
|
- Check Docker and PostgreSQL documentation
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
# Base stage with Node.js
|
||||||
|
FROM node:20-alpine AS base
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Dependencies stage
|
||||||
|
FROM base AS dependencies
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --only=production && \
|
||||||
|
cp -R node_modules /tmp/prod_node_modules && \
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
# Build stage
|
||||||
|
FROM base AS build
|
||||||
|
COPY --from=dependencies /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the client application
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM base AS production
|
||||||
|
|
||||||
|
# Install production dependencies
|
||||||
|
COPY --from=dependencies /tmp/prod_node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=build /app/dist ./dist
|
||||||
|
COPY --from=build /app/server ./server
|
||||||
|
COPY --from=build /app/shared ./shared
|
||||||
|
COPY --from=build /app/drizzle.config.ts ./
|
||||||
|
COPY --from=build /app/package.json ./
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=5000
|
||||||
|
|
||||||
|
# Expose the application port
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "require('http').get('http://localhost:5000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["node", "server/index.js"]
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# PostgreSQL Database
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: taskflow-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-taskflow}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-taskflow_password}
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-taskflow}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "${POSTGRES_PORT:-5432}:5432"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-taskflow}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- taskflow-network
|
||||||
|
|
||||||
|
# TaskFlow Application
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: production
|
||||||
|
container_name: taskflow-app
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER:-taskflow}:${POSTGRES_PASSWORD:-taskflow_password}@postgres:5432/${POSTGRES_DB:-taskflow}
|
||||||
|
PORT: 5000
|
||||||
|
ports:
|
||||||
|
- "${APP_PORT:-5000}:5000"
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "node", "-e", "require('http').get('http://localhost:5000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
networks:
|
||||||
|
- taskflow-network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
taskflow-network:
|
||||||
|
driver: bridge
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { drizzle } from 'drizzle-orm/neon-http';
|
||||||
|
import { neon } from '@neondatabase/serverless';
|
||||||
|
import * as schema from '@shared/schema';
|
||||||
|
|
||||||
|
let db: ReturnType<typeof drizzle> | null = null;
|
||||||
|
|
||||||
|
export function getDatabase() {
|
||||||
|
if (!db) {
|
||||||
|
const databaseUrl = process.env.DATABASE_URL;
|
||||||
|
|
||||||
|
if (!databaseUrl) {
|
||||||
|
throw new Error('DATABASE_URL environment variable is not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sql = neon(databaseUrl);
|
||||||
|
db = drizzle(sql, { schema });
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initializeDatabase() {
|
||||||
|
try {
|
||||||
|
const database = getDatabase();
|
||||||
|
|
||||||
|
// Create default labels if they don't exist
|
||||||
|
const existingLabels = await database.select().from(schema.labels);
|
||||||
|
|
||||||
|
if (existingLabels.length === 0) {
|
||||||
|
const defaultLabels = [
|
||||||
|
{ name: "Work", color: "#3B82F6" },
|
||||||
|
{ name: "Personal", color: "#10B981" },
|
||||||
|
{ name: "Urgent", color: "#EF4444" },
|
||||||
|
{ name: "Study", color: "#8B5CF6" },
|
||||||
|
];
|
||||||
|
|
||||||
|
await database.insert(schema.labels).values(defaultLabels);
|
||||||
|
console.log('✓ Created default labels');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✓ Database initialized successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to initialize database:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import express, { type Request, Response, NextFunction } from "express";
|
import express, { type Request, Response, NextFunction } from "express";
|
||||||
import { registerRoutes } from "./routes";
|
import { registerRoutes } from "./routes";
|
||||||
import { setupVite, serveStatic, log } from "./vite";
|
import { setupVite, serveStatic, log } from "./vite";
|
||||||
|
import { initializeDatabase } from "./db";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
@@ -37,6 +38,16 @@ app.use((req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
// Initialize database if using production mode or USE_DB is true
|
||||||
|
if (process.env.NODE_ENV === 'production' || process.env.USE_DB === 'true') {
|
||||||
|
try {
|
||||||
|
await initializeDatabase();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to initialize database:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const server = await registerRoutes(app);
|
const server = await registerRoutes(app);
|
||||||
|
|
||||||
app.use((err: any, _req: Request, res: Response, _next: NextFunction) => {
|
app.use((err: any, _req: Request, res: Response, _next: NextFunction) => {
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import { storage } from "./storage";
|
|||||||
import { insertLabelSchema, insertTaskSchema } from "@shared/schema";
|
import { insertLabelSchema, insertTaskSchema } from "@shared/schema";
|
||||||
|
|
||||||
export async function registerRoutes(app: Express): Promise<Server> {
|
export async function registerRoutes(app: Express): Promise<Server> {
|
||||||
|
// Health check endpoint
|
||||||
|
app.get("/api/health", (req, res) => {
|
||||||
|
res.status(200).json({ status: "ok", timestamp: new Date().toISOString() });
|
||||||
|
});
|
||||||
|
|
||||||
// Labels API routes
|
// Labels API routes
|
||||||
app.get("/api/labels", async (req, res) => {
|
app.get("/api/labels", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+83
-1
@@ -140,4 +140,86 @@ export class MemStorage implements IStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storage = new MemStorage();
|
import { getDatabase } from './db';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
import * as schema from '@shared/schema';
|
||||||
|
|
||||||
|
export class DbStorage implements IStorage {
|
||||||
|
private db = getDatabase();
|
||||||
|
|
||||||
|
async getUser(id: string): Promise<User | undefined> {
|
||||||
|
const result = await this.db.select().from(schema.users).where(eq(schema.users.id, id));
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserByUsername(username: string): Promise<User | undefined> {
|
||||||
|
const result = await this.db.select().from(schema.users).where(eq(schema.users.username, username));
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(insertUser: InsertUser): Promise<User> {
|
||||||
|
const result = await this.db.insert(schema.users).values(insertUser).returning();
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllLabels(): Promise<Label[]> {
|
||||||
|
return await this.db.select().from(schema.labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLabel(id: string): Promise<Label | undefined> {
|
||||||
|
const result = await this.db.select().from(schema.labels).where(eq(schema.labels.id, id));
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async createLabel(insertLabel: InsertLabel): Promise<Label> {
|
||||||
|
const result = await this.db.insert(schema.labels).values(insertLabel).returning();
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateLabel(id: string, updates: Partial<InsertLabel>): Promise<Label | undefined> {
|
||||||
|
const result = await this.db
|
||||||
|
.update(schema.labels)
|
||||||
|
.set(updates)
|
||||||
|
.where(eq(schema.labels.id, id))
|
||||||
|
.returning();
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteLabel(id: string): Promise<boolean> {
|
||||||
|
const result = await this.db.delete(schema.labels).where(eq(schema.labels.id, id)).returning();
|
||||||
|
return result.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllTasks(): Promise<Task[]> {
|
||||||
|
return await this.db.select().from(schema.tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTask(id: string): Promise<Task | undefined> {
|
||||||
|
const result = await this.db.select().from(schema.tasks).where(eq(schema.tasks.id, id));
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTask(insertTask: InsertTask): Promise<Task> {
|
||||||
|
const result = await this.db.insert(schema.tasks).values(insertTask).returning();
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTask(id: string, updates: Partial<InsertTask>): Promise<Task | undefined> {
|
||||||
|
const result = await this.db
|
||||||
|
.update(schema.tasks)
|
||||||
|
.set(updates)
|
||||||
|
.where(eq(schema.tasks.id, id))
|
||||||
|
.returning();
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteTask(id: string): Promise<boolean> {
|
||||||
|
const result = await this.db.delete(schema.tasks).where(eq(schema.tasks.id, id)).returning();
|
||||||
|
return result.length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export storage based on environment
|
||||||
|
export const storage = process.env.NODE_ENV === 'production' || process.env.USE_DB === 'true'
|
||||||
|
? new DbStorage()
|
||||||
|
: new MemStorage();
|
||||||
|
|||||||
Reference in New Issue
Block a user