Add tasko

This commit is contained in:
dvirlabs 2025-12-11 03:57:16 +02:00
parent 9bd13a324a
commit bc173e7ab7
4 changed files with 212 additions and 102 deletions

View File

@ -0,0 +1,95 @@
{{- if .Values.postgres }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "tasko.fullname" . }}-db-schema
labels:
{{- include "tasko.labels" . | nindent 4 }}
app.kubernetes.io/component: database
data:
schema.sql: |
-- Create users table
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
first_name TEXT,
last_name TEXT,
display_name TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_users_username ON users (username);
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
CREATE INDEX IF NOT EXISTS idx_users_display_name ON users (display_name);
-- Create tasks table
CREATE TABLE IF NOT EXISTS tasks (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT,
status TEXT NOT NULL DEFAULT 'pending', -- pending / in_progress / completed / cancelled
priority TEXT DEFAULT 'medium', -- low / medium / high / urgent
due_date TIMESTAMP,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
assigned_to INTEGER REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP
);
-- Indexes for tasks
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks (status);
CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks (priority);
CREATE INDEX IF NOT EXISTS idx_tasks_user_id ON tasks (user_id);
CREATE INDEX IF NOT EXISTS idx_tasks_assigned_to ON tasks (assigned_to);
CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks (due_date);
-- Create tags table
CREATE TABLE IF NOT EXISTS tags (
id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
color TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create task_tags junction table
CREATE TABLE IF NOT EXISTS task_tags (
task_id INTEGER REFERENCES tasks(id) ON DELETE CASCADE,
tag_id INTEGER REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (task_id, tag_id)
);
CREATE INDEX IF NOT EXISTS idx_task_tags_task_id ON task_tags (task_id);
CREATE INDEX IF NOT EXISTS idx_task_tags_tag_id ON task_tags (tag_id);
-- Add display_name column if it doesn't exist (migration support)
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'display_name'
) THEN
ALTER TABLE users ADD COLUMN display_name TEXT;
-- Set display_name to username for existing users
UPDATE users SET display_name = username WHERE display_name IS NULL;
ALTER TABLE users ALTER COLUMN display_name SET NOT NULL;
ALTER TABLE users ADD CONSTRAINT users_display_name_key UNIQUE (display_name);
END IF;
END $$;
-- Verify schema
SELECT 'Users table:' as info;
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'users'
ORDER BY ordinal_position;
SELECT 'Tasks table:' as info;
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'tasks'
ORDER BY ordinal_position;
{{- end }}

View File

@ -39,6 +39,8 @@ spec:
volumeMounts: volumeMounts:
- name: data - name: data
mountPath: /var/lib/postgresql/data mountPath: /var/lib/postgresql/data
- name: init-sql
mountPath: /docker-entrypoint-initdb.d
livenessProbe: livenessProbe:
exec: exec:
command: command:
@ -66,6 +68,10 @@ spec:
limits: limits:
cpu: {{ .Values.postgres.resources.limits.cpu }} cpu: {{ .Values.postgres.resources.limits.cpu }}
memory: {{ .Values.postgres.resources.limits.memory }} memory: {{ .Values.postgres.resources.limits.memory }}
volumes:
- name: init-sql
configMap:
name: {{ include "tasko.fullname" . }}-db-schema
volumeClaimTemplates: volumeClaimTemplates:
- metadata: - metadata:
name: data name: data

View File

