Skip to content

Commit 98eaead

Browse files
author
dynamicdev-official
committed
feat: initialize watchdocs project with core UI components and automation workspace layout
1 parent 29429a4 commit 98eaead

3 files changed

Lines changed: 207 additions & 0 deletions

File tree

.dockerignore

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Node dependencies - reinstalled inside the build stage
2+
node_modules
3+
npm-debug.log
4+
yarn-debug.log
5+
yarn-error.log
6+
pnpm-debug.log
7+
8+
# Next.js build artifacts
9+
.next
10+
out
11+
12+
# Version control
13+
.git
14+
.gitignore
15+
.github
16+
17+
# Environments and local config
18+
.env
19+
.env.local
20+
.env.development.local
21+
.env.test.local
22+
.env.production.local
23+
24+
# IDE and OS metadata
25+
.vscode
26+
.idea
27+
.DS_Store
28+
Thumbs.db
29+
30+
# Test and coverage output
31+
coverage
32+
.nyc_output
33+
34+
# Documentation and misc files not needed at runtime
35+
README.md
36+
DEPLOYMENT.md
37+
LICENSE
38+
*.md
39+
!app/**/*.md
40+
41+
# Docker artifacts
42+
Dockerfile
43+
docker-compose.yml
44+
.dockerignore
45+
46+
# Vercel local dev artifacts
47+
.vercel

Dockerfile

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# syntax=docker/dockerfile:1.7
2+
3+
# ---------------------------------------------------------------
4+
# WatchDocs - Multi-stage production image
5+
# Image: watchdocs:1.0.0
6+
# Port: 3355
7+
# Output: Next.js standalone server
8+
# ---------------------------------------------------------------
9+
10+
# ----- Stage 1: dependencies ---------------------------------------
11+
FROM node:20-alpine AS deps
12+
WORKDIR /app
13+
14+
# Enable corepack so pnpm is available without an extra install step
15+
RUN corepack enable
16+
17+
# Copy only lockfiles to maximize Docker layer cache hits
18+
COPY package.json pnpm-lock.yaml* package-lock.json* yarn.lock* ./
19+
20+
# Install dependencies using whichever lockfile is present
21+
RUN \
22+
if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; \
23+
elif [ -f package-lock.json ]; then npm ci; \
24+
elif [ -f yarn.lock ]; then yarn install --frozen-lockfile; \
25+
else pnpm install; \
26+
fi
27+
28+
29+
# ----- Stage 2: build ----------------------------------------------
30+
FROM node:20-alpine AS builder
31+
WORKDIR /app
32+
RUN corepack enable
33+
34+
# Bring in installed modules and source
35+
COPY --from=deps /app/node_modules ./node_modules
36+
COPY . .
37+
38+
# Disable Next.js telemetry at build time
39+
ENV NEXT_TELEMETRY_DISABLED=1
40+
41+
# Build the Next.js app (produces .next/standalone when output: 'standalone')
42+
RUN \
43+
if [ -f pnpm-lock.yaml ]; then pnpm build; \
44+
elif [ -f package-lock.json ]; then npm run build; \
45+
elif [ -f yarn.lock ]; then yarn build; \
46+
else pnpm build; \
47+
fi
48+
49+
50+
# ----- Stage 3: runner (slim production image) --------------------
51+
FROM node:20-alpine AS runner
52+
WORKDIR /app
53+
54+
# Production defaults
55+
ENV NODE_ENV=production
56+
ENV NEXT_TELEMETRY_DISABLED=1
57+
ENV PORT=3355
58+
ENV HOSTNAME=0.0.0.0
59+
60+
# Create a non-root user so the app does not run as root
61+
RUN addgroup --system --gid 1001 nodejs \
62+
&& adduser --system --uid 1001 nextjs
63+
64+
# Copy the public directory (static assets served directly)
65+
COPY --from=builder /app/public ./public
66+
67+
# Copy the standalone server and its required static chunks
68+
# Ownership is assigned to the nextjs user for tighter permissions
69+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
70+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
71+
72+
USER nextjs
73+
74+
EXPOSE 3355
75+
76+
# Lightweight healthcheck - Next.js standalone answers on the root path
77+
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
78+
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:3355/ || exit 1
79+
80+
# server.js is generated by Next.js standalone output
81+
CMD ["node", "server.js"]

docker-compose.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# ---------------------------------------------------------------
2+
# WatchDocs - docker compose stack
3+
# Service : watchdocs
4+
# Image : watchdocs:1.0.0
5+
# Host : watchdocs.dynamicdev.asia
6+
# Port : 3355:3355
7+
# Network : dynamicdev-net (external - shared across the ecosystem)
8+
# ---------------------------------------------------------------
9+
10+
services:
11+
watchdocs:
12+
# Build the image locally from the Dockerfile in this repo
13+
build:
14+
context: .
15+
dockerfile: Dockerfile
16+
# Tag the built image so it can be re-used, pushed, or pulled by name
17+
image: watchdocs:1.0.0
18+
container_name: watchdocs
19+
hostname: watchdocs
20+
restart: unless-stopped
21+
22+
# Host-to-container port mapping (left side = host, right side = container)
23+
ports:
24+
- "3355:3355"
25+
26+
environment:
27+
NODE_ENV: production
28+
PORT: 3355
29+
HOSTNAME: 0.0.0.0
30+
NEXT_TELEMETRY_DISABLED: "1"
31+
# Public URL used for share links, metadata, and absolute URLs
32+
NEXT_PUBLIC_APP_URL: https://watchdocs.dynamicdev.asia
33+
# Reference an existing Postgres container on the same docker network.
34+
# Override these in a local .env file when deploying.
35+
DATABASE_URL: ${DATABASE_URL:-}
36+
TZ: Asia/Bangkok
37+
38+
# Attach to the shared ecosystem network so it can be routed by the
39+
# reverse proxy (Traefik / Nginx Proxy Manager / Caddy) and reach other
40+
# services such as postgres by container name.
41+
networks:
42+
- dynamicdev-net
43+
44+
# Reverse-proxy hints - enable if Traefik is the active edge router
45+
labels:
46+
- "com.dynamicdev.project=watchdocs"
47+
- "com.dynamicdev.version=1.0.0"
48+
- "traefik.enable=true"
49+
- "traefik.http.routers.watchdocs.rule=Host(`watchdocs.dynamicdev.asia`)"
50+
- "traefik.http.routers.watchdocs.entrypoints=websecure"
51+
- "traefik.http.routers.watchdocs.tls.certresolver=letsencrypt"
52+
- "traefik.http.services.watchdocs.loadbalancer.server.port=3355"
53+
- "traefik.docker.network=dynamicdev-net"
54+
55+
# Container-level healthcheck mirrors the one in the Dockerfile so that
56+
# docker compose can flag the service as unhealthy without touching the
57+
# image layer.
58+
healthcheck:
59+
test:
60+
- CMD-SHELL
61+
- "wget --no-verbose --tries=1 --spider http://127.0.0.1:3355/ || exit 1"
62+
interval: 30s
63+
timeout: 5s
64+
start_period: 20s
65+
retries: 3
66+
67+
# Keep logs bounded to avoid filling up the host disk
68+
logging:
69+
driver: json-file
70+
options:
71+
max-size: "10m"
72+
max-file: "5"
73+
74+
networks:
75+
# External means the network must already exist on the host.
76+
# Create it once with: docker network create dynamicdev-net
77+
dynamicdev-net:
78+
external: true
79+
name: dynamicdev-net

0 commit comments

Comments
 (0)