Skip to content

Commit 7b37139

Browse files
committed
feat: add CodeQL SAST, rate limiting, pagination, and architecture diagram
- Add CodeQL workflow for Python and JavaScript/TypeScript security analysis - Add rate limiting with in-memory or Redis backend support - Add PaginatedResponse[T] generic model for consistent pagination - Add mermaid architecture diagram to README files
1 parent d3fc748 commit 7b37139

File tree

6 files changed

+457
-0
lines changed

6 files changed

+457
-0
lines changed

.github/workflows/codeql.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: CodeQL
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
- cron: "0 6 * * 1" # Every Monday at 6 AM UTC
10+
11+
jobs:
12+
analyze:
13+
name: Analyze (${{ matrix.language }})
14+
runs-on: ubuntu-latest
15+
permissions:
16+
security-events: write
17+
packages: read
18+
actions: read
19+
contents: read
20+
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
include:
25+
- language: javascript-typescript
26+
build-mode: none
27+
- language: python
28+
build-mode: none
29+
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v4
33+
34+
- name: Initialize CodeQL
35+
uses: github/codeql-action/init@v3
36+
with:
37+
languages: ${{ matrix.language }}
38+
build-mode: ${{ matrix.build-mode }}
39+
queries: security-extended
40+
41+
- name: Perform CodeQL Analysis
42+
uses: github/codeql-action/analyze@v3
43+
with:
44+
category: "/language:${{ matrix.language }}"

README.ko.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,41 @@
44

55
프로덕션 레디 풀스택 모노레포 템플릿. Next.js 16, FastAPI, Flutter, GCP 인프라를 포함합니다.
66

7+
```mermaid
8+
graph TB
9+
subgraph Client["클라이언트"]
10+
Web[Next.js 16<br/>React 19]
11+
Mobile[Flutter 3.32<br/>Riverpod]
12+
end
13+
14+
subgraph GCP["GCP Cloud Run"]
15+
API[FastAPI<br/>Python 3.13]
16+
Worker[Worker<br/>CloudTasks]
17+
end
18+
19+
subgraph Data["데이터"]
20+
DB[(PostgreSQL 16)]
21+
Cache[(Redis 7)]
22+
Storage[(Cloud Storage)]
23+
end
24+
25+
Web --> API
26+
Mobile --> API
27+
API --> DB
28+
API --> Cache
29+
API --> Worker
30+
Worker --> DB
31+
API --> Storage
32+
33+
style Web fill:#0070f3,color:#fff
34+
style Mobile fill:#02569B,color:#fff
35+
style API fill:#009688,color:#fff
36+
style Worker fill:#009688,color:#fff
37+
style DB fill:#336791,color:#fff
38+
style Cache fill:#DC382D,color:#fff
39+
style Storage fill:#4285F4,color:#fff
40+
```
41+
742
## 주요 기능
843

944
- **모던 스택**: Next.js 16 + React 19, FastAPI, Flutter 3.32, TailwindCSS v4

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,41 @@ English | [한국어](./README.ko.md)
44

55
Production-ready fullstack monorepo template with Next.js 16, FastAPI, Flutter, and GCP infrastructure.
66

7+
```mermaid
8+
graph TB
9+
subgraph Client
10+
Web[Next.js 16<br/>React 19]
11+
Mobile[Flutter 3.32<br/>Riverpod]
12+
end
13+
14+
subgraph GCP["GCP Cloud Run"]
15+
API[FastAPI<br/>Python 3.13]
16+
Worker[Worker<br/>CloudTasks]
17+
end
18+
19+
subgraph Data
20+
DB[(PostgreSQL 16)]
21+
Cache[(Redis 7)]
22+
Storage[(Cloud Storage)]
23+
end
24+
25+
Web --> API
26+
Mobile --> API
27+
API --> DB
28+
API --> Cache
29+
API --> Worker
30+
Worker --> DB
31+
API --> Storage
32+
33+
style Web fill:#0070f3,color:#fff
34+
style Mobile fill:#02569B,color:#fff
35+
style API fill:#009688,color:#fff
36+
style Worker fill:#009688,color:#fff
37+
style DB fill:#336791,color:#fff
38+
style Cache fill:#DC382D,color:#fff
39+
style Storage fill:#4285F4,color:#fff
40+
```
41+
742
## Key Features
843

944
- **Modern Stack**: Next.js 16 + React 19, FastAPI, Flutter 3.32, TailwindCSS v4
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Common models for the API."""
2+
3+
from src.common.models.base import TimestampMixin, UUIDMixin
4+
from src.common.models.pagination import (
5+
PaginatedResponse,
6+
PaginationMeta,
7+
PaginationParams,
8+
)
9+
10+
__all__ = [
11+
"TimestampMixin",
12+
"UUIDMixin",
13+
"PaginatedResponse",
14+
"PaginationMeta",
15+
"PaginationParams",
16+
]
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Pagination models and utilities."""
2+
3+
from typing import Generic, TypeVar
4+
5+
from pydantic import BaseModel, Field
6+
7+
T = TypeVar("T")
8+
9+
10+
class PaginationParams(BaseModel):
11+
"""Query parameters for pagination."""
12+
13+
page: int = Field(default=1, ge=1, description="Page number (1-indexed)")
14+
limit: int = Field(default=20, ge=1, le=100, description="Items per page")
15+
16+
@property
17+
def offset(self) -> int:
18+
"""Calculate offset for database query."""
19+
return (self.page - 1) * self.limit
20+
21+
22+
class PaginationMeta(BaseModel):
23+
"""Pagination metadata."""
24+
25+
page: int = Field(description="Current page number")
26+
limit: int = Field(description="Items per page")
27+
total: int = Field(description="Total number of items")
28+
total_pages: int = Field(description="Total number of pages")
29+
has_next: bool = Field(description="Whether there is a next page")
30+
has_prev: bool = Field(description="Whether there is a previous page")
31+
32+
33+
class PaginatedResponse(BaseModel, Generic[T]):
34+
"""Generic paginated response wrapper."""
35+
36+
data: list[T]
37+
meta: PaginationMeta
38+
39+
@classmethod
40+
def create(
41+
cls,
42+
data: list[T],
43+
total: int,
44+
page: int,
45+
limit: int,
46+
) -> "PaginatedResponse[T]":
47+
"""
48+
Create a paginated response.
49+
50+
Args:
51+
data: List of items for the current page
52+
total: Total number of items across all pages
53+
page: Current page number (1-indexed)
54+
limit: Items per page
55+
56+
Returns:
57+
PaginatedResponse with data and metadata
58+
"""
59+
total_pages = (total + limit - 1) // limit if total > 0 else 0
60+
61+
return cls(
62+
data=data,
63+
meta=PaginationMeta(
64+
page=page,
65+
limit=limit,
66+
total=total,
67+
total_pages=total_pages,
68+
has_next=page < total_pages,
69+
has_prev=page > 1,
70+
),
71+
)

0 commit comments

Comments
 (0)