@ -1,47 +1,13 @@
replicaCount: 1 global:
namespace: my-apps
frontend: imagePullSecrets: []
image:
repository: tasko-frontend
pullPolicy: IfNotPresent
tag: "latest"
service:
type: ClusterIP
port: 80
targetPort: 80
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
hosts:
- host: tasko.dvirlabs.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: tasko-frontend-tls
hosts:
- tasko.dvirlabs.com
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
env:
- name: VITE_API_URL
value: "https://api-tasko.dvirlabs.com"
# Backend configuration
backend: backend:
name: backend
replicaCount: 1
image: image:
repository: tasko-backend repository: harbor.dvirlabs.com/my-apps/tasko-backend
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
tag: "latest" tag: "latest"
@ -50,76 +16,121 @@ backend:
port: 8000 port: 8000
targetPort: 8000 targetPort: 8000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
env:
PYTHONUNBUFFERED: "1"
ingress: ingress:
enabled: true enabled: true
className: "nginx" className: "traefik"
annotations: annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod" cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://tasko.dvirlabs.com"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
hosts: hosts:
- host: api-tasko.dvirlabs.com - host: api-tasko.dvirlabs.com
paths: paths:
- path: / - path: /
pathType: Prefix pathType: Prefix
tls: tls:
- secretName: tasko-backend-tls - secretName: api-tasko-tls
hosts: hosts:
- api-tasko.dvirlabs.com - api-tasko.dvirlabs.com
# Frontend configuration
frontend:
name: frontend
replicaCount: 1
image:
repository: harbor.dvirlabs.com/my-apps/tasko-frontend
pullPolicy: IfNotPresent
tag: "latest"
resources: service:
limits: type: ClusterIP
cpu: 500m port: 80
memory: 512Mi targetPort: 80
requests:
cpu: 250m
memory: 256Mi
env: env:
- name: DATABASE_URL VITE_API_URL: "https://api-tasko.dvirlabs.com"
valueFrom:
secretKeyRef: resources:
name: tasko-secrets requests:
key: database-url cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
postgresql: ingress:
enabled: true enabled: true
auth: className: "traefik"
username: tasko_user annotations:
password: tasko_password traefik.ingress.kubernetes.io/router.entrypoints: websecure
database: tasko_db traefik.ingress.kubernetes.io/router.tls: "true"
primary: cert-manager.io/cluster-issuer: "letsencrypt-prod"
persistence: hosts:
enabled: true - host: tasko.dvirlabs.com
size: 8Gi paths:
resources: - path: /
limits: pathType: Prefix
cpu: 500m tls:
memory: 512Mi - secretName: tasko-tls
requests: hosts:
cpu: 250m - tasko.dvirlabs.com
memory: 256Mi
imagePullSecrets: [] # PostgreSQL configuration
nameOverride: "" postgres:
fullnameOverride: "" name: db
image:
repository: postgres
tag: "16-alpine"
pullPolicy: IfNotPresent
user: tasko_user
password: tasko_password
database: tasko_db
port: 5432
service:
type: ClusterIP
port: 5432
targetPort: 5432
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: "nfs-client"
size: 10Gi
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
serviceAccount: # Ingress configuration
create: true ingress:
annotations: {} enabled: false # Individual frontend/backend ingress resources handle routing instead
name: "" className: "traefik"
annotations:
podAnnotations: {} cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
podSecurityContext: {} - host: tasko.dvirlabs.com
paths:
securityContext: {} - path: /
pathType: Prefix
nodeSelector: {} backend: frontend
tls:
tolerations: [] - secretName: tasko-tls
hosts:
affinity: {} - tasko.dvirlabs.com

View File

@ -12,8 +12,8 @@ backend:
service: service:
type: ClusterIP type: ClusterIP
port: 8001 port: 8000
targetPort: 8001 targetPort: 8000
resources: resources:
requests: requests:
cpu: 100m cpu: 100m
@ -22,8 +22,7 @@ backend:
cpu: 500m cpu: 500m
memory: 512Mi memory: 512Mi
env: env:
- name: PYTHONUNBUFFERED PYTHONUNBUFFERED: "1"
value: "1"
ingress: ingress:
enabled: true enabled: true
className: "traefik" className: "traefik"
@ -54,8 +53,7 @@ frontend:
port: 80 port: 80
targetPort: 80 targetPort: 80
env: env:
- name: VITE_API_URL VITE_API_URL: "https://api-tasko.dvirlabs.com"
value: "https://api-tasko.dvirlabs.com"
resources: resources:
requests: requests:
cpu: 50m cpu: 50m