Skip to content

Commit c76aa3c

Browse files
committed
chore: dockerize app and add CI/security setup
0 parents  commit c76aa3c

157 files changed

Lines changed: 10377 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Docker compose environment
2+
APP_ENV=development
3+
DATABASE_URL=sqlite:////app/data/dev.sqlite3
4+
JWT_SECRET_KEY=replace-with-strong-random-secret-min-32-chars
5+
BIOMETRIC_INGEST_API_KEY=replace-with-strong-random-api-key
6+
7+
DEFAULT_ADMIN_EMAIL=admin@company.com
8+
DEFAULT_ADMIN_PASSWORD=replace-admin-password
9+
DEFAULT_ADMIN_NAME=System Admin
10+
DEFAULT_HR_EMAIL=hr@company.com
11+
DEFAULT_HR_PASSWORD=replace-hr-password
12+
DEFAULT_HR_NAME=HR Manager
13+
14+
CORS_ORIGINS=http://localhost:8080

.github/workflows/ci.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
pull_request:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: ci-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
backend-tests:
19+
name: Backend Tests (Python 3.12)
20+
runs-on: ubuntu-latest
21+
defaults:
22+
run:
23+
working-directory: backend
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Setup Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: "3.12"
33+
cache: pip
34+
cache-dependency-path: backend/requirements.txt
35+
36+
- name: Install backend dependencies
37+
run: |
38+
python -m pip install --upgrade pip
39+
pip install -r requirements.txt
40+
41+
- name: Run backend tests
42+
run: python -m pytest -q
43+
44+
frontend-build:
45+
name: Frontend Build (Bun)
46+
runs-on: ubuntu-latest
47+
defaults:
48+
run:
49+
working-directory: frontend
50+
51+
steps:
52+
- name: Checkout
53+
uses: actions/checkout@v4
54+
55+
- name: Setup Bun
56+
uses: oven-sh/setup-bun@v2
57+
with:
58+
bun-version: "1.2.23"
59+
60+
- name: Install frontend dependencies
61+
run: bun install --frozen-lockfile
62+
63+
- name: Build frontend
64+
run: bun run build

