mirror of
https://github.com/ForFarmTeam/ForFarm.git
synced 2025-12-18 13:34:08 +01:00
chore: rewrite compose and add manifest file, markdown
This commit is contained in:
parent
1b819e4ed0
commit
00700af27f
91
README.md
91
README.md
@ -1,10 +1,91 @@
|
||||
# ForFarm
|
||||
A smart farming software uses AI, weather data, and analytics to help farmers make better decisions and improve productivity. It empowers farmers and agribusinesses to make data-driven decisions and enhance productivity through integrated technological tools.
|
||||
|
||||
## Installation
|
||||
A farming software designed to empower farmers and agribusinesses by AI, weather data, and analytics. ForFarm helps users make data-driven decisions, and optimize resource management through a tools.
|
||||
|
||||
### For development
|
||||
## Features
|
||||
|
||||
- **Farm & Crop Management:** Define farms, map croplands (points, polygons), track crop lifecycles, status, and growth stages.
|
||||
- **Inventory Tracking:** Manage farm resources like seeds, fertilizers, equipment, etc.
|
||||
- **Data Analytics:** Visualize farm and crop performance metrics. (Integration with weather, soil data planned).
|
||||
- **Knowledge Hub:** Access articles and guides on farming best practices.
|
||||
- **AI Chatbot:** Get contextual assistance based on your farm/crop data or ask general farming questions.
|
||||
- **Weather Integration:** (Implemented via Worker) Fetches current weather data for farms.
|
||||
- **User Authentication:** Secure login/registration using email/password and Google OAuth.
|
||||
- **Marketplace Insights:** (Mock Data) Provides simulated market price trends and analysis.
|
||||
|
||||
## Project Structure
|
||||
|
||||
The project is organized into two main components:
|
||||
|
||||
```zsh
|
||||
docker compose up
|
||||
```
|
||||
├── backend/ # Go backend application (API, business logic, data access)
|
||||
│ ├── cmd/ # Main entry points (API server, CLI commands)
|
||||
│ ├── internal/ # Private application code
|
||||
│ │ ├── api/ # API handlers and routing (Huma framework)
|
||||
│ │ ├── cache/ # Caching interface and implementations
|
||||
│ │ ├── config/ # Configuration loading (Viper)
|
||||
│ │ ├── domain/ # Core business entities and repository interfaces
|
||||
│ │ ├── event/ # Event bus and projection logic
|
||||
│ │ ├── middlewares/ # HTTP middlewares (Auth, Rate Limiting)
|
||||
│ │ ├── repository/ # Data access layer implementations (Postgres)
|
||||
│ │ ├── services/ # Business logic services (Chat, Weather, Analytics)
|
||||
│ │ └── workers/ # Background worker processes (Weather Updater)
|
||||
│ ├── migrations/ # Database schema migrations (Goose)
|
||||
│ ├── scripts/ # Utility scripts (Seeding)
|
||||
│ ├── .air.toml # Live reload config for backend dev
|
||||
│ ├── go.mod # Go module dependencies
|
||||
│ └── go.dockerfile # Dockerfile for backend
|
||||
├── frontend/ # Next.js frontend application (UI)
|
||||
│ ├── app/ # Next.js App Router structure (pages, layouts)
|
||||
│ ├── api/ # Frontend API client functions for backend interaction
|
||||
│ ├── components/ # Reusable UI components (shadcn/ui)
|
||||
│ ├── context/ # React context providers (Session)
|
||||
│ ├── hooks/ # Custom React hooks
|
||||
│ ├── lib/ # Utility functions, providers
|
||||
│ ├── schemas/ # Zod validation schemas for forms
|
||||
│ ├── types.ts # TypeScript type definitions
|
||||
│ ├── next.config.ts # Next.js configuration
|
||||
│ └── next.dockerfile # Dockerfile for frontend
|
||||
├── docker-compose.yml # Docker Compose configuration for services
|
||||
├── .env.example # Example environment variables file
|
||||
├── README.md # This file
|
||||
└── SETUP.md # Detailed development setup guide
|
||||
```
|
||||
|
||||
- **Backend:** Built with Go, using Chi for routing, Huma for API definition, pgx for PostgreSQL interaction, and Cobra for CLI commands. It handles business logic, data persistence, and external service integrations.
|
||||
- **Frontend:** Built with Next.js (App Router) and TypeScript, using Tailwind CSS and shadcn/ui for styling and components. It provides the user interface and interacts with the backend API.
|
||||
|
||||
## Installation & Setup
|
||||
|
||||
For detailed setup instructions, please refer to the **[SETUP.md](SETUP.md)** guide.
|
||||
|
||||
The basic steps are:
|
||||
|
||||
1. **Prerequisites:** Ensure Docker, Docker Compose, Go, Node.js, and pnpm are installed.
|
||||
2. **Clone:** Clone this repository.
|
||||
3. **Configure:** Create a `.env` file from `.env.example` and fill in necessary secrets and keys (Database, JWT, Google OAuth, Maps API, Weather API, Gemini API).
|
||||
4. **Run:** Start all services using `docker compose up --build -d`.
|
||||
5. **Migrate:** Run database migrations: `cd backend && make migrate && cd ..`.
|
||||
6. **Seed (Optional):** Populate static data: `cd backend && make seed && cd ..`.
|
||||
7. **Access:** Open [http://localhost:3000](http://localhost:3000) in your browser.
|
||||
|
||||
## Usage
|
||||
|
||||
Once set up and running:
|
||||
|
||||
1. Navigate to [http://localhost:3000](http://localhost:3000).
|
||||
2. Register a new account or log in.
|
||||
3. Explore the dashboard:
|
||||
- Add and manage your farms.
|
||||
- Add croplands within your farms, drawing boundaries or placing markers.
|
||||
- Manage your inventory items.
|
||||
- Consult the AI Chatbot for farming advice.
|
||||
- Browse the Knowledge Hub articles.
|
||||
- View (simulated) Marketplace data.
|
||||
|
||||
## Contributors
|
||||
|
||||
- [Natthapol Sermsaran](https://github.com/xNatthapol)
|
||||
- [Sirin Puenggun](https://github.com/Sosokker/)
|
||||
- [Pattadon Loyprasert](https://github.com/GGWPXXXX)
|
||||
- [Buravit Yenjit](https://github.com/KikyoBRV)
|
||||
|
||||
283
SETUP.md
Normal file
283
SETUP.md
Normal file
@ -0,0 +1,283 @@
|
||||
# ForFarm Project Setup Guide
|
||||
|
||||
This guide provides instructions for setting up and running the ForFarm project using different methods.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Ensure you have the following tools installed:
|
||||
|
||||
- **Go:** Version 1.23 or later (see `backend/go.mod`).
|
||||
- **Node.js:** Version 20 or later (see `frontend/next.dockerfile`).
|
||||
- **pnpm:** Node package manager (`npm install -g pnpm`).
|
||||
- **Docker:** Latest version.
|
||||
- **Docker Compose:** Latest version (often included with Docker Desktop).
|
||||
- **kubectl:** Kubernetes command-line tool.
|
||||
- **gcloud:** Google Cloud SDK (if deploying to GKE).
|
||||
|
||||
## Configuration
|
||||
|
||||
Environment variables are used for configuration.
|
||||
|
||||
1. **Backend:**
|
||||
|
||||
- Copy `backend/sample.env` to `backend/.env`.
|
||||
- Fill in the required values in `backend/.env`:
|
||||
- `DATABASE_URL`: Connection string for your PostgreSQL database. (e.g., `postgres://postgres:@Password123@localhost:5433/postgres?sslmode=disable` for local Docker Compose setup).
|
||||
- `RABBITMQ_URL`: Connection string for RabbitMQ (e.g., `amqp://user:password@localhost:5672/` for local Docker Compose).
|
||||
- `JWT_SECRET_KEY`: A strong, random secret key (at least 32 characters).
|
||||
- `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`: For Google OAuth.
|
||||
- `OPENWEATHER_API_KEY`: Your OpenWeatherMap API key.
|
||||
- `GEMINI_API_KEY`: Your Google AI Gemini API key.
|
||||
- `GCS_BUCKET_NAME`: Your Google Cloud Storage bucket name.
|
||||
- `GCS_SERVICE_ACCOUNT_KEY_PATH`: (Optional) Path to your GCS service account key JSON file if _not_ using Application Default Credentials (ADC). Leave empty if using ADC (recommended for GKE with Workload Identity).
|
||||
|
||||
2. **Frontend:**
|
||||
- Copy `frontend/sample.env` to `frontend/.env`.
|
||||
- Fill in the required values in `frontend/.env`:
|
||||
- `NEXT_PUBLIC_BACKEND_URL`: URL of the running backend API (e.g., `http://localhost:8000` for local/Compose).
|
||||
- `NEXT_PUBLIC_GOOGLE_CLIENT_ID`: Your Google Client ID for OAuth on the frontend.
|
||||
- `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY`: Your Google Maps API Key.
|
||||
- (Other `NEXTAUTH_*` variables might be needed if you integrate `next-auth` fully).
|
||||
|
||||
## Running Locally (Manual Setup)
|
||||
|
||||
This method requires running services like Postgres and RabbitMQ separately.
|
||||
|
||||
1. **Start Database:** Run PostgreSQL (e.g., using Docker: `docker run --name some-postgres -e POSTGRES_PASSWORD=yourpassword -p 5432:5432 -d postgres:16-alpine`). Ensure the `DATABASE_URL` in `backend/.env` points to it.
|
||||
2. **Start RabbitMQ:** Run RabbitMQ (e.g., using Docker: `docker run --name some-rabbit -p 5672:5672 -p 15672:15672 -d rabbitmq:3-management-alpine`). Ensure `RABBITMQ_URL` in `backend/.env` points to it.
|
||||
3. **Backend Migrations:**
|
||||
```bash
|
||||
cd backend
|
||||
go run cmd/forfarm/main.go migrate
|
||||
```
|
||||
4. **Run Backend API:**
|
||||
```bash
|
||||
cd backend
|
||||
# For live reloading (requires air - go install github.com/cosmtrek/air@latest)
|
||||
# air
|
||||
# Or run directly
|
||||
go run cmd/forfarm/main.go api
|
||||
```
|
||||
The backend should be running on `http://localhost:8000`.
|
||||
5. **Run Frontend:**
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
The frontend should be running on `http://localhost:3000`.
|
||||
|
||||
6. (Optional) Add dummy data in /backend/dummy directory to database
|
||||
|
||||
- Do it manually or `make seed`
|
||||
|
||||
## Installation Steps (In detailed)
|
||||
|
||||
1. **Clone the Repository:**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-username/ForFarm.git # Replace with your repo URL
|
||||
cd ForFarm
|
||||
```
|
||||
|
||||
2. **Environment Variables:**
|
||||
|
||||
- Copy the example environment file:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
- **Edit the `.env` file:** Fill in the required values, especially for:
|
||||
- `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` (you can keep defaults for local setup)
|
||||
- `JWT_SECRET_KEY` (generate a strong, random secret)
|
||||
- `GOOGLE_CLIENT_ID` (if using Google OAuth)
|
||||
- `NEXT_PUBLIC_GOOGLE_CLIENT_ID` (Frontend Google Client ID)
|
||||
- `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` (Required for maps)
|
||||
- `OPENWEATHER_API_KEY` (Required for weather features)
|
||||
- `GEMINI_API_KEY` (Required for AI chatbot features)
|
||||
- `RABBITMQ_URL` (Keep default if using the docker-compose setup)
|
||||
- (Optionally adjust `RATE_LIMIT_*` variables)
|
||||
|
||||
3. **Build and Run Services:**
|
||||
Use Docker Compose to build the images and start the backend, frontend, and database containers.
|
||||
|
||||
```bash
|
||||
docker compose up --build -d
|
||||
```
|
||||
|
||||
- `--build`: Forces Docker to rebuild images if Dockerfiles have changed.
|
||||
- `-d`: Runs containers in detached mode (in the background).
|
||||
|
||||
4. **Run Backend Database Migrations:**
|
||||
Apply the necessary database schema changes. Open a **new terminal** in the project root and navigate to the backend directory:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
make migrate
|
||||
cd ..
|
||||
```
|
||||
|
||||
- This command uses Go to connect to the database (running in Docker) and applies migrations located in `backend/migrations`.
|
||||
|
||||
5. **Install Frontend Dependencies:**
|
||||
Navigate to the frontend directory and install its dependencies using pnpm.
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
pnpm install
|
||||
cd ..
|
||||
```
|
||||
|
||||
_(Docker Compose might handle this during build if configured in `next.dockerfile`, but running it explicitly ensures dependencies are up-to-date)_
|
||||
|
||||
6. **Access the Application:**
|
||||
|
||||
- **Frontend:** Open your browser and navigate to [http://localhost:3000](http://localhost:3000) (or the port specified by `FRONTEND_PORT` in your `.env`).
|
||||
- **Backend API:** The API is accessible at [http://localhost:8000](http://localhost:8000) (or the port specified by `BACKEND_PORT`). You can use tools like Postman or `curl` to interact with it.
|
||||
|
||||
7. (Optional) Add dummy data in /backend/dummy directory to database
|
||||
|
||||
- Do it manually or `make seed`
|
||||
|
||||
## Running with Docker Compose
|
||||
|
||||
This is the recommended way for local development and testing the containerized setup.
|
||||
|
||||
1. **Ensure `.env` files are configured** as described in the Configuration section. Use `localhost` for hostnames in URLs (e.g., `DATABASE_URL='postgres://postgres:@Password123@db:5432/postgres?sslmode=disable'`, `RABBITMQ_URL=amqp://user:password@rabbitmq:5672/` - note the service names `db` and `rabbitmq`).
|
||||
2. **Build and Start:**
|
||||
```bash
|
||||
docker compose up --build -d # -d runs in detached mode
|
||||
```
|
||||
3. **Run Migrations (First time or after changes):**
|
||||
```bash
|
||||
docker compose exec backend /app/api migrate
|
||||
# Or if using source mount and go is available:
|
||||
# docker compose exec backend go run cmd/forfarm/main.go migrate
|
||||
```
|
||||
4. **Access Services:**
|
||||
- Frontend: `http://localhost:3000`
|
||||
- Backend API: `http://localhost:8000`
|
||||
- RabbitMQ Management: `http://localhost:15672` (user/password from `.env`)
|
||||
- Database: Connect via `localhost:5433` using credentials from `.env`.
|
||||
5. **View Logs:** `docker compose logs -f [service_name]` (e.g., `docker compose logs -f backend`)
|
||||
6. **Stop:** `docker compose down`
|
||||
|
||||
## Development Workflow
|
||||
|
||||
- **Live Reload (Backend):** While `docker compose up -d` keeps the backend running, for active Go development with live reload, stop the backend service (`docker compose stop backend`) and run:
|
||||
```bash
|
||||
cd backend
|
||||
make live
|
||||
```
|
||||
This uses `air` (configured in `.air.toml`) to automatically rebuild and restart the Go application when code changes.
|
||||
- **Live Reload (Frontend):** The `pnpm dev` command used in the frontend Dockerfile typically includes hot module replacement (HMR). Changes made to frontend code should reflect in the browser automatically when running `docker compose up`. If not, check the Next.js configuration.
|
||||
|
||||
## Deploying to Google Kubernetes Engine (GKE)
|
||||
|
||||
This requires a configured GKE cluster and `gcloud` CLI authenticated.
|
||||
|
||||
1. **Prerequisites:**
|
||||
|
||||
- Create a GKE cluster.
|
||||
- Configure `kubectl` to connect to your cluster (`gcloud container clusters get-credentials YOUR_CLUSTER_NAME --zone YOUR_ZONE --project YOUR_PROJECT_ID`).
|
||||
- Enable Google Container Registry (GCR) or Artifact Registry API.
|
||||
|
||||
2. **Configure GCS:**
|
||||
|
||||
- Create a GCS bucket (`YOUR_GCS_BUCKET_NAME`).
|
||||
- **Authentication:**
|
||||
- **(Recommended) Workload Identity:** Set up Workload Identity to grant your Kubernetes Service Account permissions to access the GCS bucket without key files. This involves creating a GCP Service Account, granting it `roles/storage.objectAdmin` on the bucket, creating a K8s Service Account (e.g., `backend-sa`), and binding them. Update `backend-deployment.yaml` to use `serviceAccountName: backend-sa`.
|
||||
- **(Alternative) Service Account Key:** Create a GCP Service Account, grant it permissions, download its JSON key file.
|
||||
|
||||
3. **Build and Push Docker Images:**
|
||||
|
||||
- Authenticate Docker with GCR/Artifact Registry (`gcloud auth configure-docker YOUR_REGION-docker.pkg.dev`).
|
||||
- Build the images:
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
docker build -t YOUR_REGION-docker.pkg.dev/YOUR_GCR_PROJECT_ID/forfarm/backend:latest -f backend/go.dockerfile ./backend
|
||||
|
||||
# Frontend
|
||||
docker build -t YOUR_REGION-docker.pkg.dev/YOUR_GCR_PROJECT_ID/forfarm/frontend:latest -f frontend/next.dockerfile ./frontend
|
||||
```
|
||||
|
||||
- Push the images:
|
||||
```bash
|
||||
docker push YOUR_REGION-docker.pkg.dev/YOUR_GCR_PROJECT_ID/forfarm/backend:latest
|
||||
docker push YOUR_REGION-docker.pkg.dev/YOUR_GCR_PROJECT_ID/forfarm/frontend:latest
|
||||
```
|
||||
- **Update `k8s/*.yaml` files:** Replace `YOUR_GCR_PROJECT_ID/forfarm-backend:latest` and `YOUR_GCR_PROJECT_ID/forfarm-frontend:latest` with your actual image paths.
|
||||
|
||||
4. **Create Kubernetes Secrets:**
|
||||
|
||||
- **Encode Secrets:** Base64 encode all values needed in `k8s/secrets.yaml`.
|
||||
```bash
|
||||
echo -n "your_password" | base64
|
||||
# For GCS key file (if using):
|
||||
cat path/to/your-gcs-key.json | base64 | tr -d '\n' # Ensure no newlines in output
|
||||
```
|
||||
- **Update `k8s/secrets.yaml`:** Paste the base64 encoded values into the `data` section.
|
||||
- **Apply Secrets:**
|
||||
```bash
|
||||
kubectl apply -f k8s/namespace.yaml
|
||||
kubectl apply -f k8s/secrets.yaml -n forfarm
|
||||
```
|
||||
Alternatively, create secrets imperatively (safer as values aren't stored in YAML):
|
||||
```bash
|
||||
kubectl create secret generic forfarm-secrets -n forfarm \
|
||||
--from-literal=POSTGRES_PASSWORD='your_db_password' \
|
||||
--from-literal=RABBITMQ_PASSWORD='your_rabbit_password' \
|
||||
# ... add other secrets ...
|
||||
# If using key file:
|
||||
# --from-file=GCS_SERVICE_ACCOUNT_KEY_JSON=/path/to/your-gcs-key.json
|
||||
```
|
||||
|
||||
5. **Create ConfigMap:**
|
||||
|
||||
- **Update `k8s/configmap.yaml`:** Replace placeholders like `YOUR_GOOGLE_CLIENT_ID`, `YOUR_GOOGLE_MAPS_API_KEY`, `YOUR_GCS_BUCKET_NAME`. Adjust service URLs if needed.
|
||||
- **Apply ConfigMap:**
|
||||
```bash
|
||||
kubectl apply -f k8s/configmap.yaml -n forfarm
|
||||
```
|
||||
|
||||
6. **Apply Deployments, Services, PVCs:**
|
||||
|
||||
```bash
|
||||
# Apply database and message queue first
|
||||
kubectl apply -f k8s/postgres-pvc.yaml -n forfarm # Only if using self-hosted postgres
|
||||
kubectl apply -f k8s/postgres-deployment.yaml -n forfarm
|
||||
kubectl apply -f k8s/postgres-service.yaml -n forfarm
|
||||
kubectl apply -f k8s/rabbitmq-pvc.yaml -n forfarm
|
||||
kubectl apply -f k8s/rabbitmq-deployment.yaml -n forfarm
|
||||
kubectl apply -f k8s/rabbitmq-service.yaml -n forfarm
|
||||
|
||||
# Wait for DB and RabbitMQ to be ready (check pods: kubectl get pods -n forfarm -w)
|
||||
|
||||
# Apply backend and frontend
|
||||
kubectl apply -f k8s/backend-deployment.yaml -n forfarm
|
||||
kubectl apply -f k8s/backend-service.yaml -n forfarm
|
||||
kubectl apply -f k8s/frontend-deployment.yaml -n forfarm
|
||||
kubectl apply -f k8s/frontend-service.yaml -n forfarm
|
||||
```
|
||||
|
||||
_Note: The `initContainer` in `backend-deployment.yaml` should handle migrations._
|
||||
|
||||
7. **Setup Ingress:**
|
||||
|
||||
- **Update `k8s/ingress.yaml`:** Replace `your-domain.com` with your domain. Configure TLS and managed certificates if needed (requires creating a `ManagedCertificate` resource in GKE).
|
||||
- **Apply Ingress:**
|
||||
```bash
|
||||
kubectl apply -f k8s/ingress.yaml -n forfarm
|
||||
```
|
||||
- **Get Ingress IP:** Wait a few minutes, then run `kubectl get ingress forfarm-ingress -n forfarm`. Note the `ADDRESS`.
|
||||
- **Configure DNS:** Point your domain's A record(s) to the Ingress IP address.
|
||||
|
||||
8. **Alternative: Cloud SQL:** Instead of running Postgres in K8s, consider using Cloud SQL. Create a Cloud SQL instance, configure its user/database, and update the `DATABASE_URL` in your `k8s/configmap.yaml` to point to the Cloud SQL proxy or private IP. You won't need the `postgres-*.yaml` files.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Docker Compose:** Use `docker compose logs -f <service_name>` to check logs. Use `docker compose exec <service_name> sh` to get a shell inside a container.
|
||||
- **Kubernetes:** Use `kubectl get pods -n forfarm`, `kubectl logs <pod_name> -n forfarm [-c <container_name>]`, `kubectl describe pod <pod_name> -n forfarm`.
|
||||
- **Migrations:** Check the `goose_db_version` table in your database to see applied migrations.
|
||||
@ -1,16 +1,48 @@
|
||||
FROM golang:1.23.6-alpine3.21
|
||||
FROM golang:1.23-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk update && apk add --no-cache curl
|
||||
|
||||
RUN go install github.com/air-verse/air@latest
|
||||
# Install build dependencies (if any, e.g., for CGO)
|
||||
# RUN apk add --no-cache gcc musl-dev
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
# Build the application binary
|
||||
# Statically link if possible (reduces dependencies in final image)
|
||||
# RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o ./tmp/api ./cmd/forfarm
|
||||
# Or standard build if CGO is needed or static linking causes issues
|
||||
RUN go build -o ./tmp/api ./cmd/forfarm
|
||||
|
||||
# --- Runner Stage ---
|
||||
FROM alpine:latest
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies (ca-certificates for HTTPS, tzdata for timezones)
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
|
||||
# Copy the compiled binary from the builder stage
|
||||
COPY --from=builder /app/tmp/api /app/api
|
||||
|
||||
# Copy migrations directory (needed if running migrations from container)
|
||||
COPY migrations ./migrations
|
||||
|
||||
# Copy .env file (for local/compose - NOT for production K8s)
|
||||
# If you intend to run migrations inside the container on start,
|
||||
# the DATABASE_URL needs to be available. Secrets/ConfigMaps are preferred in K8s.
|
||||
# COPY .env .env
|
||||
|
||||
# Expose the port the application listens on
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["air", "-c", ".air.toml"]
|
||||
# Define the entrypoint - runs the API server by default
|
||||
# Migrations should ideally be run as a separate step or init container
|
||||
ENTRYPOINT ["/app/api"]
|
||||
|
||||
# Default command (in case ENTRYPOINT is just the binary)
|
||||
CMD ["api"]
|
||||
@ -1,38 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/danielgtaylor/huma/v2"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type HelloWorldInput struct {
|
||||
MyHeader string `header:"Authorization" required:"true" example:"Bearer token"`
|
||||
}
|
||||
|
||||
type HelloWorldOutput struct {
|
||||
Body struct {
|
||||
Message string `json:"message" example:"hello world"`
|
||||
}
|
||||
}
|
||||
|
||||
func (a *api) registerHelloRoutes(_ chi.Router, api huma.API) {
|
||||
tags := []string{"hello"}
|
||||
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "helloWorld",
|
||||
Method: http.MethodPost,
|
||||
Path: "/hello",
|
||||
Tags: tags,
|
||||
Summary: "Get hello world message",
|
||||
Description: "Returns a simple hello world message",
|
||||
}, a.helloWorldHandler)
|
||||
}
|
||||
|
||||
func (a *api) helloWorldHandler(ctx context.Context, input *HelloWorldInput) (*HelloWorldOutput, error) {
|
||||
resp := &HelloWorldOutput{}
|
||||
resp.Body.Message = "hello world from forfarm"
|
||||
return resp, nil
|
||||
}
|
||||
12
backend/sample.env
Normal file
12
backend/sample.env
Normal file
@ -0,0 +1,12 @@
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=@Password123
|
||||
POSTGRES_DB=postgres
|
||||
DATABASE_URL='postgres://postgres:@Password123@localhost:5433/postgres'
|
||||
GOOGLE_CLIENT_ID=GOOGLE_CLIENT_ID
|
||||
GOOGLE_CLIENT_SECRET=GOOGLE_CLIENT_SECRET
|
||||
RABBITMQ_URL=amqp://user:password@localhost:5672/
|
||||
WEATHER_FETCH_INTERVAL=60m
|
||||
OPENWEATHER_API_KEY=OPENWEATHER_API_KEY
|
||||
GEMINI_API_KEY=GEMINI_API_KEY
|
||||
RATE_LIMIT_ENABLED=true
|
||||
RATE_LIMIT_RPS=100
|
||||
@ -1,47 +1,90 @@
|
||||
services:
|
||||
go-api:
|
||||
container_name: go-api
|
||||
# image: goapi
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
container_name: forfarm_db
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-@Password123}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
ports:
|
||||
- "5433:5432"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-postgres} -d $${POSTGRES_DB:-postgres}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
rabbitmq:
|
||||
image: rabbitmq:3-management-alpine
|
||||
container_name: forfarm_rabbitmq
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- rabbitmq_data:/var/lib/rabbitmq/
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-user}
|
||||
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-password}
|
||||
ports:
|
||||
- "5672:5672"
|
||||
- "15672:15672"
|
||||
healthcheck:
|
||||
test: rabbitmq-diagnostics -q ping
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
backend:
|
||||
container_name: forfarm_backend
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: go.dockerfile
|
||||
environment:
|
||||
DATABASE_URL: 'postgres://postgres:@Password123@psqldb:5432/postgres?sslmode=disable'
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '8000:8000'
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- psqldb
|
||||
db:
|
||||
condition: service_healthy
|
||||
rabbitmq:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./backend/.env
|
||||
# If running migrations inside the container:
|
||||
# command: sh -c "/app/api migrate && /app/api api"
|
||||
# If running migrations separately (preferred):
|
||||
command: ["api"] # Runs the default command in the Dockerfile
|
||||
volumes: # Optional: Mount source for live reload during dev (remove for prod builds)
|
||||
- ./backend:/app
|
||||
# networks:
|
||||
# - forfarm-net
|
||||
|
||||
psqldb:
|
||||
container_name: psqldb
|
||||
image: postgres:17
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: '@Password123'
|
||||
POSTGRES_DB: postgres
|
||||
ports:
|
||||
- '5433:5432'
|
||||
volumes:
|
||||
- pgsqldata:/var/lib/postgresql/data
|
||||
|
||||
next-frontend:
|
||||
container_name: next-frontend
|
||||
# image: nextfront
|
||||
frontend:
|
||||
container_name: forfarm_frontend
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: next.dockerfile
|
||||
environment:
|
||||
NEXT_PUBLIC_API_URL: 'localhost:8000/api'
|
||||
# args:
|
||||
# NEXT_PUBLIC_BACKEND_URL: ${NEXT_PUBLIC_BACKEND_URL}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3000:3000'
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- go-api
|
||||
- backend
|
||||
env_file:
|
||||
- ./frontend/.env
|
||||
# volumes: # Mount source for live reload during dev (remove for prod builds)
|
||||
# - ./frontend:/app
|
||||
# - /app/node_modules # Avoid overwriting node_modules
|
||||
# - /app/.next # Avoid overwriting build artifacts
|
||||
# networks:
|
||||
# - forfarm-net
|
||||
|
||||
volumes:
|
||||
pgsqldata:
|
||||
postgres_data:
|
||||
driver: local
|
||||
rabbitmq_data:
|
||||
driver: local
|
||||
# networks:
|
||||
# forfarm-net:
|
||||
# driver: bridge
|
||||
|
||||
@ -58,7 +58,7 @@ export function EditFarmForm({ initialData, onSubmit, onCancel, isSubmitting }:
|
||||
type: initialData.farmType || "",
|
||||
area: initialData.totalSize || "",
|
||||
});
|
||||
}, [initialData, form.reset]);
|
||||
}, [initialData, form]);
|
||||
|
||||
const handleSubmit = async (values: z.infer<typeof farmFormSchema>) => {
|
||||
try {
|
||||
|
||||
@ -49,11 +49,11 @@ export function FarmCard({ variant, farm, onClick, onEditClick, onDeleteClick }:
|
||||
}
|
||||
|
||||
if (variant === "farm" && farm) {
|
||||
const formattedDate = new Intl.DateTimeFormat("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
}).format(new Date(farm.createdAt));
|
||||
// const formattedDate = new Intl.DateTimeFormat("en-US", {
|
||||
// year: "numeric",
|
||||
// month: "short",
|
||||
// day: "numeric",
|
||||
// }).format(new Date(farm.createdAt));
|
||||
|
||||
return (
|
||||
<Card className={cardClasses}>
|
||||
|
||||
@ -10,7 +10,15 @@ const compat = new FlatCompat({
|
||||
});
|
||||
|
||||
const eslintConfig = [
|
||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||
...compat.config({
|
||||
extends: ["next", "next/core-web-vitals", "next/typescript"],
|
||||
rules: {
|
||||
"react/no-unescaped-entities": "off",
|
||||
"@next/next/no-page-custom-font": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
export default eslintConfig;
|
||||
|
||||
@ -13,6 +13,9 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@ -1,19 +1,47 @@
|
||||
FROM node:20 AS base
|
||||
# --- Base Stage (Dependencies) ---
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm i -g pnpm
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# Copy package manager files
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# Install dependencies using pnpm
|
||||
# Use --frozen-lockfile for reproducible installs
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# --- Builder Stage ---
|
||||
FROM base AS builder
|
||||
|
||||
# Copy the rest of the source code
|
||||
COPY . .
|
||||
|
||||
FROM node:20-alpine3.20 AS release
|
||||
WORKDIR /app
|
||||
# Copy environment variables needed for build time (if any)
|
||||
# Ensure this file exists or handle its absence
|
||||
# COPY .env.production .env.production
|
||||
|
||||
RUN npm i -g pnpm
|
||||
# Build the Next.js application
|
||||
# Pass build-time env vars if needed via ARG and --build-arg
|
||||
# Example: ARG NEXT_PUBLIC_SOME_VAR
|
||||
# ENV NEXT_PUBLIC_SOME_VAR=$NEXT_PUBLIC_SOME_VAR
|
||||
RUN pnpm build
|
||||
|
||||
COPY --from=base /app .
|
||||
# --- Runner Stage ---
|
||||
FROM base AS runner
|
||||
|
||||
# Copy built artifacts from the builder stage
|
||||
COPY --from=builder /app/.next ./.next
|
||||
COPY --from=builder /app/public ./public
|
||||
# Copy only necessary node_modules for production runtime
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
|
||||
# Expose the port the Next.js app runs on
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["pnpm", "dev"]
|
||||
# Set NODE_ENV to production
|
||||
ENV NODE_ENV=production
|
||||
|
||||
CMD ["pnpm", "start"]
|
||||
8
frontend/sample.env
Normal file
8
frontend/sample.env
Normal file
@ -0,0 +1,8 @@
|
||||
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_URL_INTERNAL=http://localhost:3000
|
||||
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
|
||||
NEXT_PUBLIC_GOOGLE_CLIENT_ID=NEXT_PUBLIC_GOOGLE_CLIENT_ID
|
||||
GOOGLE_CLIENT_SECRET=GOOGLE_CLIENT_SECRET
|
||||
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
|
||||
OPENWEATHER_API_KEY=OPENWEATHER_API_KEY
|
||||
43
k8s/backend-deployment.yaml
Normal file
43
k8s/backend-deployment.yaml
Normal file
@ -0,0 +1,43 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forfarm-backend
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: forfarm-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: forfarm-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: backend
|
||||
image: sosokker/forfarm-backend:latest
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: forfarm-config
|
||||
- secretRef:
|
||||
name: forfarm-secrets
|
||||
resources:
|
||||
requests: # Minimum guaranteed resources
|
||||
memory: "128Mi" # Mebibytes
|
||||
cpu: "100m" # 100 millicores (0.1 CPU)
|
||||
limits: # Maximum allowed resources
|
||||
memory: "256Mi"
|
||||
cpu: "500m" # 500 millicores (0.5 CPU)
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 20
|
||||
13
k8s/backend-service.yaml
Normal file
13
k8s/backend-service.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: backend-service
|
||||
namespace: forfarm
|
||||
spec:
|
||||
selector:
|
||||
app: backend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8000
|
||||
targetPort: 8000
|
||||
type: ClusterIP
|
||||
29
k8s/configmap.yaml
Normal file
29
k8s/configmap.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: forfarm-config
|
||||
namespace: forfarm
|
||||
data:
|
||||
POSTGRES_USER: "postgres"
|
||||
POSTGRES_DB: "forfarmdb"
|
||||
POSTGRES_HOST: "postgres-service.forfarm.svc.cluster.local"
|
||||
DATABASE_URL: "postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@$(POSTGRES_HOST):5432/$(POSTGRES_DB)?sslmode=disable"
|
||||
|
||||
RABBITMQ_USER: "user"
|
||||
RABBITMQ_HOST: "rabbitmq-service.forfarm.svc.cluster.local"
|
||||
RABBITMQ_URL: "amqp://$(RABBITMQ_USER):$(RABBITMQ_PASSWORD)@$(RABBITMQ_HOST):5672/"
|
||||
|
||||
# Backend Config
|
||||
PORT: "8000"
|
||||
WEATHER_FETCH_INTERVAL: "60m"
|
||||
OPENWEATHER_CACHE_TTL: "15m"
|
||||
GOOGLE_CLIENT_ID: "GOOGLE_CLIENT_ID"
|
||||
GOOGLE_REDIRECT_URL: "https://your-domain.com/auth/login/google"
|
||||
|
||||
NEXT_PUBLIC_BACKEND_URL: "http://backend-service.forfarm.svc.cluster.local:8000"
|
||||
NEXT_PUBLIC_GOOGLE_CLIENT_ID: "NEXT_PUBLIC_GOOGLE_CLIENT_ID"
|
||||
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: "NEXT_PUBLIC_GOOGLE_MAPS_API_KEY"
|
||||
|
||||
# GCS Config
|
||||
GCS_BUCKET_NAME: "YOUR_GCS_BUCKET_NAME"
|
||||
# GCS_SERVICE_ACCOUNT_KEY_PATH: "/etc/gcs-secrets/key.json"
|
||||
45
k8s/frontend-deployment.yaml
Normal file
45
k8s/frontend-deployment.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forfarm-frontend
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: forfarm-frontend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: forfarm-frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: frontend
|
||||
image: sosokker/forfarm-frontend:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
env:
|
||||
- name: NEXT_PUBLIC_BACKEND_URL
|
||||
value: "http://forfarm-backend-service:8000"
|
||||
- name: NEXT_PUBLIC_GOOGLE_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: forfarm-secrets
|
||||
key: NEXT_PUBLIC_GOOGLE_CLIENT_ID
|
||||
- name: NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: forfarm-secrets
|
||||
key: NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "150m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "750m"
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 3000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
13
k8s/frontend-service.yaml
Normal file
13
k8s/frontend-service.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: frontend-service
|
||||
namespace: forfarm
|
||||
spec:
|
||||
selector:
|
||||
app: frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 3000
|
||||
type: ClusterIP
|
||||
30
k8s/ingress.yaml
Normal file
30
k8s/ingress.yaml
Normal file
@ -0,0 +1,30 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: forfarm-ingress
|
||||
namespace: forfarm
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "gce"
|
||||
networking.gke.io/managed-certificates: "forfarm-certificate"
|
||||
spec:
|
||||
rules:
|
||||
- host: sirin.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: frontend-service
|
||||
port:
|
||||
number: 80
|
||||
- host: api.sirin.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: backend-service
|
||||
port:
|
||||
number: 8000
|
||||
4
k8s/namespace.yaml
Normal file
4
k8s/namespace.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: forfarm
|
||||
72
k8s/postgres-deployment.yaml
Normal file
72
k8s/postgres-deployment.yaml
Normal file
@ -0,0 +1,72 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: postgres-deployment
|
||||
namespace: forfarm
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:16-alpine
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "500m"
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: forfarm-config
|
||||
key: POSTGRES_DB
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: forfarm-config
|
||||
key: POSTGRES_USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: forfarm-secrets
|
||||
key: POSTGRES_PASSWORD
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql/data
|
||||
name: postgres-storage
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["pg_isready", "-U", "$(POSTGRES_USER)", "-d", "$(POSTGRES_DB)"]
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["pg_isready", "-U", "$(POSTGRES_USER)", "-d", "$(POSTGRES_DB)"]
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: postgres-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: postgres-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: postgres-pvc
|
||||
namespace: forfarm
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
13
k8s/postgres-service.yaml
Normal file
13
k8s/postgres-service.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: postgres-service
|
||||
namespace: forfarm
|
||||
spec:
|
||||
selector:
|
||||
app: postgres
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
type: ClusterIP
|
||||
68
k8s/rabbitmq-deployment.yaml
Normal file
68
k8s/rabbitmq-deployment.yaml
Normal file
@ -0,0 +1,68 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: rabbitmq-deployment
|
||||
namespace: forfarm
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rabbitmq
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rabbitmq
|
||||
spec:
|
||||
containers:
|
||||
- name: rabbitmq
|
||||
image: rabbitmq:3-management-alpine
|
||||
ports:
|
||||
- containerPort: 5672 # AMQP
|
||||
- containerPort: 15672 # Management UI
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "300m"
|
||||
env:
|
||||
- name: RABBITMQ_DEFAULT_USER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: forfarm-config
|
||||
key: RABBITMQ_USER
|
||||
- name: RABBITMQ_DEFAULT_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: forfarm-secrets
|
||||
key: RABBITMQ_PASSWORD
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/rabbitmq/
|
||||
name: rabbitmq-storage
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["rabbitmq-diagnostics", "status"]
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["rabbitmq-diagnostics", "ping"]
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: rabbitmq-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: rabbitmq-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: rabbitmq-pvc
|
||||
namespace: forfarm
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
18
k8s/rabbitmq-service.yaml
Normal file
18
k8s/rabbitmq-service.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: rabbitmq-service
|
||||
namespace: forfarm
|
||||
spec:
|
||||
selector:
|
||||
app: rabbitmq
|
||||
ports:
|
||||
- name: amqp
|
||||
protocol: TCP
|
||||
port: 5672
|
||||
targetPort: 5672
|
||||
- name: management
|
||||
protocol: TCP
|
||||
port: 15672
|
||||
targetPort: 15672
|
||||
type: ClusterIP
|
||||
15
k8s/secrets.yaml
Normal file
15
k8s/secrets.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: forfarm-secrets
|
||||
namespace: forfarm
|
||||
type: Opaque
|
||||
data:
|
||||
# Use: echo -n "your_password" | base64
|
||||
POSTGRES_PASSWORD: <base64-encoded-db-password>
|
||||
RABBITMQ_PASSWORD: <base64-encoded-rabbitmq-password>
|
||||
JWT_SECRET_KEY: <base64-encoded-jwt-secret>
|
||||
GOOGLE_CLIENT_SECRET: <base64-encoded-google-client-secret>
|
||||
OPENWEATHER_API_KEY: <base64-encoded-openweather-key>
|
||||
GEMINI_API_KEY: <base64-encoded-gemini-key>
|
||||
GCS_SERVICE_ACCOUNT_KEY_JSON: <base64-encoded-gcs-key-json>
|
||||
@ -1,5 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@types/js-cookie": "^3.0.6"
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@types/js-cookie':
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
|
||||
packages:
|
||||
|
||||
'@types/js-cookie@3.0.6':
|
||||
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@types/js-cookie@3.0.6': {}
|
||||
Loading…
Reference in New Issue
Block a user