P1 Foundation + IPAM — Phase 1 Complete (v0.1.0)#22
Merged
fray-cloud merged 64 commits intomainfrom Mar 22, 2026
Merged
Conversation
- Set up uv workspace with shared library and 5 service packages (ipam, auth, tenant, event, webhook) - Each service follows DDD layer structure (domain, application, infrastructure, interface) - Initialize Next.js 16 frontend with TypeScript, Tailwind CSS, App Router - Add ruff for Python linting/formatting with pre-commit hooks - Add GitHub Actions CI for Python lint/test and frontend lint - Add nginx config, .gitignore, version files (.python-version, .node-version) Resolves #2 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Base Dockerfile with multi-stage dev/prod targets - Per-service Dockerfiles (prod) and Dockerfile.dev (dev with hot reload) - Infrastructure compose: PostgreSQL (5 DBs), Kafka KRaft, Redis, Nginx - Per-service compose files with complete dev/prod separation - Root compose with include (dev includes dev only, prod includes prod only) - Makefile for command standardization (extended set) - Environment variable management (.env.example, .env.dev) - Nginx config with per-service upstream routing and WebSocket support Resolves #3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Entity base class (Pydantic, id/created_at/updated_at) - ValueObject base class (frozen Pydantic for immutability) - Repository abstract base class (async find_by_id/save/delete) - DomainService marker base class - Domain exception hierarchy: DomainError, EntityNotFoundError, BusinessRuleViolationError, AuthorizationError, ConflictError, ValidationError, InfrastructureError Part of #4 (section 3.4) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Command/Query base classes (frozen Pydantic models) - CommandHandler/QueryHandler abstract base classes (async, generic return) - CommandBus/QueryBus with explicit type mapping registration - Dispatch raises ValueError for unregistered command/query types Part of #4 (section 3.1) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DomainEvent base class (frozen Pydantic, auto event_type via __init_subclass__)
- AggregateRoot with convention-based _apply_{EventName} dispatch
- EventStore ABC with optimistic concurrency (expected_version)
- PostgresEventStore implementation (SQLAlchemy async, JSONB payload)
- StoredEvent/StoredSnapshot SQLAlchemy models (separate DeclarativeBase)
- SnapshotStrategy (configurable every N events)
- Snapshot support (to_snapshot/from_snapshot on AggregateRoot)
Part of #4 (section 3.2)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EventSerializer with registry-based DomainEvent deserialization - KafkaEventProducer (aggregate_id as key for partition ordering) - KafkaEventConsumer with manual commit and Dead Letter Queue support - Context manager support for producer lifecycle Part of #4 (section 3.3) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CustomFieldDefinition with FieldType enum and validation - CustomFieldValidator for type checking, choices, and regex validation - Tag model (name, slug, color) - SQLAlchemy models: CustomFieldDefinitionModel, TagModel, TagAssignmentModel - CustomFieldMixin (JSONB column + GIN index) for entities - Filtering utilities for custom fields and tags - Generic FK pattern (content_type + object_id) for cross-service tags Part of #4 (section 3.5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- TenantMiddleware (X-Tenant-ID header extraction) - CorrelationIdMiddleware (X-Correlation-ID generation/propagation) - Pagination: OffsetParams/Page + CursorParams/Page with base64 cursor encoding - Filtering: FilterOperator enum + apply_filters for SQLAlchemy queries - Sorting: SortParam + apply_sorting for SQLAlchemy queries - RFC 7807 Problem Details error responses with DomainError → HTTP status mapping - OpenAPI schema customization utility Part of #4 (section 3.6) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Tenant entity with create/suspend/mark_deleted/update_settings - TenantStatus (active/suspended/deleted), TenantSettings, TenantDbConfig - Domain events: TenantCreated, TenantSuspended, TenantDeleted - TenantRepository interface with find_by_slug and find_all Part of #5 (section 4.1) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CreateTenantCommand/Handler with DB provisioning and Kafka events - SuspendTenantCommand/Handler, DeleteTenantCommand/Handler - UpdateTenantSettingsCommand/Handler - GetTenantQuery/Handler, ListTenantsQuery/Handler - TenantDTO for read model (hides db_config credentials) Part of #5 (section 4.2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PostgresTenantRepository (SQLAlchemy async, merge for upsert) - TenantModel (tenants table with JSONB settings/db_config) - TenantDbProvisioner (CREATE DATABASE + programmatic Alembic) - TenantDbManager (dynamic engine cache per tenant) - Database helper (async engine + session factory) - Settings (pydantic-settings) - Alembic setup for tenant service DB (001_create_tenants_table) - Alembic scaffold for per-tenant DBs (empty, ready for service migrations) - Updated pyproject.toml with asyncpg, alembic, pydantic-settings deps Part of #5 (section 4.3) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- FastAPI app with lifespan (DB, Kafka producer, provisioner, DB manager)
- REST endpoints: POST/GET/PATCH/DELETE /tenants, POST /tenants/{id}/suspend
- Per-request CommandBus/QueryBus wiring via FastAPI dependencies
- Request/response schemas with slug validation (^[a-z0-9-]+$)
- CorrelationIdMiddleware and DomainError exception handler
Resolves #5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auth Service for the CMDB platform implementing local authentication, authorization, and API token management as defined in issue #6. Domain: User, Role, Group, APIToken aggregates with Permission VO Application: CQRS with 12 commands and 7 queries Infrastructure: bcrypt hashing, RS256 JWT with JWKS endpoint, Redis token blacklist, login rate limiting, PostgreSQL repositories Interface: 17 REST endpoints across 5 routers (auth, users, roles, api-tokens, permissions) Deferred: SSO (OIDC/SAML), MFA (TOTP), email verification Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… rate limiting Nginx API Gateway for the CMDB platform as defined in issue #7. - URL versioning: /api/v1/ prefix for all service endpoints - JWT validation via auth_request subrequest to Auth Service /auth/validate - Public endpoints (login, register, refresh, JWKS) bypass auth - Rate limiting: IP-based 30r/s with burst=50 (limit_req_zone) - CORS: map-based origin matching (localhost dev + *.cmdb.io prod) - SSL/TLS: self-signed cert support (443 + 80→443 redirect) - JSON access logging with correlation_id - Auth Service additions: GET /auth/validate, GET /health endpoints Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nge Log Central Event Service for the CMDB platform as defined in issue #8. - Kafka Consumer with regex pattern subscription (*.events) - Generic event storage: raw JSON payload without deserialization - stored_events table: aggregate_id, event_type, version, payload (JSONB) - change_logs table: aggregate_id, action, user_id, tenant_id metadata - REST API: event stream replay, changelog by aggregate/type/tenant - Auto-extraction of aggregate_type and action from event_type strings - DLQ support for failed message processing - Alembic migration for stored_events + change_logs tables Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…cing pattern IPAM Core Domain for the CMDB platform as defined in issue #9. Core Aggregates (AggregateRoot pattern with event sourcing): - Prefix: IPv4/IPv6 subnet management with hierarchical structure - IPAddress: Individual IP address management with VRF scoping - VRF: Virtual Routing and Forwarding domains with Route Distinguisher - VLAN: IEEE 802.1Q VLAN management with VLANId(1-4094) validation Value Objects: PrefixNetwork (CIDR validation, contains()), IPAddressValue, VLANId, RouteDistinguisher, Status enums Domain Services: PrefixUtilization, AvailablePrefix, IPAvailability Fix: shared DomainEvent.__init_subclass__ → __pydantic_init_subclass__ to preserve subclass fields during model rebuild 338 unit tests (pytest) covering all aggregates, VOs, and services Deferred: IPRange, RIR/ASN, FHRP Group, Service (후속 이터레이션) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d refactoring - Extract TenantDbManager to shared/db for cross-service reuse - Add external session support to PostgresEventStore for transactional consistency - Add custom_fields, tags to all IPAM aggregates and events - Add vlan_id to Prefix aggregate for VLAN-to-Prefix linking - Create IPRange, RIR, ASN, FHRPGroup aggregates with event sourcing - Add new value objects: IPRangeStatus, ASNumber, FHRPProtocol, FHRPAuthType - Add repository interfaces for new aggregates - Add 118 new domain tests (456 total, all passing) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 28 command classes for 8 aggregates (Prefix, IPAddress, VRF, VLAN, IPRange, RIR, ASN, FHRPGroup) - Add 28 command handlers using EventStore + Read Model pattern - Add Read Model repository interfaces for each aggregate - Implement IP duplicate check (VRF scope) in CreateIPAddressHandler - All handlers: EventStore.append → ReadModel upsert → Kafka publish Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 20 query classes for 8 aggregates (Get/List + Prefix specials) - Add 20 query handlers reading from Read Model repositories - Add domain service query handlers (utilization, available prefixes/IPs) - Add 8 DTOs with custom_fields, tags, timestamps Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 8 BulkCreate commands and handlers (per-aggregate) - Add SQLAlchemy Read Model tables (8 tables) with Alembic migration - Add PostgreSQL Read Model repository implementations - Add Settings, Database infrastructure - Add FastAPI routers for all 8 aggregates with CRUD + Bulk + special endpoints - Add request/response schemas - Add main.py with lifespan (EventStore, Kafka, middleware) - Prefix-specific: children, utilization, available-prefixes, available-ips Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hot on append - Add PostgresEventStore.load_aggregate() that loads snapshot first, then replays only newer events - Add optional aggregate param to append() for automatic snapshot saving via SnapshotStrategy - Refactor all IPAM Update/ChangeStatus/Delete command handlers to use load_aggregate() + aggregate= pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ection - IPAMEventProjector handles all 28 event types with direct SQL updates (no aggregate reconstruction) - Created → INSERT/upsert, Updated → UPDATE changed columns, Deleted → is_deleted=true, StatusChanged → UPDATE status - KafkaEventConsumer runs as background task in FastAPI lifespan (group_id: ipam-projector) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- RedisCache with get_json/set_json/invalidate_prefix_utilization (TTL 300s) - GetPrefixUtilizationHandler checks cache before computing, stores result after - Event projector invalidates cache on prefix Created/Updated/StatusChanged/Deleted events - Redis connected/closed in FastAPI lifespan, passed to router via app.state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CrossServiceConsumer listens to dcim.events and tenancy.events topics - Handlers log received events (no-op until Phase 2) - No lifespan integration — code-only preparation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- RouteTarget: name (RD format), tenant_id, description, custom_fields, tags - VLANGroup: name, slug, min_vid/max_vid range validation (1-4094) - Service: name, protocol (tcp/udp/sctp), ports validation (1-65535), ip_addresses - Add ServiceProtocol StrEnum value object - Add 9 domain events (Created/Updated/Deleted × 3) - Add comprehensive tests for all 3 aggregates (52 new tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add import_targets/export_targets (list[UUID]) to VRF domain model - Extend VRFCreated/VRFUpdated events with target fields - Update create(), update(), snapshot, and event handlers - Add 8 tests for route target functionality Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IPRangeUtilizationService calculates utilization as used_ips / total_range - GetIPRangeUtilizationQuery + handler with read model integration - Add find_ips_in_range() to IPAddressReadModelRepository - 6 tests for utilization calculation (IPv4, IPv6, edge cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…VLANGroup, Service - CQRS commands, handlers, queries, DTOs for 3 new aggregates (12 command handlers, 6 query handlers) - Read model tables + Postgres repositories for RouteTarget, VLANGroup, Service - Event projector handlers for 9 new event types - VRF infrastructure updated for import_targets/export_targets (models, repository, projector, DTO, commands) - Alembic migration 002: new tables + VRF columns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…afka consumer - WebhookDeliveryService: httpx POST with HMAC-SHA256 signing (X-Webhook-Signature) - RetryManager: Redis sorted set queue with exponential backoff (10s→1h, max 5 retries) - WebhookDispatcher: orchestrates delivery → logging → retry scheduling - WebhookConsumerWorker: Kafka *.events pattern, tenant-scoped matching, Redis cache - RetryWorker: 5s polling for due retries, re-dispatches via dispatcher Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 7 REST endpoints: CRUD + delivery logs + test webhook (ping payload) - Schemas with secret excluded from WebhookResponse - Lifespan manages: Database, DeliveryService, RetryManager, WebhookCache, Consumer, RetryWorker - Health check at GET /health - OpenAPI with tags and description Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Domain tests: Webhook matching (exact, wildcard, inactive, empty), activation, creation (11 tests) - Domain tests: WebhookEventLog creation and defaults (2 tests) - Infrastructure tests: Delivery service with httpx mock (success, failure, timeout, HMAC signature) (4 tests) - Infrastructure tests: RetryManager with fakeredis (schedule, retrieve, max retry, pending count) (4 tests) - Infrastructure tests: Tenant+event matching logic (5 tests) - Add pytest-httpx, fakeredis to dev dependencies Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement comprehensive search and filtering for IPAM service: - Add ILIKE filter operator and UserMiddleware to shared library - Introduce BaseListQuery with common filter fields (description, tags, custom fields, date range, sorting) for all 11 entity types - Extend ReadModelRepository.find_all with sort_params, tag_slugs, custom_field_filters parameters - Add Saved Filters CRUD (model, repository, handlers, router, API) with per-user/entity-type defaults and X-User-ID header auth - Add PostgreSQL full-text search with tsvector generated columns and GIN indexes across all 11 read models - Add global search API (GET /search) with UNION ALL across entities, ts_rank relevance ordering, and entity_type filtering - Add Alembic migration for search_vector columns and saved_filters table Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add journal entry feature to Event Service for user-created notes:
- JournalEntryModel with object_type, object_id, entry_type
(info/success/warning/danger), comment, user_id, tenant_id
- JournalRepository with flexible filtering (object_type, object_id,
tenant_id, user_id, entry_type) and pagination
- POST /journal-entries — create with user_id from X-User-ID header
- GET /journal-entries — list with optional filters
- DELETE /journal-entries/{id} — author-only delete (403 if mismatch)
- UserMiddleware added to Event Service
- Alembic migration 002 for journal_entries table
- Unit tests for schemas, model, and entry_type validation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive data import/export functionality:
- CSV Import: parse CSV → BulkCreate command integration for all
11 entity types, with partial success (errors per row)
- CSV/JSON/YAML Export: read model query → format conversion,
export-specific limit (max 10000), StreamingResponse download
- Jinja2 Export Templates: SandboxedEnvironment for security,
ExportTemplateModel with output_format metadata, CRUD API,
POST /export/{entity_type}/render for custom rendering
- Dependencies: jinja2, pyyaml, python-multipart added
- Alembic migration 004 for export_templates table
- 20 unit tests for CSV parsing, format serialization, entity types
Bulk Edit API was already implemented (PATCH /*/bulk endpoints).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restructure frontend/ as pnpm workspace monorepo: - apps/client — Main IPAM client app (Next.js 16, port 3000) - apps/admin — Admin panel skeleton (Next.js, port 3001) - packages/shared — Shared library: - types/ — 11 IPAM entity types, auth types, common types - lib/api.ts — fetch wrapper with JWT auto-attach and 401 refresh - lib/api-client.ts — typed API functions for all entities - lib/auth.ts — JWT token management (localStorage) - hooks/use-auth.tsx — AuthProvider + useAuth hook Dependencies: @tanstack/react-query, @tanstack/react-table, next-themes, lucide-react added to client app. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- shadcn/ui initialized with Button, Input, Card, Table, Dialog, Select, Badge, Tabs, Sheet, DropdownMenu, Separator, Skeleton, Label, Textarea components - Providers: QueryClientProvider, ThemeProvider (dark mode), AuthProvider - Auth route group: login page (email/password), signup page - Dashboard route group: sidebar navigation (IPAM entities), header (search placeholder, dark mode toggle, user menu) - Auth guard: client-side redirect for unauthenticated users - Dashboard placeholder with stat cards Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full CRUD (list/detail/create) for 4 core entities: - Prefix: network, status badge, VRF, role, inline edit, delete - IP Address: address, dns_name, status, VRF - VRF: name, RD, import/export targets - VLAN: VID, name, group, status, role List-only pages for 7 remaining entities: - IP Ranges, ASNs, RIRs, FHRP Groups, Route Targets, VLAN Groups, Services Reusable components: - DataTable: @tanstack/react-table with pagination, skeleton loading - StatusBadge: color-coded status indicators All pages use TanStack Query for data fetching/mutations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Global Search: Cmd+K command palette with debounced API search, results grouped by entity type, click-to-navigate - Changelog Timeline: vertical timeline with action badges (created/updated/deleted), integrated into Prefix detail tabs - Journal Entries: per-object notes with entry_type badges (info/success/warning/danger), add/delete with mutations - IPAM Dashboard: live summary cards (Prefix/IP/VRF/VLAN counts), recent changes section, loading skeletons Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mock-based tests (run without Docker): - IPAM E2E: Prefix CQRS flow (Create→Event→ReadModel→Query), BulkCreate, Update, Delete with InMemory mocks - Event serialization roundtrip for all 37 IPAM event types - Auth E2E: registration, login, JWT lifecycle, role permissions with real JWTService/BcryptPasswordService - Webhook E2E: event matching (7 cases), delivery with HMAC signature verification via httpx_mock Docker-based tests (@pytest.mark.integration, testcontainers): - IPAM DB: real PostgreSQL CRUD, filtering (status, ILIKE) - Tenant isolation: tenant A/B data separation - Auth DB: user persist/retrieve/delete - Kafka flow: produce/consume with testcontainers Kafka Infrastructure: - testcontainers[postgresql,kafka,redis] added to dev deps - pytest markers: "integration" for Docker tests - asyncio_mode="auto" for IPAM and Auth services Test counts: IPAM 622, Auth 9, Webhook 36, Event 9 (non-integration) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix IPAM pyproject.toml: add missing runtime deps (sqlalchemy, asyncpg, alembic, pydantic-settings, aiokafka, redis) - Fix frontend Dockerfile.dev for monorepo structure - Add frontend/docker-compose.dev.yml at workspace root - Fix nginx depends_on to wait for all services before starting - Switch Kafka image from bitnami/kafka to apache/kafka:3.9.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Merge all docker-compose include files into single root file (Docker Compose v5 cross-file depends_on not supported) - Switch Kafka from bitnami/kafka to apache/kafka:3.9.0 - Fix all DATABASE_URL to use postgresql+asyncpg:// - Add RSA key file mount for Auth service (rsa_private_key_path) - Add DNS resolver to nginx for dynamic upstream resolution - Fix IPAM pyproject.toml missing runtime deps - Fix frontend Dockerfile.dev for monorepo structure - Add nginx resolver directive for Docker DNS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Infrastructure:
- Add DATABASE_URL env override to all 4 alembic env.py files
- Add 4 init containers (profiles: ["init"]) for DB migration
- Add `make dev-init` target
- Auth config: support RSA key file paths (rsa_private/public_key_path)
- Nginx: add public /api/v1/setup/ route
Tenant Service:
- Add GET /setup/status — returns {initialized: bool}
- Add POST /setup/create-tenant — only works when no tenants exist
Frontend:
- Add Setup Wizard page (/setup) with 2-step flow:
Step 1: Create organization (tenant)
Step 2: Create admin account
- AuthGuard checks setup status before auth check
- Add @cmdb/shared/lib/setup.ts API functions
Flow: make dev-build → make dev-up → make dev-init → browser /setup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use `image: cmdb-*:latest` instead of `build:` for init containers (reuse pre-built service images that include alembic files) - Change `make dev-init` from --abort-on-container-exit to sequential `docker compose run --rm` for each init container - Add alembic.ini, alembic/, src/ to all service Dockerfile.dev files - Makefile dev-init: depends on dev-build + dev-up Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- setup.ts: use NEXT_PUBLIC_TENANT_API_URL (default localhost:8003) - api.ts: use NEXT_PUBLIC_API_URL (default localhost:8001 for IPAM) - api.ts: add authApi with NEXT_PUBLIC_AUTH_API_URL (localhost:8002) - auth.ts: use authApi for login/signup/me endpoints - api.ts: request() accepts baseUrl parameter for multi-service support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix CORS: add CORSMiddleware to all 4 backend services (tenant, auth, ipam, event) - Fix auth: getCurrentUser uses JWT decode instead of /auth/me (endpoint doesn't exist) - Fix login: auto-attach tenant_id from localStorage - Fix setup wizard: use direct fetch for register (bypass api wrapper) - Fix error display: handle array detail from FastAPI 422 errors - Fix Makefile: remove broken prod compose reference from clean target - Fix Tenant Dockerfile.dev: include alembic_tenant_db directory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Always show Organization dropdown on login page - Auto-select if tenant_id exists in localStorage - Fetch tenant list from Tenant API on page load - Pass tenant_id to login request Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove direct service port calls (localhost:8001/8002/8003) - Single API_BASE_URL: http://localhost (Nginx port 80) - All paths use /api/v1/ prefix matching Nginx routes - Add HTTP server block to nginx.conf (dev, no SSL required) - Remove authApi/separate base URLs from shared lib - Update login, setup, auth, api-client to use gateway paths API routing: Frontend → Nginx:80 → backend services Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frontend served through Nginx gateway, so API calls use relative paths (/api/v1/*) instead of absolute URLs. This eliminates CORS issues entirely since all requests are same-origin. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nginx: - Remove CORS preflight regex that caught all /api/* (same-origin) - IPAM: /api/v1/ipam/ → /api/v1/ catch-all proxy to ipam/api/v1/ - Add public /api/v1/tenant/tenants for login tenant selector Frontend: - Fix dashboard: changelogApi.list() instead of invalid _recent - Add changelogApi.list() to api-client IPAM: - Increase DB pool_size from 5 to 20, max_overflow 30 - Add pool_pre_ping and pool_recycle to prevent connection exhaustion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Share same DB session between CommandBus and QueryBus in prefix router to ensure flush() data is visible for post-create query - Add session.commit() after command dispatch in create/update/delete - Fix schema import name conflict (BulkUpdatePrefixItem alias) - Increase DB pool_size to 20 with pool_pre_ping and pool_recycle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Session management (all 11 routers):
- Share DB session between CommandBus and QueryBus
- Add session.commit() after command dispatch
Nullable command fields:
- Allow None for custom_fields, tags, import/export_targets,
ports, ip_addresses in all Create commands
- Handlers use `or {}` / `or []` to default None to empty
All 11 entities tested via gateway: ✅
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add eslint.config.mjs to admin app - Fix Python import sorting across all services Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auto-fix import sorting across all services. Resolves CI python-lint failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI workflow: - python-test: run per-service with --package and -m "not integration" - frontend-build: replace placeholder with actual build step Frontend lint fixes: - Remove unused Badge/useState imports - Fix setState inside useEffect in global-search.tsx Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 1 마일스톤 전체 구현. 17개 이슈(#2~#18) 모두 CLOSED.
Backend Services (Python 3.13, FastAPI, DDD+CQRS+ES)
Frontend (Next.js 16 Monorepo)
Infrastructure
make dev-init자동화Testing
Merge 후 작업
v0.1.0태그 + GitHub Release 생성 예정P2 이슈
🤖 Generated with Claude Code