Merge remote-tracking branch 'gittea/main'

# Conflicts:
#	API/app/infrastructure/teams_service.py
This commit is contained in:
Archibald 2025-06-09 21:45:49 +05:00
commit 49cc307f2c
22 changed files with 293 additions and 4 deletions

4
API/.dockerignore Normal file
View File

@ -0,0 +1,4 @@
.venv
k8s
.idea
.env

3
API/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
k8s/helm/teamfolio-api/templates/secrets.yaml
.venv
*.pyc

18
API/app/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM python:3.10-slim
RUN apt-get update && apt-get install -y \
libpq-dev \
libmagic1 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY req.txt .
RUN pip install --no-cache-dir -r req.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host=0.0.0.0"]

View File

@ -4,7 +4,7 @@ from typing import Optional, Any, Coroutine
import aiofiles
from fastapi import HTTPException, status, UploadFile
from magic import Magic
import magic
from sqlalchemy.ext.asyncio import AsyncSession
from starlette.responses import FileResponse
from werkzeug.utils import secure_filename
@ -152,7 +152,7 @@ class TeamsService:
@staticmethod
def validate_file_type(file: UploadFile):
mime = Magic(mime=True)
mime = magic.Magic(mime=True)
file_type = mime.from_buffer(file.file.read(1024))
file.file.seek(0)

View File

@ -22,7 +22,7 @@ def start_app():
api_app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_origins=["https://api.numerum.team", "https://numerum.team", "http://localhost:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@ -0,0 +1,5 @@
apiVersion: v2
name: teamfolio-api-app
description: Teamfolio API project
version: 0.1.0
appVersion: "1.0"

View File

@ -0,0 +1,40 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Chart.Name }}
template:
metadata:
labels:
app: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
env:
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: teamfolio-api-secret
key: SECRET_KEY
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: teamfolio-api-secret
key: DATABASE_URL
volumeMounts:
- name: uploads-volume
mountPath: {{ .Values.persistence.uploads.containerPath }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumes:
- name: uploads-volume
persistentVolumeClaim:
claimName: "{{ .Release.Name }}-uploads-pvc"

View File

@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: teamfolio-api-ingress
annotations:
cert-manager.io/cluster-issuer: lets-encrypt
spec:
tls:
- hosts:
- {{ .Values.ingress.domain }}
secretName: {{ .Values.ingress.secretTLSName }}
ingressClassName: public
rules:
- host: {{ .Values.ingress.domain }}
http:
paths:
- path: {{ .Values.ingress.path }}
pathType: {{ .Values.ingress.pathType }}
backend:
service:
name: {{ .Chart.Name }}-service
port:
number: {{ .Values.service.port }}

View File

@ -0,0 +1,29 @@
{{- if .Values.persistence.uploads.enabled }}
apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ .Release.Name }}-uploads-pv
spec:
capacity:
storage: {{ .Values.persistence.uploads.size }}
accessModes:
- ReadWriteOnce
storageClassName: microk8s-hostpath
hostPath:
path: {{ .Values.persistence.path }}/uploads
type: DirectoryOrCreate
persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ .Release.Name }}-uploads-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: microk8s-hostpath
resources:
requests:
storage: {{ .Values.persistence.uploads.size }}
volumeName: {{ .Release.Name }}-uploads-pv
{{- end }}

View File

@ -0,0 +1,8 @@
apiVersion: v1
kind: Secret
metadata:
name: teamfolio-api-secret
type: Opaque
data:
SECRET_KEY:
DATABASE_URL:

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}-service
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
selector:
app: {{ .Chart.Name }}

View File

@ -0,0 +1,30 @@
replicaCount: 1
image:
repository: archi341/teamfolio-api
tag: latest
pullPolicy: Always
service:
type: ClusterIP
port: 8000
resources:
limits:
memory: 512Mi
cpu: 500m
persistence:
path: /mnt/k8s_storage/teamfolio-api
uploads:
enabled: true
size: 7Gi
containerPath: /app/uploads
ingress:
secretTLSName: teamfolio-api-tls-secret
domain: api.numerum.team
path: /
pathType: Prefix

Binary file not shown.

7
WEB/.dockerignore Normal file
View File

@ -0,0 +1,7 @@
node_modules
npm-debug.log
build
.dockerignore
.git
k8s
.env

2
WEB/.gitignore vendored
View File

@ -23,3 +23,5 @@ dist-ssr
*.sln
*.sw?
*/.vscode/*
.env

25
WEB/Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
ARG VITE_BASE_URL
ENV VITE_BASE_URL=https://api.numerum.team
RUN npm run build
FROM node:20-alpine
WORKDIR /app
RUN npm install -g serve
COPY --from=builder /app/dist /app
EXPOSE 3000
CMD ["serve", "-s", ".", "-l", "3000"]

View File

@ -0,0 +1,5 @@
apiVersion: v2
name: teamfolio-web-app
description: teamfolio WEB project
version: 0.1.0
appVersion: "1.0"

View File

@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Chart.Name }}
template:
metadata:
labels:
app: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}

View File

@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: visus-api-ingress
annotations:
cert-manager.io/cluster-issuer: lets-encrypt
spec:
tls:
- hosts:
- {{ .Values.ingress.domain }}
secretName: {{ .Values.ingress.secretTLSName }}
ingressClassName: public
rules:
- host: {{ .Values.ingress.domain }}
http:
paths:
- path: {{ .Values.ingress.path }}
pathType: {{ .Values.ingress.pathType }}
backend:
service:
name: {{ .Chart.Name }}-service
port:
number: {{ .Values.service.port }}

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}-service
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
selector:
app: {{ .Chart.Name }}

View File

@ -0,0 +1,23 @@
replicaCount: 1
image:
repository: archi341/teamfolio-web
tag: latest
pullPolicy: Always
service:
type: ClusterIP
port: 3000
resources:
limits:
memory: 512Mi
cpu: 500m
ingress:
secretTLSName: teamfolio-web-tls-secret
domain: numerum.team
path: /
pathType: Prefix

View File

@ -1,5 +1,5 @@
const CONFIG = {
BASE_URL: "http://127.0.0.1:8000",
BASE_URL: import.meta.env.VITE_BASE_URL || "http://127.0.0.1:8000",
};
export default CONFIG;