Narciss CRM
Production-grade operating platform for flower retail
Django, PostgreSQL, Celery, Docker, CRM, ERP, POS and multichannel messaging
Technical product article based on live production code and runtime state
Flower retail CRM, ERP and production system architecture
$ docker compose -f docker/docker-compose.yml ps
SERVICE STATUS PORTS
web Up 3 hours 8000/tcp
db Up 2 weeks (healthy) 5432/tcp
redis Up 2 weeks 6379/tcp
celery_worker Up 3 hours 8000/tcp
celery_beat Up 3 hours 8000/tcp
telegram-bot Up 3 hours 8000/tcp
nginx Up 3 hours 80/tcp, 443/tcp
$ docker compose -f docker/docker-compose.yml exec web python manage.py check
System check identified no issues (0 silenced).Overview
Live production CRM and ERP platform
Narciss CRM is not a narrow customer database and not a generic order tracker. It is a production CRM and operating platform for a flower business, built around the daily work of sales, florists, couriers, managers, customers, online orders, warehouse documents, messaging channels and external integrations.
The reviewed production system runs as a Django 5 application with PostgreSQL, Redis, Celery, Gunicorn and Nginx. The operator interface is mostly server-rendered with Django templates, HTMX-style partial updates, Alpine-style local interactivity and focused JavaScript where operational screens need richer behavior.
The important part is scope. The codebase combines CRM, order lifecycle, stock control, bouquet recipes, supplier documents, delivery dispatching, POS surfaces, storefront flows, analytics, marketing, multichannel messaging, API access and integration control planes. In practice, Narciss CRM is closer to a business operating system for flower retail than to a simple CRM module.
Product Model
Customer, order, stock and delivery loop
The core product model is built around a flower retail operation where customer communication, order intake, assembly, stock reservation, delivery and payment are connected.
Customers carry identity data, contact channels, preferences, memorable dates, bonus balance, responsible staff, avatar data and links to Telegram, VK, MAX, Avito and other channel-shaped sources. Separate contact points, consent records, recipients, addresses and complaint records make the customer surface operational rather than purely informational.
Orders are the main business axis. An order can originate from CRM, storefront, messenger, external API or integration intake. It contains status, pipeline stage, customer, store, recipient, delivery details, items, custom bouquet data, substitutions, responsible users, florist assignment, courier assignment, payment state and public token.
- Customer identity influences messenger, intake and order history.
- Orders can carry bouquet recipes, variants, custom components and substitutions.
- Delivery has its own operational lane with zones, courier shifts and audited status logs.
- Store, legal entity and retail point models move the system toward multi-store operation.
Main Workspace
Dense operator screens instead of marketing pages
Narciss CRM is organized around dense operator workspaces. The interface keeps lists, filters, partial updates, modal actions and context panels close together so operators can do real work without losing state.
The florist flow is especially business-specific. Assembly is not treated as an abstract manufacturing module. It is modeled through order status and pipeline stages: paid order, transferred to florists, taken into assembly, assembled and ready for courier search, then courier assignment and delivery.
- customers and customer detail workspaces
- order list, board, calendar and intake screens
- florist tablet screens for assembly work
- delivery management and courier-facing flows
- inventory procurement, warehouse, sales and settlement screens
- analytics, P&L, marketing, messenger, integrations and POS surfaces
Orders And Fulfillment
The business axis where product domains converge
An order can be created manually, through a showcase checkout, from a messenger conversation, from intake data, or through external API flows. It can contain bouquet recipes, variants, custom bouquet items, product substitutions and delivery metadata.
The pipeline system is configurable through order pipeline stages and loss reasons. This lets the business shape its own sales and fulfillment process while preserving canonical order states needed by code, reporting and downstream services.
Assembly metadata from bouquet recipes, such as estimated assembly minutes and complexity, can be carried into order items. That gives the platform a path toward workload planning and florist incentive calculation.
Inventory And Recipe System
Domain depth for perishable retail
Inventory is one of the strongest signals that Narciss CRM is a domain product. It tracks product categories, units, products, variants, barcode ownership, locations, batches, movements, reservations, prices and daily snapshots.
Bouquet recipes are first-class. A recipe can contain components, packaging, labor cost, margin, variants, assembly time, assembly complexity, dimensions, photos, Tilda external identifiers and publication flags.
Storefront publication is connected to inventory. Bouquet recipes can be publication-requested and effectively published only when required components are available. This matters in flower retail, where free stock changes quickly and online availability must follow operational reality.
- supplier orders, bills, payments and returns
- incoming invoices, allocations and stock receipts
- markdown acts, inventory acts, regrade acts and transfer acts
- internal demands, closed periods, import runs and document events
Multichannel Messenger
Messaging as part of fulfillment, not a separate inbox
The messaging layer is historically named around WhatsApp, but production code shows a multichannel conversation system. The shared conversation model supports Wappi/WhatsApp, Telegram, Telegram bot, MAX, MAX bot, VK, Avito, HH, SMS and webchat-shaped channels.
The messenger is connected to customers, stores, orders and tasks. A thread can be linked to a customer, assigned, marked read, moved through conversation status, used to create tasks, used to create or link customer records, and used for outbound messages.
Media access is routed through backend-controlled messenger endpoints rather than being treated as public static files by default. Messages from different providers can appear in the same operator experience without reducing every channel to a phone number.
Integrations
Control plane and runtime plane
The integration layer is deliberately split between control plane and runtime plane. The integrations hub exposes configuration surfaces for Wappi, YooKassa, Telegram, VK, MoySklad, Email, MAX, Amobit AI Pro, API keys and outbound webhooks.
Runtime code can live in WhatsApp, Telegram bot, integrations, MoySklad, payments, webhooks, external API or developer platform modules. Many integration configs are moving toward per-store resolution, including YooKassa, Tilda, VK, Telegram bot, MAX, MoySklad and Email.
The external API has its own idempotency model for order creation. API keys store hashes and prefixes rather than raw keys, and idempotency records connect request keys to endpoint behavior, order records and response status.
- Wappi/WhatsApp and shared messenger profiles
- Telegram bot runtime and webhook failure journaling
- MAX bot runtime and profile binding
- VK callbacks and provider identity handling
- YooKassa payments, MoySklad sync, Tilda intake and outbound webhooks
- developer platform apps, installations, access tokens and webhooks
Store, Legal Entity And Retail Layer
From single-store CRM to store-aware operating platform
Production code shows a clear transition from a single-store CRM into a store-aware operating platform. The network layer defines legal entities, stores, user-store assignments, retail points and retail sale documents.
Retail points add the store-floor dimension: cash registers, inventory locations, cashiers, receipt behavior, discount rules, offline behavior, product creation policies, order handoff and prepayment rules.
This matters because flower operations often expand from one location to several branches, legal entities or countries. Store links already appear on orders, payments, inventory locations, delivery zones, messenger profiles, conversations, integration configs and marketing broadcasts.
POS And Fiscal Workflows
Retail counter state and fiscal boundaries
The POS subsystem is designed for real retail counter work. Production models include workstations, POS sessions, suspended carts, device events, sync batches, checkout records and bouquet assembly records.
Payments are modeled separately from orders and can point to stores, cash registers, counterparties, POS sessions, allocations and fiscal operations. Cash register shifts and operations track open/close state, operation type, request payload, response payload and error messages.
The Armenia fiscalization path is being separated through a dedicated gateway boundary. The monolith remains the source of business events and operator state, while country-specific fiscal protocol execution can live outside the core Django application.
API Architecture
Internal, external and platform contracts
Narciss CRM exposes several API layers. The internal API uses DRF routers for customers, orders, product batches, legacy flower batches, bouquet recipes and delivery zones, plus product-specific summary routes for prices, movements, reservations and batches.
The external API under /api/v1/external/ is designed for outside systems and storefront-style integrations. It includes catalog list/detail, external order creation, Tilda form ingestion, Tilda order ingestion and order status style endpoints.
The platform API under /api/platform/v1/ supports developer app concepts: app manifests, installations, authorization codes, access tokens, refresh tokens and webhooks. This suggests the product is becoming a platform that can host or authorize additional apps.
Background Jobs
Celery is part of production, not a placeholder
The production Compose stack runs a Celery worker, Celery Beat, Redis and django-celery-beat. Scheduled jobs include customer avatar synchronization, expiring batch checks, memorable date checks, scheduled broadcast dispatch, MoySklad full sync and operations controller runs.
That tells us where background work belongs: campaigns should not block web requests, stock warnings and date-based marketing should run asynchronously, ERP synchronization is periodic, and operational control loops can run on schedule.
Security And Access Model
Backend-side scoping, hashing and audit trails
Security is visible at several layers. Session-authenticated operator routes are protected by login-required middleware, Django sessions, CSRF protection, clickjacking protection, custom CSP middleware and django-axes login lockout behavior.
External API safety includes API-key authentication, explicit permissions, throttling, idempotency keys, allowed origins and key storage using hash/prefix/last4 style fields. Integration secrets are kept in backend config models instead of being exposed to normal operator clients.
Store scoping also matters for security. User-store assignments constrain multi-store access, and active-store middleware makes store context available consistently across views.
Why The Architecture Fits Flower Retail
Business constraints mapped into software boundaries
Flower retail has constraints that generic CRMs rarely model well. Orders often start in messengers, gift recipient and buyer are different people, stock is perishable and location-bound, substitutions are normal, assembly work is real labor, delivery timing matters, and storefront publication must follow stock reality.
Narciss CRM maps directly to those constraints. It connects customer identity, channel communication, order creation, bouquet recipe composition, inventory reservation, florist assembly, delivery and integration sync in one operational loop.
- a message can become an order
- an order consumes recipe stock
- assembly creates florist work
- delivery closes the operational chain
- integrations keep storefronts, messengers, payments and external systems connected
Current Status
Live system with production-shaped data
Narciss CRM is currently a live Django-based operating platform for a flower business. The reviewed runtime confirms populated production data across stores, legal entities, customers, products, bouquet recipes, orders, chat threads, messages and integration profiles.
The strongest product idea is that customer communication, order creation, stock availability, bouquet composition, assembly work, delivery and external integrations are not separate tools. They are one operational loop.
class ExternalOrderCreateView(ExternalAPIViewMixin, generics.CreateAPIView):
serializer_class = ExternalOrderCreateSerializer
endpoint_name = "external_order_create"
def _build_request_hash(self, data: dict) -> str:
normalized = _normalize_idempotency_payload(data)
payload = json.dumps(
normalized,
sort_keys=True,
separators=(",", ":"),
ensure_ascii=False,
)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()