.gitignore

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Python
2+
venv/
3+
__pycache__/
4+
*.pyc
5+
*.pyo
6+
*.pyd
7+
.Python
8+
*.egg-info/
9+
dist/
10+
build/
11+
.env
12+
13+
# FastAPI / Alembic
14+
alembic/versions/*.pyc
15+
16+
# Node / Bun
17+
node_modules/
18+
dist/
19+
.bun
20+
bun.lockb
21+
22+
# Vite
23+
*.local
24+
vite.config.ts.timestamp*
25+
26+
# TypeScript
27+
*.tsbuildinfo
28+
29+
# Environment
30+
.env
31+
.env.local
32+
.env.development
33+
.env.production
34+
35+
# Databases / local state
36+
*.sqlite3
37+
*.db
38+
39+
# Secrets / credentials
40+
*.pem
41+
*.key
42+
*.p12
43+
*.crt
44+
*.secrets
45+
secrets/
46+
47+
# OS
48+
.DS_Store
49+
Thumbs.db
50+
51+
# IDE
52+
.vscode/
53+
.idea/
54+
*.suo
55+
*.ntvs*
56+
*.njsproj
57+
*.sln

DOCKER.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Docker Quick Start
2+
3+
## Prerequisites
4+
- Docker Desktop
5+
6+
## 1) Prepare environment files
7+
- Copy templates and set real values:
8+
- `copy .env.example .env`
9+
- `copy backend\.env.example backend\.env`
10+
- `copy frontend\.env.example frontend\.env`
11+
12+
## 2) Build and run
13+
From project root:
14+
15+
```powershell
16+
docker compose up --build -d
17+
```
18+
19+
## 3) Access apps
20+
- Frontend: `http://localhost:8080`
21+
- Backend API (via frontend proxy): `http://localhost:8080/api/v1`
22+
23+
## 4) Logs and stop
24+
```powershell
25+
docker compose logs -f
26+
docker compose down
27+
```
28+
29+
## Notes
30+
- SQLite data is persisted in Docker volume `backend-data`.
31+
- For production, set `APP_ENV=production` and provide strong non-default secrets/passwords.

SECURITY.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Security and GitHub Commit Checklist
2+
3+
## 1) Environment and secrets
4+
- Never commit real `.env` files.
5+
- Keep only `.env.example` templates in git.
6+
- Generate strong secrets before production use:
7+
- `JWT_SECRET_KEY` at least 32 characters.
8+
- `BIOMETRIC_INGEST_API_KEY` at least 16 characters.
9+
- In production (`APP_ENV=production`), backend startup now rejects weak default secrets/passwords.
10+
11+
## 2) GitHub repository safety
12+
- Ensure repository is private if it contains internal business logic.
13+
- Enable branch protection on `main` (required PR + status checks).
14+
- Enable GitHub Dependabot alerts and secret scanning.
15+
- Add repository secrets (for CI/CD), never plaintext in workflow files.
16+
17+
## 3) Docker runtime safety
18+
- Backend container runs as non-root user.
19+
- Frontend is served by Nginx with API reverse proxy.
20+
- Do not expose backend port publicly unless required by your deployment topology.
21+
- Use HTTPS termination in production (reverse proxy/load balancer).
22+
23+
## 4) Before pushing to remote
24+
1. Verify `git status` has no real credentials.
25+
2. Confirm no local DB dumps or key files are staged.
26+
3. Keep only template values in `.env.example` files.
27+
4. Rotate any secret that may have been previously committed.

backend/.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
venv/
2+
__pycache__/
3+
*.pyc
4+
*.pyo
5+
*.pyd
6+
*.sqlite3
7+
.pytest_cache/
8+
.coverage
9+
.git
10+
.gitignore
11+
.env
12+
.env.*
13+
Dockerfile*

backend/.env.example

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
APP_NAME=HR Management API
2+
APP_ENV=development
3+
APP_PORT=8000
4+
5+
DATABASE_URL=sqlite:///./dev.sqlite3
6+
7+
JWT_SECRET_KEY=replace-with-strong-random-secret-min-32-chars
8+
JWT_ALGORITHM=HS256
9+
JWT_EXPIRE_MINUTES=60
10+
11+
DEFAULT_ADMIN_EMAIL=admin@company.com
12+
DEFAULT_ADMIN_PASSWORD=replace-admin-password
13+
DEFAULT_ADMIN_NAME=System Admin
14+
DEFAULT_HR_EMAIL=hr@company.com
15+
DEFAULT_HR_PASSWORD=replace-hr-password
16+
DEFAULT_HR_NAME=HR Manager
17+
18+
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:8080
19+
BIOMETRIC_INGEST_API_KEY=replace-with-strong-random-api-key

backend/.pytest_all.log

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
........ [100%]
2+
============================== warnings summary ===============================
3+
venv\Lib\site-packages\fastapi\routing.py:234: 43 warnings
4+
C:\Projects\fastreact\backend\venv\Lib\site-packages\fastapi\routing.py:234: DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead
5+
is_coroutine = asyncio.iscoroutinefunction(dependant.call)
6+
7+
app\employees\schemas.py:43
8+
C:\Projects\fastreact\backend\app\employees\schemas.py:43: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/
9+
class EmployeeResponse(EmployeeBase):
10+
11+
app\settings\schemas.py:10
12+
C:\Projects\fastreact\backend\app\settings\schemas.py:10: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/
13+
class DepartmentResponse(BaseModel):
14+
15+
app\settings\schemas.py:28
16+
C:\Projects\fastreact\backend\app\settings\schemas.py:28: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/
17+
class CompanyProfileResponse(BaseModel):
18+
19+
app\main.py:40
20+
C:\Projects\fastreact\backend\app\main.py:40: DeprecationWarning:
21+
on_event is deprecated, use lifespan event handlers instead.
22+
23+
Read more about it in the
24+
[FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
25+
26+
@app.on_event("startup")
27+
28+
venv\Lib\site-packages\fastapi\applications.py:4495
29+
C:\Projects\fastreact\backend\venv\Lib\site-packages\fastapi\applications.py:4495: DeprecationWarning:
30+
on_event is deprecated, use lifespan event handlers instead.
31+
32+
Read more about it in the
33+
[FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
34+
35+
return self.router.on_event(event_type)
36+
37+
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
38+
8 passed, 48 warnings in 2.42s

backend/.pytest_employee_seed.log

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
. [100%]
2+
============================== warnings summary ===============================
3+
venv\Lib\site-packages\fastapi\routing.py:234: 43 warnings
4+
C:\Projects\fastreact\backend\venv\Lib\site-packages\fastapi\routing.py:234: DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead
5+
is_coroutine = asyncio.iscoroutinefunction(dependant.call)
6+
7+
app\employees\schemas.py:43
8+
C:\Projects\fastreact\backend\app\employees\schemas.py:43: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/
9+
class EmployeeResponse(EmployeeBase):
10+
11+
app\settings\schemas.py:10
12+
C:\Projects\fastreact\backend\app\settings\schemas.py:10: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/
13+
class DepartmentResponse(BaseModel):
14+
15+
app\settings\schemas.py:28
16+
C:\Projects\fastreact\backend\app\settings\schemas.py:28: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/
17+
class CompanyProfileResponse(BaseModel):
18+
19+
app\main.py:40
20+
C:\Projects\fastreact\backend\app\main.py:40: DeprecationWarning:
21+
on_event is deprecated, use lifespan event handlers instead.
22+
23+
Read more about it in the
24+
[FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
25+
26+
@app.on_event("startup")
27+
28+
venv\Lib\site-packages\fastapi\applications.py:4495
29+
C:\Projects\fastreact\backend\venv\Lib\site-packages\fastapi\applications.py:4495: DeprecationWarning:
30+
on_event is deprecated, use lifespan event handlers instead.
31+
32+
Read more about it in the
33+
[FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
34+
35+
return self.router.on_event(event_type)
36+
37+
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
38+
1 passed, 48 warnings in 0.30s

backend/Dockerfile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
FROM python:3.12-slim
2+
3+
ENV PYTHONDONTWRITEBYTECODE=1 \
4+
PYTHONUNBUFFERED=1
5+
6+
WORKDIR /app
7+
8+
RUN apt-get update \
9+
; apt-get install -y --no-install-recommends build-essential \
10+
; rm -rf /var/lib/apt/lists/*
11+
12+
COPY requirements.txt ./
13+
RUN pip install --no-cache-dir --upgrade pip \
14+
&& pip install --no-cache-dir -r requirements.txt
15+
16+
COPY app ./app
17+
COPY alembic ./alembic
18+
COPY alembic.ini ./alembic.ini
19+
20+
RUN useradd --create-home --shell /usr/sbin/nologin appuser \
21+
&& chown -R appuser:appuser /app
22+
USER appuser
23+
24+
EXPOSE 8000
25+
26+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

0 commit comments

Comments
 (0)