Skip to content

Commit 54f0d8b

Browse files
authored
Merge pull request #34 from hasanpeal/develop
Docker compose added
2 parents 6af3d98 + 91ef182 commit 54f0d8b

File tree

20 files changed

+370
-11
lines changed

20 files changed

+370
-11
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,8 @@ obj/
1919
.idea/
2020
appsettings.Development.json
2121
appsettings.Production.json
22-
appsettings.Staging.json
22+
appsettings.Staging.json
23+
24+
# Docker
25+
docker-compose.override.yml
26+
.docker/

README.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,192 @@ npm run dev
793793

794794
---
795795

796+
## 🐳 Docker Setup
797+
798+
The project includes a complete Docker setup with hot reload for both frontend and backend, making it easy to run the entire application with a single command.
799+
800+
### Prerequisites
801+
802+
- **Docker** and **Docker Compose** installed
803+
- **`.env` file** created in the root directory (see setup below)
804+
805+
### Quick Start
806+
807+
1. **Create a `.env` file** in the root directory of the project.
808+
809+
**Option A: Copy from `appsettings.development.json`**
810+
811+
If you already have `server/appsettings.development.json` configured, you can create the `.env` file by converting the JSON structure to environment variables. Use double underscores (`__`) for nested configuration keys.
812+
813+
**Option B: Create manually**
814+
815+
The `.env` file should contain all environment variables matching the structure of `server/appsettings.development.json`. Use double underscores (`__`) for nested configuration keys.
816+
817+
**Example `.env` file:**
818+
819+
```bash
820+
# Database Connection String
821+
ConnectionStrings__Default=User Id=postgres.xxx;Password=xxx;Server=xxx;Port=5432;Database=postgres
822+
823+
# JWT Configuration
824+
Jwt__Issuer=http://localhost:3000
825+
Jwt__Audience=http://localhost:3001
826+
Jwt__SigningKey=your-secret-signing-key-here
827+
Jwt__AccessTokenMinutes=15
828+
Jwt__RefreshTokenDays=30
829+
830+
# SendGrid Configuration
831+
SendGrid__ApiKey=SG.xxx
832+
SendGrid__FromEmail=support@eloomen.com
833+
SendGrid__FromName=Eloomen
834+
SendGrid__AdminEmail=your-admin-email@example.com
835+
836+
# App Configuration
837+
App__BaseUrl=http://localhost:3001
838+
App__EmailVerificationPath=/verify-email
839+
App__DeviceVerificationPath=/verify-device
840+
App__PasswordResetPath=/reset-password
841+
App__VerificationCodeExpiration__EmailVerificationMinutes=1440
842+
App__VerificationCodeExpiration__DeviceVerificationMinutes=60
843+
App__VerificationCodeExpiration__PasswordResetMinutes=60
844+
845+
# S3 / Cloudflare R2 Configuration
846+
S3__BucketName=eloomen-dev
847+
S3__BaseUrl=https://xxx.r2.cloudflarestorage.com
848+
S3__Endpoint=https://xxx.r2.cloudflarestorage.com
849+
S3__AccessKeyId=xxx
850+
S3__SecretAccessKey=xxx
851+
852+
# Frontend Configuration
853+
NEXT_PUBLIC_API_URL=http://localhost:3000/api
854+
```
855+
856+
**Important Notes:**
857+
858+
- The `.env` file is already in `.gitignore` and will not be committed to the repository
859+
- Variable names use `__` (double underscore) for nested configuration (e.g., `ConnectionStrings__Default`, `Jwt__Issuer`)
860+
- Copy values from `server/appsettings.development.json` and convert the JSON structure to environment variable format
861+
- For nested objects, use `__` to separate levels (e.g., `App__VerificationCodeExpiration__EmailVerificationMinutes`)
862+
863+
2. **Start all services** with Docker Compose:
864+
865+
```bash
866+
docker-compose up
867+
```
868+
869+
This will:
870+
871+
- Build and start both frontend and backend services
872+
- Enable hot reload for both services (changes are reflected immediately)
873+
- Expose frontend on http://localhost:3001
874+
- Expose backend on http://localhost:3000
875+
- Automatically run database migrations on backend startup
876+
- Load all environment variables from the `.env` file
877+
878+
### Services
879+
880+
#### Backend (ASP.NET Core)
881+
882+
- **Port**: 3000
883+
- **Hot Reload**: Enabled via `dotnet watch`
884+
- **Environment**: Development
885+
- **Database**: Automatically runs migrations on startup
886+
- **Swagger**: Available at http://localhost:3000/swagger
887+
888+
#### Frontend (Next.js)
889+
890+
- **Port**: 3001
891+
- **Hot Reload**: Enabled via Next.js dev mode
892+
- **API URL**: http://localhost:3000/api
893+
894+
### Docker Commands
895+
896+
```bash
897+
# Start services
898+
docker-compose up
899+
900+
# Start in detached mode (background)
901+
docker-compose up -d
902+
903+
# Stop services
904+
docker-compose down
905+
906+
# Rebuild after dependency changes
907+
docker-compose build
908+
docker-compose up
909+
910+
# View logs
911+
docker-compose logs -f
912+
913+
# View logs for specific service
914+
docker-compose logs -f backend
915+
docker-compose logs -f frontend
916+
```
917+
918+
### Hot Reload
919+
920+
Both services support hot reload out of the box:
921+
922+
- **Backend**: Changes to `.cs` files automatically trigger `dotnet watch` to rebuild and restart
923+
- **Frontend**: Changes to `.tsx`, `.ts`, and `.css` files are automatically reflected in the browser
924+
925+
Source code is mounted as volumes, so you can edit files directly and see changes immediately.
926+
927+
### Environment Variables
928+
929+
All environment variables are loaded from the `.env` file in the root directory. The `docker-compose.yml` uses `env_file: - .env` to automatically load all variables into both services.
930+
931+
**Key Points:**
932+
933+
- The `.env` file must be created in the root directory (same level as `docker-compose.yml`)
934+
- Variable names must match the structure of `appsettings.development.json` using `__` for nesting
935+
- The `.env` file is already in `.gitignore` and will not be committed to the repository
936+
- Both backend and frontend services read from the same `.env` file
937+
- Environment variables override `appsettings.development.json` when set
938+
939+
**Converting from `appsettings.development.json` to `.env`:**
940+
941+
| JSON Structure | Environment Variable |
942+
| --------------------------------------------------------- | ----------------------------------------------------------- |
943+
| `ConnectionStrings.Default` | `ConnectionStrings__Default` |
944+
| `Jwt.Issuer` | `Jwt__Issuer` |
945+
| `App.VerificationCodeExpiration.EmailVerificationMinutes` | `App__VerificationCodeExpiration__EmailVerificationMinutes` |
946+
947+
**Quick Reference:**
948+
949+
- Replace dots (`.`) with double underscores (`__`)
950+
- Keep the same structure and nesting
951+
- All string values should be unquoted
952+
- Copy exact values from `appsettings.development.json`
953+
954+
### Troubleshooting
955+
956+
#### Services won't start
957+
958+
- Ensure Docker and Docker Compose are installed and running
959+
- Check that all required environment variables are set in `.env`
960+
- Verify ports 3000 and 3001 are not already in use
961+
962+
#### Hot reload not working
963+
964+
- Ensure source code volumes are properly mounted (check `docker-compose.yml`)
965+
- Try rebuilding containers: `docker-compose build --no-cache`
966+
967+
#### Database connection issues
968+
969+
- Verify `ConnectionStrings__Default` in `.env` is correct
970+
- Check that your database is accessible from Docker containers
971+
- For local PostgreSQL, use `host.docker.internal` instead of `localhost`
972+
- Ensure the connection string format matches: `User Id=xxx;Password=xxx;Server=xxx;Port=5432;Database=postgres`
973+
974+
#### Frontend can't connect to backend
975+
976+
- Verify `NEXT_PUBLIC_API_URL` in `.env` matches backend URL
977+
- Check that both containers are on the same Docker network
978+
- Ensure backend is running and accessible on port 3000
979+
980+
---
981+
796982
## 🔄 CI/CD Pipeline
797983

