chore: remove unused configuration files and submodules
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"image": "mcr.microsoft.com/devcontainers/universal:2",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/rust:1": {},
|
||||
"ghcr.io/devcontainers/features/node:2": {}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
git fetch origin main --depth=1 || true
|
||||
|
||||
# Detect changed files before resetting
|
||||
ALL_COMPOSE_FILES="infra/compose/traefik.yml infra/compose/shared.yml infra/compose/scraper.yml infra/compose/elysia.yml infra/compose/react.yml infra/compose/rust-auth.yml"
|
||||
ALL_COMPOSE_FILES="infra/compose/traefik.yml infra/compose/shared.yml infra/compose/scraper.yml"
|
||||
TRAEFIK_DYNAMIC_DIR="infra/traefik/dynamic"
|
||||
|
||||
if git rev-parse HEAD >/dev/null 2>&1; then
|
||||
|
||||
@@ -5,7 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'apps/**'
|
||||
- 'apps/scraper/**'
|
||||
- '.github/workflows/docker-build-push.yml'
|
||||
- 'infra/**'
|
||||
- '!infra/compose/**'
|
||||
@@ -34,9 +34,6 @@ jobs:
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
scraper-api: ${{ steps.filter.outputs['scraper-api'] == 'true' || steps.dispatch.outputs['scraper-api'] == 'true' || github.event_name == 'workflow_dispatch' }}
|
||||
elysia-api: ${{ steps.filter.outputs['elysia-api'] == 'true' || steps.dispatch.outputs['elysia-api'] == 'true' || github.event_name == 'workflow_dispatch' }}
|
||||
react-web: ${{ steps.filter.outputs['react-web'] == 'true' || steps.dispatch.outputs['react-web'] == 'true' || github.event_name == 'workflow_dispatch' }}
|
||||
rust-auth: ${{ steps.filter.outputs['rust-auth'] == 'true' || steps.dispatch.outputs['rust-auth'] == 'true' || github.event_name == 'workflow_dispatch' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
@@ -63,9 +60,6 @@ jobs:
|
||||
}
|
||||
|
||||
echo "scraper-api=$(changed '^(apps/scraper(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/scraper\.Dockerfile$)')" >> "$GITHUB_OUTPUT"
|
||||
echo "elysia-api=$(changed '^(apps/elysia(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/elysia\.Dockerfile$)')" >> "$GITHUB_OUTPUT"
|
||||
echo "react-web=$(changed '^(apps/react(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/react\.Dockerfile$)')" >> "$GITHUB_OUTPUT"
|
||||
echo "rust-auth=$(changed '^(apps/rust-auth(/|$)|infra/docker/rust\.Dockerfile$|\.github/workflows/docker-build-push\.yml$|\.gitmodules$)')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Parse repository_dispatch payload
|
||||
id: dispatch
|
||||
@@ -87,7 +81,7 @@ jobs:
|
||||
fi
|
||||
|
||||
case "$SERVICE" in
|
||||
scraper-api|elysia-api|react-web|rust-auth) ;;
|
||||
scraper-api) ;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
@@ -95,7 +89,7 @@ jobs:
|
||||
|
||||
if ! [[ "$SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then echo "::error::Invalid sha '$SHA'. Expected 40 hex characters"; exit 1; fi
|
||||
|
||||
SERVICES=(scraper-api elysia-api react-web rust-auth)
|
||||
SERVICES=(scraper-api)
|
||||
for svc in "${SERVICES[@]}"; do
|
||||
if [ "$SERVICE" = "$svc" ]; then
|
||||
echo "${svc}=true" >> "$GITHUB_OUTPUT"
|
||||
@@ -113,9 +107,6 @@ jobs:
|
||||
}
|
||||
|
||||
if [ "${{ steps.filter.outputs['scraper-api'] == 'true' || steps.dispatch.outputs['scraper-api'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "scraper-api" "docker-scraper" "apps/scraper"; fi
|
||||
if [ "${{ steps.filter.outputs['elysia-api'] == 'true' || steps.dispatch.outputs['elysia-api'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "elysia-api" "docker-elysia" "apps/elysia"; fi
|
||||
if [ "${{ steps.filter.outputs['react-web'] == 'true' || steps.dispatch.outputs['react-web'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "react-web" "docker-react" "apps/react"; fi
|
||||
if [ "${{ steps.filter.outputs['rust-auth'] == 'true' || steps.dispatch.outputs['rust-auth'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "rust-auth" "docker-rust-auth" "apps/rust-auth"; fi
|
||||
|
||||
JSON_ARRAY="[$(IFS=,; echo "${SERVICES[*]}")]"
|
||||
echo "matrix=$JSON_ARRAY" >> $GITHUB_OUTPUT
|
||||
@@ -135,9 +126,6 @@ jobs:
|
||||
|
||||
case "$SERVICE" in
|
||||
"scraper-api") REPO="https://github.com/asepharyana/asepharyana-hub-scraper.git" ;;
|
||||
"elysia-api") REPO="https://github.com/asepharyana/asepharyana-hub-elysia.git" ;;
|
||||
"react-web") REPO="https://github.com/asepharyana/asepharyana-hub-react.git" ;;
|
||||
"rust-auth") REPO="https://github.com/asepharyana/asepharyana-hub-rust-auth.git" ;;
|
||||
*)
|
||||
echo "::error::Unsupported service '$SERVICE'"
|
||||
exit 1
|
||||
@@ -219,9 +207,6 @@ jobs:
|
||||
echo "cache-registry=${REGISTRY}/${IMAGE_NAME_PREFIX}/${SVC_NAME}:buildcache" >> $GITHUB_OUTPUT
|
||||
case "$SVC_NAME" in
|
||||
"scraper-api") echo "dockerfile=infra/docker/scraper.Dockerfile" >> $GITHUB_OUTPUT ;;
|
||||
"elysia-api") echo "dockerfile=infra/docker/elysia.Dockerfile" >> $GITHUB_OUTPUT ;;
|
||||
"react-web") echo "dockerfile=infra/docker/react.Dockerfile" >> $GITHUB_OUTPUT ;;
|
||||
"rust-auth") echo "dockerfile=infra/docker/rust.Dockerfile" >> $GITHUB_OUTPUT ;;
|
||||
esac
|
||||
|
||||
- name: Build and Push Docker image
|
||||
@@ -266,15 +251,9 @@ jobs:
|
||||
|
||||
declare -A SERVICES
|
||||
SERVICES["scraper-api"]="scraper.yml"
|
||||
SERVICES["elysia-api"]="elysia.yml"
|
||||
SERVICES["react-web"]="react.yml"
|
||||
SERVICES["rust-auth"]="rust-auth.yml"
|
||||
|
||||
declare -A PATHS
|
||||
PATHS["scraper-api"]="apps/scraper"
|
||||
PATHS["elysia-api"]="apps/elysia"
|
||||
PATHS["react-web"]="apps/react"
|
||||
PATHS["rust-auth"]="apps/rust-auth"
|
||||
|
||||
# Use git config for possible commits
|
||||
git config --local user.email "action@github.com"
|
||||
@@ -283,9 +262,6 @@ jobs:
|
||||
for id in "${!SERVICES[@]}"; do
|
||||
SHOULD_HAVE_RUN=false
|
||||
if [ "${{ needs.changes.outputs['scraper-api'] }}" == "true" ] && [ "$id" == "scraper-api" ]; then SHOULD_HAVE_RUN=true; fi
|
||||
if [ "${{ needs.changes.outputs['elysia-api'] }}" == "true" ] && [ "$id" == "elysia-api" ]; then SHOULD_HAVE_RUN=true; fi
|
||||
if [ "${{ needs.changes.outputs['react-web'] }}" == "true" ] && [ "$id" == "react-web" ]; then SHOULD_HAVE_RUN=true; fi
|
||||
if [ "${{ needs.changes.outputs['rust-auth'] }}" == "true" ] && [ "$id" == "rust-auth" ]; then SHOULD_HAVE_RUN=true; fi
|
||||
|
||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then SHOULD_HAVE_RUN=true; fi
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
name: TypeCheck
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'apps/react/src/**/*.ts'
|
||||
- 'apps/react/src/**/*.tsx'
|
||||
- 'apps/elysia/src/**/*.ts'
|
||||
- 'apps/elysia/tsconfig.json'
|
||||
- 'tsconfig.base.json'
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: oven/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: TypeCheck apps/react
|
||||
working-directory: apps/react
|
||||
run: |
|
||||
bun install
|
||||
npx tsc --noEmit
|
||||
|
||||
- name: TypeCheck apps/elysia
|
||||
working-directory: apps/elysia
|
||||
run: |
|
||||
bun install
|
||||
bun run typecheck
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
fi
|
||||
|
||||
case "$SERVICE" in
|
||||
scraper-api|elysia-api|react-web|rust-auth) ;;
|
||||
scraper-api) ;;
|
||||
*)
|
||||
echo "::error::Unsupported service '$SERVICE'"
|
||||
exit 1
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
[submodule "apps/elysia"]
|
||||
path = apps/elysia
|
||||
url = https://github.com/asepharyana/asepharyana-hub-elysia.git
|
||||
[submodule "apps/react"]
|
||||
path = apps/react
|
||||
url = https://github.com/asepharyana/asepharyana-hub-react.git
|
||||
[submodule "apps/scraper"]
|
||||
path = apps/scraper
|
||||
url = https://github.com/asepharyana/asepharyana-hub-scraper.git
|
||||
[submodule "apps/rust-auth"]
|
||||
path = apps/rust-auth
|
||||
url = https://github.com/asepharyana/asepharyana-hub-rust-auth.git
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"next-devtools": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "next-devtools-mcp@latest"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
# Agent Protocol v10: Strategic Execution and Diagnostic Directives
|
||||
|
||||
1. **Mandatory Executability.**
|
||||
- **Directive:** All generated outputs must be syntactically correct and directly executable by the target system's interpreter, compiler, or shell.
|
||||
- **Constraint:** Placeholders and pseudo-code are forbidden. Every output must be a complete, functional artifact.
|
||||
|
||||
2. **Data and State Integrity.**
|
||||
- **Directive:** All generated code must strictly adhere to declared data structures, schemas, and the target language's type system.
|
||||
- **Constraint:** Any operation producing a type mismatch, schema violation, or logical inconsistency is an invalid operation and must be discarded.
|
||||
|
||||
3. **Atomic and Consistent State Modification.**
|
||||
- **Directive:** Modification of a shared resource must be performed as an atomic operation or within an ACID-compliant transaction.
|
||||
- **Constraint:** Operations that can lead to race conditions or inconsistent state are prohibited. Immutability is the required default.
|
||||
|
||||
4. **Zero-Trust Security (Inviolable Safety Constraint).**
|
||||
- **Directive:** Secrets must not be stored as literal values in source code. They must be loaded at runtime from a secure external source.
|
||||
- **Constraint:** Generated access policies must adhere to the Principle of Least Privilege.
|
||||
|
||||
5. **Supply Chain Security (Inviolable Safety Constraint).**
|
||||
- **Directive:** All external dependencies must be sourced from trusted repositories and defined in a lockfile for deterministic resolution.
|
||||
- **Constraint:** The dependency graph must be scanned for known CVEs. Dependencies with critical vulnerabilities are prohibited.
|
||||
|
||||
6. **Deterministic and Reproducible Builds.**
|
||||
- **Directive:** From a given source commit, the build process must produce a byte-for-byte identical artifact in every execution.
|
||||
- **Constraint:** All automated tests must be deterministic. A regression test codifying the fixed bug's failure condition must be included with the fix.
|
||||
|
||||
7. **Structured, Traceable Logging.**
|
||||
- **Directive:** All processes must emit structured (JSON) logs for significant events. All log entries for a request must contain the same unique trace ID.
|
||||
- **Constraint:** Error conditions must be explicitly logged with context and propagated. Errors must not be silently suppressed.
|
||||
|
||||
8. **Strict API Contract Enforcement.**
|
||||
- **Directive:** All network communication must strictly conform to its published, versioned API contract.
|
||||
- **Constraint:** Any network call violating the contract must be rejected. Breaking changes require a major version increment (SemVer).
|
||||
|
||||
9. **Distributed System Consensus.**
|
||||
- **Directive:** Changes to shared state across a distributed system are committed only after a formal consensus algorithm confirms quorum.
|
||||
- **Constraint:** Nodes in a minority partition must enter a read-only or unavailable state to prevent a split-brain scenario.
|
||||
|
||||
10. **Execution Planning and Pre-flight Validation (Think Before Acting).**
|
||||
- **Directive:** For any multi-step task, a detailed execution plan (sequence of commands and file modifications) must be formulated before any state-modifying action is taken.
|
||||
- **Constraint:** Before executing a command, the agent must first use a validation or dry-run flag (e.g., `--dry-run`, `--check`) if available. The operation may only proceed if the pre-flight check passes without error.
|
||||
|
||||
11. **Post-Failure Root Cause Analysis (Evaluate Mistakes from Logs).**
|
||||
- **Directive:** Upon command execution failure (non-zero exit code), the current execution plan must be halted, and the agent must enter a diagnostic mode.
|
||||
- **Constraint:** In diagnostic mode, the agent is required to: 1) Capture and parse the complete `stdout` and `stderr` logs. 2) Identify the specific error message or stack trace. 3) Correlate the error with the last command to form a root cause hypothesis. 4) Formulate a new, corrective execution plan based on the analysis.
|
||||
|
||||
12. **Context-Aware File System Operations.**
|
||||
- **Directive:** Before modifying any file, its full content must be read to establish context. All edits must be based on an in-memory understanding of the file's current state.
|
||||
- **Constraint:** Blind file operations, such as stream-based search-and-replace without structural validation, are strictly prohibited.
|
||||
|
||||
13. **Idempotent State Transitions.**
|
||||
- **Directive:** Operations that modify state must be designed to be idempotent wherever the protocol allows.
|
||||
- **Constraint:** Executing the same operation multiple times must result in the same final system state as executing it only once.
|
||||
|
||||
14. **Resource Lifecycle Management.**
|
||||
- **Directive:** All finite system resources (e.g., file handles, network sockets) must be explicitly released after use.
|
||||
- **Constraint:** The agent must generate code that prevents resource leaks, utilizing language-specific constructs like `try-with-resources` or `defer`.
|
||||
|
||||
15. **Configuration as Code (CaC).**
|
||||
- **Directive:** All configuration must be defined and versioned in source-controlled files.
|
||||
- **Constraint:** Manual, out-of-band configuration changes are prohibited. Versioned files are the single source of truth.
|
||||
|
||||
16. **Atomic and Semantic Version Control.**
|
||||
- **Directive:** All code changes must be organized into logically atomic commits representing one complete unit of work.
|
||||
- **Constraint:** Commit messages must adhere to a defined specification (e.g., Conventional Commits).
|
||||
|
||||
17. **User Authority and Command Primacy.**
|
||||
- **Directive:** User-provided instructions and corrections are the definitive source of truth and have the highest operational priority.
|
||||
- **Constraint:** The agent must immediately adapt its process to align with user directives. Rejected solutions must not be proposed again.
|
||||
|
||||
18. **Precedent-Based Improvement.**
|
||||
- **Directive:** User-approved outputs and successful patterns must be recorded and prioritized as precedents for subsequent tasks.
|
||||
- **Constraint:** Performance, security, and code quality must not degrade.
|
||||
|
||||
19. **Optimization by Explicit Consent.**
|
||||
- **Directive:** The agent may identify and propose optimizations with a technical justification and supporting metrics.
|
||||
- **Constraint:** The agent is prohibited from applying any self-initiated optimization without an explicit "approve" command from the user.
|
||||
|
||||
20. **System Hierarchy and Safety Overrides.**
|
||||
- **Directive:** The operational control hierarchy is absolute: 1) **User Command**, 2) **Inviolable Safety Directives (#4, #5)**, 3) **Standard Operational Directives**.
|
||||
- **Constraint:** If a command conflicts with an Inviolable Directive, the agent must halt, report the conflict and risk, and await a revised command.
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nrwl.angular-console",
|
||||
"biomejs.biome",
|
||||
"ms-playwright.playwright",
|
||||
"firsttris.vscode-jest-runner"
|
||||
]
|
||||
}
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit"
|
||||
}
|
||||
}
|
||||
+5
-16
@@ -5,9 +5,6 @@
|
||||
```
|
||||
asepharyana-hub/
|
||||
├── apps/ # Application services (Git submodules)
|
||||
│ ├── elysia/ # Realtime API (Bun/Elysia/Drizzle/Redis)
|
||||
│ ├── react/ # Frontend SPA (React/Vite/TanStack)
|
||||
│ ├── rust-auth/ # IAM & auth service (Axum/SeaORM)
|
||||
│ └── scraper/ # Web scraper service
|
||||
├── docs/ # Documentation
|
||||
│ ├── adr/ # Architecture Decision Records
|
||||
@@ -31,19 +28,11 @@ asepharyana-hub/
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Backend Services
|
||||
### Services
|
||||
|
||||
| Service | Language/Runtime | Framework | Database | Key Libraries |
|
||||
| ------------- | ---------------- | ---------- | ------------------------ | ------------------------------------------------------------ |
|
||||
| **rust-auth** | Rust | Axum 0.8 | PostgreSQL (sqlx) | sqlx, jsonwebtoken, argon2, redis, opentelemetry, prometheus |
|
||||
| **elysia** | TypeScript/Bun | Elysia 1.4 | PostgreSQL (Drizzle ORM) | Drizzle ORM, Redis (ioredis), JWT (jose), OTel, Swagger |
|
||||
| **scraper** | _(submodule)_ | — | — | — |
|
||||
|
||||
### Frontend
|
||||
|
||||
| Service | Framework | Build Tool | Key Libraries |
|
||||
| --------- | --------- | ---------- | --------------------------------------------------------------------------------------------------- |
|
||||
| **react** | React 19 | Vite 7 | TanStack Router + Query, Three.js/React Three Fiber, Tailwind CSS 4, Zustand, Recharts, tsParticles |
|
||||
| Service | Language/Runtime | Framework | Database | Key Libraries |
|
||||
| --------- | ---------------- | --------- | -------- | ------------- |
|
||||
| **scraper** | _(submodule)_ | — | — | — |
|
||||
|
||||
### Infrastructure
|
||||
|
||||
@@ -90,7 +79,7 @@ Shared services:
|
||||
Service compose files are combined during deployment:
|
||||
|
||||
```bash
|
||||
docker compose -f traefik.yml -f shared.yml -f elysia.yml -f react.yml ... up -d
|
||||
docker compose -f traefik.yml -f shared.yml -f scraper.yml up -d
|
||||
```
|
||||
|
||||
### Tailscale Networking
|
||||
|
||||
-1
Submodule apps/elysia deleted from b8f4b5806e
-1
Submodule apps/react deleted from 124d2f88bd
Submodule apps/rust-auth deleted from 6e695f07e8
+1
-8
@@ -9,10 +9,7 @@ infra/
|
||||
├── compose/ # One compose file per stack/service
|
||||
│ ├── traefik.yml # Public reverse proxy
|
||||
│ ├── shared.yml # Shared Redis
|
||||
│ ├── react.yml # React SPA
|
||||
│ ├── scraper.yml # Scraper API
|
||||
│ ├── elysia.yml # Elysia API
|
||||
│ └── rust-auth.yml # Rust auth API
|
||||
│ └── scraper.yml # Scraper API
|
||||
├── docker/ # Dockerfiles and image runtime helpers
|
||||
├── traefik/ # Static and dynamic Traefik configuration
|
||||
│ ├── dynamic/ # Routers, services, middlewares, TLS certs
|
||||
@@ -41,10 +38,7 @@ docker compose -f infra/compose/shared.yml up -d
|
||||
docker compose -f infra/compose/traefik.yml up -d
|
||||
|
||||
docker compose \
|
||||
-f infra/compose/react.yml \
|
||||
-f infra/compose/scraper.yml \
|
||||
-f infra/compose/elysia.yml \
|
||||
-f infra/compose/rust-auth.yml \
|
||||
up -d
|
||||
```
|
||||
|
||||
@@ -55,7 +49,6 @@ Common variables used by infra compose files:
|
||||
```env
|
||||
DATABASE_URL=
|
||||
GITHUB_TOKEN=
|
||||
JWT_SECRET=
|
||||
SHARED_REDIS_EXPOSE=127.0.0.1:6379:6379
|
||||
```
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
services:
|
||||
elysia-api:
|
||||
container_name: elysia-api
|
||||
image: ghcr.io/asepharyana/asepharyana-hub/elysia-api:sha-fe998aa
|
||||
restart: always
|
||||
networks:
|
||||
app-shared-net:
|
||||
aliases:
|
||||
- elysia-api
|
||||
env_file:
|
||||
- ../../.env
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- GITHUB_TOKEN=${GITHUB_TOKEN}
|
||||
- PORT=4092
|
||||
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otlp-metrics-backend:4317
|
||||
- OTEL_SERVICE_NAME=elysia-api
|
||||
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
external: true
|
||||
@@ -1,13 +0,0 @@
|
||||
services:
|
||||
react-web:
|
||||
container_name: react-web
|
||||
image: ghcr.io/asepharyana/asepharyana-hub/react-web:sha-124223c
|
||||
restart: always
|
||||
networks: [app-shared-net]
|
||||
environment:
|
||||
- VITE_API_URL=https://scraper.asepharyana.my.id/api
|
||||
- VITE_ELYSIA_URL=https://elysia.asepharyana.my.id
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
external: true
|
||||
@@ -1,20 +0,0 @@
|
||||
services:
|
||||
rust-auth:
|
||||
container_name: rust-auth-api
|
||||
image: ghcr.io/asepharyana/asepharyana-hub/rust-auth:sha-b199f8c
|
||||
restart: always
|
||||
networks:
|
||||
app-shared-net:
|
||||
aliases:
|
||||
- rust-auth
|
||||
env_file:
|
||||
- ../../.env
|
||||
environment:
|
||||
- PORT=3000
|
||||
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otlp-metrics-backend:4317
|
||||
- OTEL_SERVICE_NAME=rust-auth
|
||||
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
external: true
|
||||
@@ -1,26 +0,0 @@
|
||||
# build stage
|
||||
FROM oven/bun:1-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# install dependencies with cache mounts
|
||||
COPY apps/elysia/package.json apps/elysia/bun.lock ./
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile
|
||||
|
||||
# build the application
|
||||
COPY apps/elysia ./
|
||||
RUN bun run build
|
||||
|
||||
# runtime stage
|
||||
FROM oven/bun:1-distroless
|
||||
WORKDIR /app
|
||||
|
||||
# copy build artifacts
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/package.json ./
|
||||
|
||||
# distroless uses nonroot user (UID 65532) by default, or we can use it
|
||||
USER nonroot
|
||||
|
||||
EXPOSE 4092
|
||||
CMD ["run", "dist/index.js"]
|
||||
Vendored
-77
@@ -1,77 +0,0 @@
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { resolve, sep } from 'node:path';
|
||||
|
||||
const distDir = resolve('./dist');
|
||||
const indexPath = resolve(distDir, 'index.html');
|
||||
|
||||
const contentTypes = {
|
||||
html: 'text/html; charset=utf-8',
|
||||
css: 'text/css; charset=utf-8',
|
||||
js: 'application/javascript; charset=utf-8',
|
||||
json: 'application/json; charset=utf-8',
|
||||
svg: 'image/svg+xml',
|
||||
png: 'image/png',
|
||||
jpg: 'image/jpeg',
|
||||
jpeg: 'image/jpeg',
|
||||
gif: 'image/gif',
|
||||
webp: 'image/webp',
|
||||
ico: 'image/x-icon',
|
||||
woff: 'font/woff',
|
||||
woff2: 'font/woff2',
|
||||
ttf: 'font/ttf',
|
||||
};
|
||||
|
||||
function responseFromFile(filePath, headers) {
|
||||
try {
|
||||
return new Response(readFileSync(filePath), { headers });
|
||||
} catch (error) {
|
||||
if (error?.code === 'ENOENT') {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
console.error('File read error:', error);
|
||||
return new Response('Internal Server Error', { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
function serveIndex() {
|
||||
return responseFromFile(indexPath, {
|
||||
'Content-Type': contentTypes.html,
|
||||
'Cache-Control': 'no-cache',
|
||||
});
|
||||
}
|
||||
|
||||
function serveFile(filePath, pathname) {
|
||||
const ext = filePath.split('.').pop() || '';
|
||||
return responseFromFile(filePath, {
|
||||
'Content-Type': contentTypes[ext] || 'application/octet-stream',
|
||||
'Cache-Control': pathname.startsWith('/assets/')
|
||||
? 'public, max-age=31536000, immutable'
|
||||
: 'no-cache',
|
||||
});
|
||||
}
|
||||
|
||||
Bun.serve({
|
||||
port: 80,
|
||||
hostname: '0.0.0.0',
|
||||
fetch(req) {
|
||||
const url = new URL(req.url);
|
||||
const pathname = url.pathname;
|
||||
const filePath = resolve(distDir, pathname.slice(1));
|
||||
const insideDist = filePath === distDir || filePath.startsWith(`${distDir}${sep}`);
|
||||
|
||||
if (!insideDist) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
if (pathname !== '/' && existsSync(filePath)) {
|
||||
return serveFile(filePath, pathname);
|
||||
}
|
||||
|
||||
if (!pathname.includes('.') && existsSync(indexPath)) {
|
||||
return serveIndex();
|
||||
}
|
||||
|
||||
return new Response('Not Found', { status: 404 });
|
||||
},
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
# ─── Stage 1: Build ─────────────────────────────────────────────────────────
|
||||
FROM oven/bun:1 AS builder
|
||||
WORKDIR /app
|
||||
COPY apps/react/package.json apps/react/bun.lock ./
|
||||
RUN bun install --frozen-lockfile
|
||||
COPY apps/react .
|
||||
RUN bun run build
|
||||
|
||||
# ─── Stage 2: Runtime (Bun static server) ──────────────────────────────────
|
||||
FROM oven/bun:1-alpine
|
||||
WORKDIR /app
|
||||
COPY infra/docker/react-server.js ./server.js
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["bun", "server.js"]
|
||||
@@ -1,42 +0,0 @@
|
||||
# Use cargo-chef for dependency caching
|
||||
FROM lukemathwalker/cargo-chef:latest-rust-1.89.0 AS chef
|
||||
WORKDIR /app
|
||||
|
||||
FROM chef AS planner
|
||||
COPY apps/rust-auth .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
FROM chef AS builder
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
# Utilize buildkit cache mounts for cargo
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/app/target \
|
||||
cargo chef cook --release --recipe-path recipe.json
|
||||
|
||||
# Build application
|
||||
COPY apps/rust-auth .
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/app/target \
|
||||
cargo build --release && \
|
||||
cp target/release/rust-auth /app/rust-auth
|
||||
|
||||
# Final runtime image
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
libssl3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Add non-root user
|
||||
RUN groupadd -g 1001 appgroup && \
|
||||
useradd -u 1001 -g appgroup -s /bin/sh appuser
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/rust-auth /app/rust-auth
|
||||
|
||||
# Run as non-root
|
||||
USER appuser
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["./rust-auth"]
|
||||
@@ -1,13 +1,5 @@
|
||||
http:
|
||||
routers:
|
||||
# ── React SPA (domain root) ──
|
||||
react:
|
||||
rule: 'Host(`asepharyana.my.id`) || Host(`asepharyana.web.id`)'
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls: {}
|
||||
service: react-service
|
||||
|
||||
# ── Scraper API ──
|
||||
scraper:
|
||||
rule: 'Host(`scraper.asepharyana.my.id`) || Host(`api.asepharyana.my.id`) || Host(`scraper.asepharyana.web.id`) || Host(`api.asepharyana.web.id`)'
|
||||
@@ -18,40 +10,8 @@ http:
|
||||
- common-chain@file
|
||||
service: scraper-service
|
||||
|
||||
# ── Elysia API ──
|
||||
elysia:
|
||||
rule: 'Host(`elysia.asepharyana.my.id`) || Host(`elysia.asepharyana.web.id`)'
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls: {}
|
||||
middlewares:
|
||||
- common-chain@file
|
||||
service: elysia-service
|
||||
|
||||
# ── Rust Auth API ──
|
||||
rust-auth:
|
||||
rule: 'Host(`auth.asepharyana.my.id`) || Host(`auth.asepharyana.web.id`)'
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls: {}
|
||||
middlewares:
|
||||
- common-chain@file
|
||||
service: rust-auth-service
|
||||
|
||||
services:
|
||||
react-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: 'http://react-web:80'
|
||||
scraper-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: 'http://scraper-api:4091'
|
||||
elysia-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: 'http://elysia-api:4092'
|
||||
rust-auth-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: 'http://rust-auth:3000'
|
||||
|
||||
Reference in New Issue
Block a user