Symfony Backend
Why the api repository exists, which business responsibilities it owns, and how admin and member requests share data.
The api repository provides the newer server-side part of Agapi. It gives
staff, member clients, and approved integrations a consistent way to work with
bookings, fleet, members, payments, messages, files, and reports.
Its purpose is to protect business rules at the server boundary. A screen can hide an invalid choice, but the backend must still reject an unauthorized user, an overlapping booking, a missing company, or an invalid payment request.
Two API applications, one business data model
The Symfony code starts in two contexts:
| Context | Who it serves | Why it is separate |
|---|---|---|
| Admin API | Staff portal and approved service users. | Staff can search broadly, manage settings, run reports, and perform operational changes. |
| Member API | Current member clients. | Members should receive only their own profile/trips and public fleet or support information. |
They share entities, repositories, services, and the same business vocabulary. The member API is deliberately smaller; staff capability must not become member capability just because the underlying code is shared.
flowchart TD
Staff[Staff portal] --> Admin[Admin API /api/v1]
Member[Member client] --> Mobile[Member API /api]
Partner[Approved external system] --> Public[Integration-specific public API]
Admin --> Rules[Shared business rules]
Mobile --> Rules
Public --> Rules
Rules --> Data[(PostgreSQL records)]
Rules --> External[Stripe, messages, files, FMP]What the repository contributes to the product
| Business area | Symfony responsibility |
|---|---|
| Access | Authenticate staff, members, and service/integration callers and apply role, account, region, and location scope. |
| Members | Create and update members, show booking/request context, manage balances, ratings, activity, and newsletter audiences. |
| Fleet | Manage boats, models, places, facilities, checklists, issue categories, issues, service visits, and availability. |
| Bookings | Create and change bookings, protect state changes, record history, serve dashboards, service requests, and linked issues. |
| Booking requests | Keep unresolved demand separate from confirmed reservations and control allowed states. |
| Payments | Create/cancel invoices and subscriptions, select the correct company Stripe account, and apply later webhook results. |
| Communication | Prepare email, SMS, and push work and preserve delivery information. |
| Reports | Answer specific operational and financial questions and create matching exports. |
| Integrations | Exchange booking/availability data with approved external callers and send check-in/out status to fleet monitoring. |
How a request becomes a business change
sequenceDiagram
actor Caller
participant Access as Access check
participant Endpoint as Feature endpoint
participant Rules as Repository/service rules
participant DB as PostgreSQL
participant Provider as Optional external provider
Caller->>Access: identity and request
Access->>Endpoint: allowed caller and scope
Endpoint->>Rules: validated business input
Rules->>DB: read or save current state
opt payment, message, or fleet update
Rules->>Provider: provider request
end
Endpoint-->>Caller: result or clear errorThe order matters. If a database save succeeds and a provider request fails—or the other way around—the operation may need reconciliation rather than a full retry.
Company, account, and location scope
Most shared records carry an account_id, and staff users can also be limited
to regions or locations. Financial operations additionally choose a company.
These scopes solve different problems:
- account keeps tenants and their configuration separate;
- region/location limits operational visibility;
- company selects the legal and payment context.
They should not be substituted for one another.
Access roles
The server recognizes viewer, manager, admin, service, and customer contexts. Admin inherits manager capability; manager inherits viewer and selected service capability. The exact endpoint rule comes from server security and feature code, not from whether a button is visible in the browser.
Data storage in plain language
PostgreSQL stores Agapi's operational history. Many records use normal identity
and account columns plus flexible JSON sections called data and meta.
This supports older and newer code reading the same records, but it also means a number written inside JSON is not automatically a protected database link. When changing stored data, developers must preserve the meaning expected by both repositories.
See Business Data Dictionary for every entity and its purpose.
Feature references
- Payments and Stripe
- Fleet Monitoring Status Updates
- Email, SMS, Push, and Background Delivery
- Complete API Feature Catalogue
Technical reference
The source is under api/symfony. Admin controllers live in
apps/admin/src/Controller, member controllers in apps/mobile/src/Controller,
and shared entities/repositories/services in src. Locally, the admin context is
served on port 80, the member context on 8080, and PostgreSQL on host port
5435 with the checked-in Compose mappings.