798984
**GitHub Actions Workflow:**

client/.dockerignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
node_modules/
2+
.next/
3+
.git/
4+
.gitignore
5+
.env*.local
6+
coverage/
7+
.nyc_output/
8+
*.log
9+
.DS_Store
10+
*.swp
11+
*.swo
12+
*~
13+
.vscode/
14+
.idea/
15+
dist/
16+
build/
17+
*.md
18+
README.md
19+

client/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ yarn-error.log*
3939
# typescript
4040
*.tsbuildinfo
4141
next-env.d.ts
42+
43+
# Docker
44+
.docker/

client/Dockerfile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
FROM node:20-alpine
2+
3+
WORKDIR /app
4+
5+
# Copy package files and install dependencies
6+
COPY package.json package-lock.json* ./
7+
RUN npm ci
8+
9+
# Copy the rest (source code will be mounted as volume in docker-compose)
10+
COPY . .
11+
12+
ENV NODE_ENV=development
13+
ENV NEXT_TELEMETRY_DISABLED=1
14+
15+
# Expose port
16+
EXPOSE 3001
17+
18+
# Run dev server with hot reload
19+
CMD ["npm", "run", "dev"]
20+

client/app/accept-invite/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ function AcceptInviteContent() {
131131
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
132132
></path>
133133
</svg>
134-
<p className="mt-4 text-slate-400">Processing invitation...</p>
134+
<p className="mt-4 text-slate-400">Processing invitation</p>
135135
</div>
136136
</div>
137137
);

client/app/account/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ export default function AccountPage() {
3434
const [activeTab, setActiveTab] = useState<Tab>("profile");
3535
const [devices, setDevices] = useState<UserDevice[]>([]);
3636
const [logs, setLogs] = useState<AccountLog[]>([]);
37-
const [loading] = useState(true);
3837
const [devicesLoading, setDevicesLoading] = useState(false);
3938
const [logsLoading, setLogsLoading] = useState(false);
4039
const [editingField, setEditingField] = useState<"username" | "email" | null>(
@@ -236,7 +235,7 @@ export default function AccountPage() {
236235
.replace(/^./, (str) => str.toUpperCase());
237236
};
238237

239-
if (isLoading || loading) {
238+
if (isLoading) {
240239
return (
241240
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-indigo-950/50 flex items-center justify-center">
242241
<div className="text-center">

client/app/components/ContactModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ export default function ContactModal({ isOpen, onClose, isPublic = false }: Cont
202202
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
203203
></path>
204204
</svg>
205-
Sending...
205+
Sending
206206
</span>
207207
) : (
208208
"Send Message"

client/app/components/DeleteItemModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export default function DeleteItemModal({
101101
disabled={loading}
102102
className="flex-1 px-4 py-3 bg-red-500 text-white font-semibold rounded-lg hover:bg-red-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
103103
>
104-
{loading ? "Deleting..." : "Delete"}
104+
{loading ? "Deleting" : "Delete"}
105105
</button>
106106
</div>
107107
</div>

client/app/components/DeleteVaultModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export default function DeleteVaultModal({
7575
disabled={loading}
7676
className="flex-1 px-4 py-3 bg-red-500 text-white font-semibold rounded-lg hover:bg-red-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
7777
>
78-
{loading ? "Deleting..." : "Delete Vault"}
78+
{loading ? "Deleting" : "Delete Vault"}
7979
</button>
8080
</div>
8181
</div>

0 commit comments

Comments
 (0)