NSS Nexus

Run NSS operations with reliable approvals, attendance, and reporting.

NSS Nexus is a multi-tenant operations platform for colleges running NSS programs across yearly batches. It helps program officers, unit leaders, and volunteers manage activities, registrations, attendance, feedback, notifications, and hours with strong role-based access, offline support, and auditable workflows. The product matters because it replaces fragmented manual coordination with a reliable system that preserves official records and scales across colleges.

Business Goals

  • Reach 30 pilot colleges within 6 months of launch with at least 70% monthly active usage among active batch leaders.
  • Reduce activity approval turnaround time by 50% within 90 days by replacing manual follow-ups and ad hoc approvals.
  • Cut attendance processing time by 60% per event within 3 months through QR and manual session workflows.
  • Achieve 90% notification delivery success for approved activities and attendance reminders within the first release cycle.
  • Maintain under 2% critical write failure rate in production over the first 100,000 transactional operations.

User Goals

  • Let program officers create, approve, and archive activities without spreadsheet tracking.
  • Let unit leaders register volunteers, open attendance sessions, and submit bulk attendance quickly on mobile.
  • Let volunteers see approved activities, register, receive notifications, and submit feedback from one app.
  • Let users keep working offline for reads and queue writes safely when connectivity drops.
  • Provide accurate NSS hours and immutable records that can be trusted during audits and reporting.

Non-Goals

  • Replacing the college’s general ERP or student information system.
  • Building a payment gateway, subscription billing, or monetization engine in V1.
  • Adding webhooks, AI analytics, or a dedicated search engine in the first release.
  • Supporting microservices, Kafka, RabbitMQ, or distributed worker infrastructure in V1.

Program Officer Priya, 38 - Priya manages NSS across one college and multiple batches. She needs dependable approval workflows, permission control, and audit trails so that official records stay accurate and defensible.

Program Officer Priya, 38

  • As a program officer, I want to review and approve activities with clear state transitions, so that only valid events are published to volunteers.
  • As a program officer, I want to suspend or exit memberships when needed, so that access matches real-world NSS participation.
  • As a program officer, I want dashboard summaries of hours, attendance, and approvals, so that I can report progress to leadership quickly.

Unit Leader Arun, 24 - Arun coordinates volunteers for a specific batch and handles attendance on event day. He needs fast mobile workflows that still prevent duplicate or invalid records.

Unit Leader Arun, 24

  • As a unit leader, I want to open an attendance session and generate a QR token, so that volunteers can mark attendance securely.
  • As a unit leader, I want to bulk mark manual attendance, so that I can finish event closeout even when network quality is poor.
  • As a unit leader, I want to see eligible registered members only, so that I do not mark attendance for the wrong batch.

Volunteer Meera, 19 - Meera participates in activities across campus and wants a simple app for discovery, registration, attendance, feedback, and seeing her NSS hours.

Volunteer Meera, 19

  • As a volunteer, I want to see approved activities for my batch, so that I can register for the right events.
  • As a volunteer, I want to receive reminders and attendance notifications, so that I do not miss important events.
  • As a volunteer, I want to view my total hours and participation history, so that I can track my NSS progress.

Identity, tenancy, and access control · High priority

  • The platform must enforce college and batch isolation with membership-based permissions so users only see and change data they are authorized for.
  • Support login, refresh, logout, and logout-all with hashed refresh tokens and multi-device sessions.
  • Resolve tenant scope from authenticated context, not from client-supplied college or batch IDs.
  • Support system roles including SUPER_ADMIN, PROGRAM_OFFICER, UNIT_LEADER, PROJECT_LEADER, and VOLUNTEER.
  • Enforce permission strings such as activity.approve, attendance.mark.manual, and member.suspend.
  • Block access for suspended accounts, suspended colleges, exited memberships, and completed memberships.

Activity lifecycle and registration · High priority

  • Users must be able to create activities, submit them for approval, approve or reject them, and allow volunteers to register only when business rules are satisfied.
  • Activities move through DRAFT, PENDING, APPROVED, REJECTED, and ARCHIVED states only through a lifecycle service.
  • Registration must enforce approved status, open deadline, active membership, and capacity checks atomically.
  • Use idempotency keys for registration and other critical writes to prevent duplicates.
  • Store official NSS hours on the activity as the credited amount, not as derived event duration.
  • Allow activity visibility to vary by state and role, with server-side authorization on every query.

Attendance and session management · High priority

  • Attendance must be tracked through a structured session model that supports QR, Bluetooth, and manual entry while keeping records immutable.
  • Create an ActivitySession with OPEN and CLOSED states to represent the attendance window.
  • Accept QR and Bluetooth only as session discovery or transport, never as trusted attendance authority.
  • Write immutable Attendance records with unique membership, activity, and session constraints.
  • Support bulk manual attendance with transactional submission and clear duplicate handling.
  • Track short-lived AttendanceAttempt records for troubleshooting and security review.

Notifications, outbox, and offline resilience · High priority

  • The system must reliably create notification intent in the same transaction as business changes, then dispatch asynchronously without blocking the user response.
  • Persist Notification and NotificationOutbox records together inside a MongoDB transaction.
  • Use cron-based outbox sweeping in V1, with later upgrade path to BullMQ workers.
  • Deduplicate client-side by notificationId so repeated dispatch attempts do not create duplicate user-visible notifications.
  • Support notification preferences, batch and role targeting, and system-critical overrides.
  • Provide offline read caching and queued pending actions for mobile users, with safe idempotent replay.

Reporting, dashboards, and auditability · Medium priority

  • The product must provide accurate operational dashboards, member history, and immutable audit/security logs for review and compliance.
  • Generate dashboards from derived queries rather than stored totals.
  • Maintain separate immutable audit logs and security event logs.
  • Provide leaderboard views based on official attendance-present hours and sorted business rules.
  • Support cursor pagination for large feeds like notifications, activities, members, and logs.
  • Allow admins to inspect and retry dead-letter notification outbox entries.

First-Time Setup and First Value

  • Install the app and sign in with college credentials or invited account.
  • Validate session, restore any existing membership, and load app configuration.
  • Select the active membership if the user belongs to more than one batch.
  • Show the personalized dashboard, notifications, and next eligible activity.
  • Let the user complete a meaningful action within 2 minutes, such as registering for an approved activity or viewing hours.

1. Login and Membership Selection

  • Users authenticate once, then choose the active college and batch context if they have multiple memberships.
  • If the session is revoked or the account is suspended, force a clear logout and show the correct status screen.
  • If only one active membership exists, skip the picker and go straight to the dashboard.
  • Never allow the client to spoof college or batch context; the server resolves the authoritative tenant scope.

2. Activity Discovery and Approval

  • Volunteers browse approved activities while leaders and officers see drafts, pending reviews, and admin actions.
  • Show only activities allowed by state and role, with DRAFT hidden from volunteers.
  • Handle archived or rejected activities with clear reason labels and restricted actions.
  • Use cursor pagination and local caching to keep feeds fast even with many activities.

3. Registration and Session Readiness

  • Eligible members register for activities and leaders prepare attendance sessions when the event begins.
  • Prevent duplicate registration, late registration, and over-capacity signup with clear error feedback.
  • If the user is offline, queue the registration with an idempotency key and retry safely later.
  • When an activity opens attendance, generate a short-lived session token and display a QR only after the server confirms the session.

4. Attendance Capture and Closeout

  • Leaders mark attendance using QR, Bluetooth, or manual bulk entry, then close the session and finalize records.
  • Reject attendance outside the session window or for already marked members.
  • Mark duplicates, expired attempts, and invalid scans distinctly for troubleshooting.
  • Keep Attendance immutable after commit and store any attempt logs separately.

5. Feedback, Hours, and Notifications

  • After attendance, eligible volunteers submit feedback and view updated NSS hours with related notifications.
  • Only allow feedback for attendees with PRESENT status and active membership.
  • Refresh hours totals from authoritative attendance and activity hours, not from cached client math.
  • Deliver approval, reminder, and system notifications asynchronously and deduplicate them by notificationId.

Power Features and Edge Cases

  • Offline read cache with stale indicators and queued write replay when connectivity returns.
  • Membership suspension, exit, and account suspension flows with session revocation and topic cleanup.
  • Admin retry screen for failed outbox entries and security-event review.
  • Dashboard widgets tailored by permission, batch, and role.
  • Public IDs in URLs and client state for display-safe sharing without exposing database IDs.

Design and Interaction Principles

  • Keep the app simple and task-focused: dashboard first, action cards second, details third.
  • Use strong empty, loading, offline, and error states so the user always knows what is happening.
  • Support fast one-hand mobile workflows for attendance, registration, and feedback.
  • Use accessible contrast, large tap targets, and clear status labels for approvals and attendance windows.
  • Optimize for low-bandwidth environments with local caching and minimal unnecessary refreshes.

Priya used to manage NSS activities through chat messages, spreadsheet approvals, and manual attendance sheets. When a volunteer missed an event or a leader forgot to update hours, it took hours to reconcile records and explain discrepancies to college staff.

With NSS Nexus, Priya creates an activity, submits it for approval, and the system records the decision, notification intent, and audit trail in one transaction. On event day, Arun opens an attendance session, volunteers scan a QR, and the system writes immutable attendance records while updating official hours automatically.

By the end of the month, Priya has a clean dashboard of approvals, attendance, and hours. Volunteers trust the app because their records appear quickly and consistently, and the college gains a reliable operational system instead of a patchwork of manual follow-ups.

User-Centric Metrics

  • 90% of volunteers can find and register for an approved activity within 30 seconds of opening the app.
  • 80% of attendance sessions are closed in under 5 minutes after event start.
  • Reduce duplicate or invalid attendance submissions to below 0.5% of total attendance attempts.
  • Achieve a 4.5/5 average satisfaction score from program officers after the first semester.
  • At least 70% of active volunteers check their hours or notifications monthly.

Business Metrics

  • Convert 30 pilot colleges within 6 months.
  • Reach 60% monthly active usage among enrolled NSS members in participating colleges.
  • Reduce manual coordination time for officers and leaders by at least 40% in 90 days.
  • Maintain 85%+ retention of pilot colleges into the next NSS batch cycle.

Technical Metrics

  • 99.9% API uptime during the academic term.
  • P95 response time under 300 ms for common read endpoints and under 800 ms for transactional writes.
  • Zero critical write dependency on Redis or background workers in V1.
  • No unhandled security-relevant access violations in tenant-isolation tests before launch.

Tracking Plan

  • track user login and membership selection
  • track activity list viewed and activity detail opened
  • track activity registration attempt and registration success or failure
  • track attendance session opened, QR verified, Bluetooth verified, and manual attendance submitted
  • track feedback submitted and feedback rejection reasons
  • track notification delivered, notification opened, and notification marked read
  • track outbox retry, dead-letter creation, and admin retry action

Technical Needs

  • Flutter mobile app with Riverpod state management, Dio networking, Isar local storage, and secure storage for session tokens.
  • Node.js and Express modular monolith backend with Mongoose and MongoDB transactions.
  • JWT access tokens plus hashed refresh tokens and per-device sessions.
  • Transactional outbox pattern with cron-based dispatcher for notifications in V1.
  • Shared contract package for enums, permission keys, error codes, and event names across backend and Flutter.
  • Centralized configuration and validation using Zod and a typed config service.
  • Structured logging and error monitoring with Pino and Sentry on the backend, Crashlytics and Performance on mobile.

Integration Points

  • Firebase Cloud Messaging for push notifications and token/topic management.
  • Firebase Crashlytics and Performance for mobile crash and performance monitoring.
  • Sentry for backend error monitoring and correlation with request IDs.
  • MongoDB Atlas or another managed MongoDB deployment with transaction support.
  • Optional Redis-compatible cache for permission and dashboard acceleration without correctness dependency.

Data Storage & Privacy

  • Store passwords only as strong hashes and refresh tokens only as hashes, never in plaintext.
  • Treat attendance, feedback, audit logs, and security logs as immutable records with retention policies.
  • Keep tenant data isolated by college and batch in every tenant-owned query and endpoint.
  • Support privacy-aware handling of personal profile data such as phone, email, address, and demographics.
  • Design for GDPR and CCPA-style rights where applicable, including minimization, access control, and configurable retention on non-critical logs.

Scalability & Performance

  • Use cursor pagination for feeds that can grow large, such as notifications, members, and audit logs.
  • Cache permissions, dashboard summaries, and leaderboard data temporarily, but always fall back to MongoDB.
  • Avoid blocking HTTP responses on push notifications or other external services.
  • Use atomic claims for outbox dispatch instead of distributed locks or always-on workers.

Potential Challenges

  • Risk: duplicate notifications during retries. Mitigation: persist a unique notification intent, dispatch from outbox rows, and deduplicate client display by notificationId.
  • Risk: tenant leakage between colleges or batches. Mitigation: enforce context-derived scope, add explicit tenant-isolation tests, and never trust client-supplied tenant IDs.
  • Risk: inconsistent attendance due to offline or low-connectivity event venues. Mitigation: queue writes with idempotency keys and validate on the server when network returns.
  • Risk: permission cache staleness after role changes. Mitigation: version permissions and use version-keyed cache invalidation rather than manual cache purges.
  • Risk: operational complexity from premature infrastructure upgrades. Mitigation: keep V1 on MongoDB plus cron dispatcher and postpone workers, queues, and advanced search until measured need exists.

Team & resourcing - Small team - 2 backend engineers, 1 Flutter engineer, 1 product designer, part-time QA, part-time PM

Phase 1: Core Platform Foundation · Weeks 1–4

  • Authentication, refresh, logout, and session revocation
  • College, batch, membership, roles, and permission resolution
  • Shared contracts for errors, enums, permissions, and events
  • Base app shell, login, membership picker, and dashboard shell
  • Health, readiness, config, and maintenance mode endpoints

Phase 2: NSS Activity Workflow · Weeks 5–8

  • Activity creation, submission, approval, rejection, resubmission, and archive
  • Volunteer activity listing and detail screens
  • Registration with capacity checks and idempotency
  • Audit logging for core administrative actions
  • Initial dashboard and leaderboard queries

Phase 3: Attendance, Notifications, and Feedback · Weeks 9–12

  • Activity sessions, QR attendance, Bluetooth verification, and manual bulk attendance
  • Transactional notification creation and cron-based outbox dispatcher
  • Feedback submission and read flows
  • Push notification integration through FCM
  • Admin outbox retry and security-event review screens

Phase 4: Offline and Hardening · Weeks 13–16

  • Isar read cache and pending write queue
  • Stale state indicators and safe retry synchronization
  • Permission-driven UI refinement and error mapping
  • Tenant-isolation, concurrency, and security test coverage
  • Production monitoring, backup/restore test, and release hardening

Paste this into Cursor, Bolt, Lovable, or v0 to start building.

Build a mobile-first NSS operations platform called NSS Nexus.

Tech stack:
Frontend: Flutter, Riverpod, Dio, Freezed, JSON Serializable, Isar, Flutter Secure Storage, Firebase Messaging, Crashlytics, Performance, AutoRoute.
Backend: Node.js, Express, MongoDB, Mongoose, Zod, JWT, bcrypt, Pino, Firebase Admin SDK.
Architecture: modular monolith backend, transactional outbox, cron-based dispatcher in V1, no microservices, no Kafka, no RabbitMQ.

Core product:
A multi-tenant NSS SaaS for colleges with colleges, yearly batches, memberships, roles, permissions, activities, registrations, attendance sessions, attendance attempts, attendance, feedback, forms, notifications, dashboards, leaderboard, announcements, admin tools, audit logs, security logs, offline read cache, and queued offline writes.

Primary flows to implement:
1. Login, refresh, logout, logout-all, session revocation, membership switching.
2. Activity lifecycle: draft, submit, approve, reject, resubmit, archive.
3. Volunteer registration with capacity checks and idempotency.
4. Attendance sessions with QR, Bluetooth, and manual bulk marking.
5. Feedback submission for attendees only.
6. Notification inbox, read state, preferences, and FCM token management.
7. Admin screens for announcements, outbox retries, system config, and security events.
8. Offline mode with Isar cached reads and pending write queue.

Data model to create:
Users, Sessions, Colleges, Batches, Memberships, Projects, Activities, Registrations, ActivitySessions, AttendanceAttempts, Attendance, Feedback, Forms, FormResponses, Notifications, NotificationOutbox, AuditLogs, SecurityEventLogs.
Use publicId fields for user-facing resources and Mongo ObjectIds internally. Make Attendance, Feedback, FormResponses, AuditLogs, SecurityEventLogs, and NotificationOutbox immutable or append-only as appropriate.

Backend requirements:
Implement RequestContext with actor, tenant, resource, and flags.
Enforce server-derived tenant scope and permission-based authorization.
Use MongoDB transactions for critical writes.
Implement a transactional outbox with cron sweep and retry/dead-letter handling.
Add error codes, global error handler, request IDs, health and readiness endpoints, config service, and maintenance mode.

Flutter requirements:
Create a clean feature-based architecture with feature/data, feature/domain, feature/presentation, and feature.dart exports.
Use Riverpod providers, typed failures, permission-driven UI, shared contracts, local caching in Isar, and offline pending actions with idempotency keys.

Screens to scaffold:
Splash, Login, Membership Picker, Dashboard, Activity List, Activity Detail, Create Activity, Approval Queue, Attendance Session, QR Scanner, Manual Attendance, Feedback, Notifications, Notification Preferences, Forms, Members, Permissions, Announcements, Settings, Admin Outbox, Security Events.

Implementation notes:
Keep V1 simple and production-ready. Do not build microservices, distributed locks, a dedicated search engine, payment infrastructure, or generic repository/job frameworks. Prioritize clean state machines, testability, tenant isolation, and reliable notifications.

Business Idea

NSS SaaS Platform — Architecture Specification v13.0 Final This is the final updated architecture plan based on the original v12.4 specification and the architectural review. It preserves the useful parts of the original design while simplifying the infrastructure and correcting the reliability assumptions. The original already had the right foundation: multi-tenant college/batch structure, membership-based RBAC, explicit state transitions, transactions, shared JS/Dart contracts, and layered Flutter architecture. --- 1. Platform Frontend: Flutter mobile application Backend: Node.js + Express Database: MongoDB + Mongoose Authentication: JWT access tokens + hashed refresh tokens Notifications: Firebase Cloud Messaging Cache: Redis-compatible cache Optional in V1 Primary background mechanism: MongoDB Outbox + scheduled cron sweeps Future background mechanism: BullMQ + worker when VPS/managed worker infrastructure exists Observability: Pino backend logging Sentry backend Firebase Crashlytics + Performance on Flutter Deployment: Hostinger Node.js Web App / compatible Node hosting initially VPS later without domain/business-logic changes The application must remain fully functional without a permanently running worker. That is the important hosting constraint, rather than tying the architecture permanently to a particular Hostinger product. --- 2. Core Objective The platform digitizes NSS operations across multiple colleges with: Multi-tenant colleges Yearly batches Membership-based RBAC Dynamic permissions Projects Activities Activity approval workflow Volunteer registration Attendance NSS hours Feedback Dynamic forms Notifications Leaderboards Dashboards Persistent multi-device authentication Audit logging Security event logging Tenant suspension Membership suspension Membership exit Remote announcements Offline read cache Offline write queue Idempotent critical writes Transactional persistence Reliable notification intent Future monetization Future exports/certificates The original specification correctly centered the system around Colleges → Batches → Memberships → Users. --- 3. Core Architectural Principles 3.1 Modular monolith The backend is a modular monolith, not microservices. One Node application │ ├── Auth ├── Colleges ├── Batches ├── Memberships ├── Projects ├── Activities ├── Registration ├── Attendance ├── Feedback ├── Forms ├── Notifications ├── Dashboard ├── Leaderboard ├── Admin └── System No Kafka. No RabbitMQ. No microservices. No distributed architecture until scale genuinely requires it. --- 4. Overall Backend Architecture HTTP Request │ ▼ Global Middleware │ ▼ Authentication │ ▼ Session Guard │ ▼ Tenant / Membership Context │ ▼ Authorization │ ▼ Validation │ ▼ Scope / Resource Loading │ ▼ Controller │ ▼ Domain Service │ ├──────────────► Business Rules │ ├──────────────► Repository / Mongoose │ └──────────────► Domain Events │ ▼ best-effort reactions Critical side effects: Domain Service │ ▼ MongoDB Transaction ├── Domain mutation ├── Notification └── Outbox record │ ▼ COMMIT │ ▼ Cron / Worker Dispatcher │ ▼ External service The critical change from v12.4 is that EventEmitter2 is no longer responsible for guaranteeing critical database side effects. --- 5. Domain Layers Backend follows: Routes ↓ Middleware ↓ Controllers ↓ Domain Services ↓ Business Rules ↓ Repositories / Mongoose ↓ MongoDB Controllers Controllers only: read request validate already-validated input call one domain service return response No business rules. No database orchestration. No direct notifications. --- 6. Business Rules Rules are pure logic. ActivityRules RegistrationRules AttendanceRules FeedbackRules MembershipRules NotificationRules PermissionRules FormRules TenantRules Rules must: contain no database access contain no HTTP logic contain no Firebase calls contain no side effects The original document's separation of Rules and Services is retained. --- 7. Domain Services Core services: AuthService SessionService CollegeService BatchService MembershipService PermissionService ProjectService ActivityLifecycleService RegistrationService AttendanceService AttendanceSessionService FeedbackService FormService FormResponseService NotificationService NotificationDispatchService OutboxService DashboardService LeaderboardService SearchService SystemConfigService AnnouncementService AuditService SecurityEventService Every domain service receives: Service(ctx, payload) but ctx is now split conceptually into actor and tenant information. --- 8. Request Context — Updated Instead of assuming every request has a normal membership, use: RequestContext request requestId traceId ip userAgent timestamp actor userId sessionId membershipId? permissions tenant collegeId? batchId? resource optional loaded resource flags membershipCompleted This is important because SUPER_ADMIN is not always operating through a normal college/batch membership. --- 9. Tenant Model There are three scopes. GLOBAL Users Sessions PermissionRegistry SystemConfig System-level Roles Migrations Seeds TENANT College College-specific Roles Announcements TENANT + BATCH Membership Project Activity Registration Attendance Feedback Forms FormResponses Notifications Every service explicitly knows which scope it operates in. --- 10. Multi-Tenancy Rules Normal users: collegeId = ctx.tenant.collegeId batchId = ctx.tenant.batchId Every tenant-owned query must enforce those scopes. Never trust: collegeId batchId supplied from the Flutter client. The backend derives the authoritative values from the authenticated context. SUPER_ADMIN can operate globally through explicitly authorized administrative paths. --- 11. Shared Contract Package Retain: packages/shared/ js/ errorCodes.js permissionKeys.js eventNames.js featureFlags.js notificationTypes.js auditEvents.js securityEvents.js appConfigKeys.js enums.js dart/ error_codes.dart permission_keys.dart event_names.dart feature_flags.dart notification_types.dart audit_events.dart security_events.dart app_config_keys.dart enums.dart shared_contracts.dart The original shared-contract design is retained. CI verifies that exported keys remain synchronized. Do not over-engineer this into a complicated monorepo build system immediately. --- 12. IDs MongoDB ID Use native MongoDB ObjectId internally. Public ID Use public IDs for user-facing display. Example: USR_xxxxxxxxxx ACT_xxxxxxxxxx MBR_xxxxxxxxxx COL_xxxxxxxxxx Public IDs: are display-safe are stable are not MongoDB lookup keys internally API URL decision Prefer public-facing resource IDs in new public routes where practical: /api/v1/activities/:publicId The service resolves the public ID to the internal ObjectId. If using ObjectId URLs during initial implementation is materially simpler, that is acceptable for V1; the internal database design must not depend on the URL representation. --- 13. Global Schema Convention User-facing/domain collections should contain: publicId createdBy updatedBy createdAt updatedAt Infrastructure collections do not need pointless public IDs. Examples that can remain internal: _migrations _seeds Immutable collections: Attendance Feedback FormResponses AuditLogs SecurityEventLogs NotificationOutbox No update/delete API on immutable records. --- 14. Roles System roles: SUPER_ADMIN PROGRAM_OFFICER UNIT_LEADER PROJECT_LEADER VOLUNTEER New roles can be seeded/created without rewriting the authorization architecture. --- 15. Permission System Permission format: resource.action.scope Examples: activity.create.own activity.create.any activity.read.own activity.read.any activity.update.own activity.update.any activity.approve member.read.any member.manage member.suspend member.exit attendance.mark.manual attendance.mark.qr attendance.mark.bluetooth attendance.read notification.send.batch feedback.submit feedback.read.any form.create form.read.any form.respond form.responses.read report.read report.export No business code should depend on: role === "PROGRAM_OFFICER" unless the operation is genuinely a system-level role exception. The original permission hierarchy remains valid. --- 16. Permission Resolution Effective permissions: (role.permissions ∪ granted) − revoked Membership contains: permissionOverrides granted[] revoked[] permissionsVersion Cache key: membership:{membershipId}:{permissionsVersion} Redis is the preferred cache. An in-process cache may exist as a performance fallback. Correctness must never depend on cache invalidation. Changing permissions increments: permissionsVersion so old cache keys naturally become obsolete. --- 17. Permission Management Rules: SUPER_ADMIN → can modify everyone PROGRAM_OFFICER → UL and below UNIT_LEADER → volunteers only An actor can never grant a permission they themselves don't possess. Cannot modify SUPER_ADMIN permissions through normal permission management. Every permission change: transaction + permissionsVersion increment + audit event + domain event --- 18. Collections Users Users _id publicId name passwordHash accountStatus ACTIVE SUSPENDED accountSuspendedAt accountSuspendedBy accountSuspendReason personal dob sex bloodGroup caste contact phone email address notificationPreferences activityCreated activityReminder approvalUpdates generalAnnouncements createdAt updatedAt Users are permanent identities. Account suspension blocks login across all colleges/batches. --- 19. Sessions Sessions _id publicId userId refreshTokenHash deviceInfo platform model appVersion ip userAgent lastUsedAt revoked revokedAt revokedReason createdAt updatedAt Indexes: unique refreshTokenHash (userId, revoked) (userId, lastUsedAt) Refresh tokens are hashed. --- 20. Colleges Colleges _id publicId name uniqueCode status ACTIVE SUSPENDED ARCHIVED suspendedAt suspendedBy suspendReason createdAt updatedAt Behavior: ACTIVE → normal SUSPENDED → reads allowed → writes blocked except authorized SUPER_ADMIN operations ARCHIVED → operationally inaccessible → data retained --- 21. Batches Batches _id publicId collegeId year active config totalRequiredHours categoryTargets ABP1 ABP2 COLLEGE UNIVERSITY notificationConfig activityCreated activityReminder feedbackConfig enabled requireRating requireComment approvalConfig autoApproveActivities Unique: (collegeId, year) --- 22. Memberships — Core Model Memberships _id publicId userId collegeId batchId roleId roleName nssYear academic class division rollNo yearOfJoining enrollmentId assignedProjectIds[] permissionOverrides granted[] revoked[] status ACTIVE SUSPENDED EXITED COMPLETED suspension suspendedAt suspendedBy suspendReason exit exitedAt exitedBy exitReason exitType hoursAtExit joinedAt version permissionsVersion Indexes: unique(userId, batchId) unique(collegeId, batchId, enrollmentId) only when enrollmentId is present/non-empty (batchId, roleName) (batchId, status) --- 23. Membership State Machine ACTIVE ├──→ SUSPENDED ├──→ EXITED └──→ COMPLETED SUSPENDED ├──→ ACTIVE ├──→ EXITED └──→ COMPLETED EXITED └──→ ACTIVE only SUPER_ADMIN COMPLETED └── terminal/read-only PO cannot: exit PO exit UL suspend PO suspend UL operate outside own batch Past official records remain intact. --- 24. Projects Projects _id publicId collegeId batchId name description active Index: (batchId, active) --- 25. Activities Activities _id publicId title description startDateTime endDateTime location projectId category ABP1 ABP2 COLLEGE UNIVERSITY hours maxParticipants registrationDeadline collegeId batchId version lifecycle status DRAFT PENDING APPROVED REJECTED approvalFlowEnabled approvedBy approvedAt rejectionReason resubmittedFrom revisionCount isArchived archivedAt notificationOverride enabled customMessage reminderMessage feedbackEnabled --- 26. Activity Hours Rule Important NSS rule: hours ≠ duration hours is the officially credited NSS value. It is manually assigned. It is not automatically derived from: endDateTime - startDateTime The original specification explicitly separated these concepts. --- 27. Activity State Machine DRAFT ↓ submit PENDING ├── approve → APPROVED └── reject → REJECTED REJECTED ↓ resubmit DRAFT Optional alternate resubmission: REJECTED ↓ new Activity old Activity → ARCHIVED All transitions happen through: ActivityLifecycleService No controller can directly mutate status. --- 28. Activity Visibility DRAFT creator only PENDING creator + PO + authorized UL/PL APPROVED creator + administrative users + volunteers REJECTED relevant management users Volunteer database query must enforce: status = APPROVED isArchived = false The original visibility model is retained. --- 29. Activity Revision V1: revisionCount resubmittedFrom isArchived Do not build a separate revision collection yet. Later, if detailed revision history becomes necessary: ActivityRevision can be introduced without changing the main activity API. --- 30. Registrations Registrations _id publicId membershipId activityId registeredAt idempotencyKey collegeId batchId Constraints: unique(membershipId, activityId) unique(idempotencyKey) Registration rules: activity approved activity not archived deadline not passed membership ACTIVE capacity available Capacity must be checked atomically. --- 31. Attendance — New Structured Design Instead of treating QR/Bluetooth as merely an Attendance.method, introduce: ActivitySession AttendanceAttempt Attendance This makes attendance much easier to expand later. --- 32. ActivitySession ActivitySessions _id publicId activityId status NOT_STARTED OPEN CLOSED attendanceMode QR BLUETOOTH MANUAL attendanceOpensAt attendanceClosesAt attendanceTokenVersion createdAt updatedAt The entity represents the operational attendance window for the activity. --- 33. AttendanceAttempt Short-lived operational record: AttendanceAttempts _id activitySessionId membershipId method QR BLUETOOTH MANUAL attemptedAt deviceId / session context result ACCEPTED REJECTED DUPLICATE EXPIRED OUTSIDE_WINDOW This can have a short retention period. It is useful for security and troubleshooting. --- 34. Attendance Official immutable record: Attendance _id publicId membershipId activityId activitySessionId status PRESENT ABSENT method QR BLUETOOTH MANUAL markedBy timestamp idempotencyKey collegeId batchId createdAt Unique: (membershipId, activityId, activitySessionId) Attendance remains permanent official data. --- 35. QR Attendance QR should represent a temporary attendance session/token. Example conceptual flow: Leader opens attendance ↓ ActivitySession OPEN ↓ server creates short-lived token ↓ leader displays QR ↓ volunteer scans ↓ server validates token/session ↓ membership eligibility check ↓ Attendance created Never trust the QR alone. The server remains authoritative. --- 36. Bluetooth Attendance Bluetooth is a transport/discovery mechanism, not the attendance authority. Flow: ActivitySession ↓ temporary session identifier ↓ Bluetooth proximity/discovery ↓ Volunteer identifies session ↓ server validation ↓ Attendance record Do not encode trusted attendance information entirely inside the Bluetooth payload. --- 37. Manual Attendance Authorized leader: select activity session ↓ load registered/eligible members ↓ mark present/absent ↓ bulk submission ↓ transaction Bulk attendance must be transactional. --- 38. Feedback Feedback _id publicId activityId membershipId rating comment submittedAt idempotencyKey collegeId batchId Rules: attendance PRESENT membership ACTIVE one feedback per activity Feedback is immutable. --- 39. Dynamic Forms Forms _id publicId title description fields[] label type required options target ROLE BATCH PROJECT linkedTo GENERAL ACTIVITY active allowMultipleSubmissions collegeId batchId Initial field types: text number dropdown checkbox date textarea The original six-field form design is retained. --- 40. Form Responses FormResponses _id publicId formId membershipId responses submittedAt collegeId batchId If: allowMultipleSubmissions = false use a unique constraint: (formId, membershipId) If multiple submissions are allowed, do not enforce that uniqueness. This fixes the ambiguity in the original unconditional-unique-index design. --- 41. Notifications Notifications _id publicId title message type APPROVAL ACTIVITY ATTENDANCE SYSTEM BROADCAST scope BATCH COLLEGE GLOBAL templateKey preferenceKey target type value data requestId collegeId batchId createdAt Instead of an ever-growing readBy[] array for potentially large audiences, prefer a recipient/read model when notification volume grows. V1 can still use readBy[] for small-scale usage if query patterns remain acceptable. --- 42. Notification Delivery Model This is one of the most important changes. The guarantee is: > Exactly-once creation of the logical notification/outbox intent, with at-least-once dispatch attempts and client deduplication. Not exactly-once FCM delivery. --- 43. Transactional Outbox When a business action needs a notification: MongoDB transaction 1. update domain object 2. create Notification 3. create NotificationOutbox COMMIT Example: Approve Activity │ ├── Activity.status = APPROVED ├── Notification = created └── Outbox = created All three succeed or fail together. --- 44. NotificationOutbox NotificationOutbox _id publicId notificationId status PENDING PROCESSING SENT FAILED DEAD attempts nextAttemptAt lastAttemptAt claimedAt lastError sourceEventId requestId createdAt updatedAt Indexes: (status, nextAttemptAt) unique sparse(sourceEventId) sourceEventId prevents duplicate logical outbox creation. --- 45. Outbox Dispatcher V1 Cron ↓ find eligible outbox rows ↓ atomic claim ↓ FCM ↓ mark result No permanent worker required. Later Outbox ↓ BullMQ ↓ Worker ↓ FCM The business transaction remains unchanged. --- 46. Remove FCM From the HTTP Critical Path Do NOT: approve request ↓ wait for FCM ↓ return HTTP response Instead: approve request ↓ Mongo transaction ↓ commit ↓ HTTP success FCM is delivered asynchronously afterwards. This keeps the core API independent of FCM latency. --- 47. Retry Strategy Example: attempt 1 → immediate attempt 2 → 30 sec attempt 3 → 2 min attempt 4 → 10 min attempt 5 → 30 min After configured maximum attempts: DEAD Admin can inspect and retry dead-letter records. --- 48. Notification Deduplication Every logical notification has: notificationId Flutter stores/handles the notification ID and avoids displaying duplicate logical notifications. Thus: server duplicate dispatch does not become: duplicate user-visible notification --- 49. Domain Events Events remain useful, but they are no longer the reliability mechanism for critical persistence. Catalog: activity.created.v1 activity.submitted.v1 activity.approved.v1 activity.rejected.v1 activity.resubmitted.v1 activity.archived.v1 registration.created.v1 attendance.marked.v1 feedback.submitted.v1 membership.roleChanged.v1 membership.permissionChanged.v1 membership.suspended.v1 membership.unsuspended.v1 membership.exited.v1 membership.exitReversed.v1 user.accountSuspended.v1 user.accountUnsuspended.v1 form.responseSubmitted.v1 session.created.v1 session.revoked.v1 systemConfig.changed.v1 Each event contains: eventName eventId occurredAt requestId collegeId? batchId? actorUserId actorMembershipId? data --- 50. Event Bus EventEmitter2 may be retained as a lightweight in-process event bus. Use it for: metrics best-effort logging non-critical cache refresh local application reactions Do not depend on it for durable writes. Do not require an EventEmitter listener to make the core transaction correct. --- 51. Audit Events Audit log is separate from security events. Examples: ACTIVITY_CREATED ACTIVITY_APPROVED ACTIVITY_REJECTED ATTENDANCE_MARKED ATTENDANCE_BULK_MARKED MEMBERSHIP_SUSPENDED MEMBERSHIP_EXITED MEMBERSHIP_EXIT_REVERSED PERMISSION_CHANGED SESSION_REVOKED COLLEGE_SUSPENDED ANNOUNCEMENT_CREATED The original audit catalog is retained conceptually. --- 52. Audit Log AuditLogs _id publicId action performedByUserId performedByMembershipId roleAtAction collegeId batchId entity entityId details requestId ip userAgent createdAt Immutable. No update/delete route. Important historical actor information is stored independently of future membership changes. --- 53. Security Event Log SecurityEventLogs _id eventType userId? ip userAgent requestId details createdAt Examples: FAILED_LOGIN SESSION_REVOKED INVALID_TOKEN PERMISSION_ESCALATION_ATTEMPT RATE_LIMIT_EXCEEDED TENANT_SUSPENDED_WRITE_ATTEMPT MAINTENANCE_MODE_BYPASS_ATTEMPT SUSPENDED_ACCOUNT_LOGIN_ATTEMPT SUSPENDED_MEMBERSHIP_ACCESS_ATTEMPT EXITED_MEMBERSHIP_ACCESS_ATTEMPT CRON_SECRET_MISMATCH --- 54. Authentication Access JWT: short-lived Refresh token: long-lived hashed in database Session: one record per login/device Flow: Login ↓ create Session ↓ issue access JWT ↓ issue refresh token Refresh: verify refresh token ↓ load session ↓ ensure not revoked ↓ issue new access token Support: logout current device logout all devices admin force revoke password change → revoke sessions account suspension → revoke all --- 55. Refresh Token Rotation Prefer refresh-token rotation. old refresh token ↓ validated ↓ revoke/rotate old token ↓ new refresh token Store only hashes. This improves session security without changing the overall architecture. --- 56. Middleware Pipeline Global: requestId logger helmet cors compression request timeout JSON body limit mongo sanitize hpp Per route: 1. authenticate 2. sessionGuard 3. build RequestContext 4. maintenanceGuard 5. tenantSuspensionGuard 6. authorize(permission) 7. validate(Zod) 8. tenant/resource scope validation 9. resource loading 10. visibility/ownership checks 11. lifecycle validation 12. idempotency validation 13. optimistic locking 14. rate limiting 15. feature gate 16. controller 17. domain service The original pipeline is retained conceptually, but durable side effects stay in the service/database transaction rather than middleware. --- 57. Idempotency Critical writes: registration attendance feedback selected administrative actions must accept: Idempotency-Key Pattern: request ↓ idempotency key ↓ existing successful response? yes → return existing result no → execute transaction The database uniqueness constraint remains the final safety mechanism. --- 58. Idempotency Storage Use: short-term cache + database constraint Do not make Redis the sole source of idempotency correctness. If Redis disappears, the DB constraint still prevents duplicate records. --- 59. Optimistic Locking Use version numbers on mutable high-conflict entities: Activity.version Membership.version Flow: client reads version 4 server update where version = 4 success → version 5 someone else already changed: version != 4 → 409 CONCURRENT_MODIFICATION Don't add optimistic locking to every collection just because it is available. --- 60. State Machines Centralize transitions. Activity: VALID_TRANSITIONS Membership: VALID_MEMBERSHIP_TRANSITIONS No arbitrary: model.status = ... outside the relevant domain service. --- 61. Caching Strategy Keep V1 intentionally simple. Backend Primary source: MongoDB Cache only where useful: permissions dashboard leaderboard Redis is an optimization. No correctness may depend on Redis. Flutter Primary local cache: Isar Do not simultaneously build an aggressive Dio cache + Isar cache + separate in-memory cache unless profiling proves the need. --- 62. Search Create: SearchService for genuine search operations: searchActivities searchMembers searchProjects searchNotifications Initial engine: MongoDB Later: Typesense Elasticsearch/OpenSearch can replace the implementation. The original abstraction is retained. --- 63. Pagination Use: Cursor pagination for high-volume feeds: notifications activities members audit logs Use normal page/limit only where a total count is genuinely useful. Avoid calculating expensive total counts on every high-volume endpoint. --- 64. Dashboard Dashboards are derived queries. Do not store dashboard totals as primary data. Examples: Volunteer hours Activity count Attendance Category totals Approval queue Feedback summary Use MongoDB aggregation pipelines. Cache the result temporarily when needed. --- 65. NSS Hours Official hour calculation: Attendance PRESENT ↓ Activity.hours ↓ member total Do not use activity duration. Do not persist total hours as a normal aggregate. Exception: Membership.exit.hoursAtExit This preserves the official point-in-time record when someone exits. The original specification intentionally made hoursAtExit the sole persisted aggregate exception. --- 66. Leaderboard Derived from: Attendance.PRESENT + Activity.hours Sort: hours DESC joinedAt ASC EXITED members: remain visible + Exited badge SUSPENDED members: remain visible according to leaderboard policy Cache briefly. Never treat the cache as source of truth. --- 67. Scheduled Jobs V1 uses hosting cron. Internal services: OutboxSweepService ReminderSweepService RetentionService BackupService One cron entry can trigger: POST /internal/cron/run and execute the required jobs. Or separate cron endpoints can be retained when operational visibility is more useful. --- 68. Reminders On activity approval: Activity approved ↓ calculate reminder time ↓ persist reminder information V1: cron scans approved activities instead of requiring BullMQ delayed jobs. Use: reminderSent or a dedicated reminder record to guarantee one logical reminder. Later: BullMQ delayed job can replace cron scanning. --- 69. FCM Topics Topics: batch_{batchId} role_{roleName}_{batchId} project_{projectId} Topic membership changes on: login membership switch role change project assignment change suspension unsuspension exit account suspension token refresh Rules: SUSPENDED → unsubscribe restricted membership topics UNSUSPENDED → resubscribe ACCOUNT SUSPENDED → unsubscribe all applicable topics Do not use topics as the only source of authorization. The server still decides whether a notification should exist. --- 70. Notification Targeting For important targeted notifications: direct user token For broadcast-like notifications: FCM topic Do not blindly send the same notification to both mechanisms. The notification record must define the authoritative target. --- 71. Notification Preferences Priority: Activity override ↓ Batch configuration ↓ Template default ↓ User preference Preference should always be checked before dispatch unless the notification is explicitly classified as mandatory/system-critical. --- 72. Application Configuration Registry: APP_CONFIG_KEYS MAINTENANCE_MODE MAX_UPLOAD_SIZE_MB FEEDBACK_WINDOW_HOURS ATTENDANCE_QR_EXPIRY_SECONDS MAX_ACTIVITY_HOURS REGISTRATION_CLOSE_BEFORE_MINUTES LEADERBOARD_CACHE_TTL DASHBOARD_CACHE_TTL MAX_FCM_TOKENS_PER_USER All config keys are defined centrally. Never: SystemConfigService.get("randomString") without a registered key. --- 73. Remote Announcements System announcement: title message type active visibleTo startsAt endsAt Returned through: GET /api/v1/app-config Flutter can display without an app release. The original announcement approach is retained. --- 74. Maintenance Mode If enabled: normal users → blocked SUPER_ADMIN → allowed Exceptions: /health /ready /app-config remain accessible. --- 75. Tenant Suspension College: ACTIVE SUSPENDED ARCHIVED Suspended: GET allowed writes blocked SUPER_ADMIN bypass Every blocked write can generate a security event. --- 76. Rate Limits Categories: Login Refresh General Activity management Manual notifications Attendance Reports/export Example policy: Login: strict Refresh: strict General: moderate Attendance: higher Reports: low Manual FCM: low Exact limits should be configurable rather than architectural constants. --- 77. API Error Architecture Base: AppError Hierarchy: ValidationError AuthenticationError AuthorizationError NotFoundError ConflictError BusinessRuleError InfrastructureError Flutter switches on: errorCode never on: message --- 78. API Response Contract Success: { "success": true, "message": "...", "data": {}, "meta": {}, "requestId": "..." } Error: { "success": false, "errorCode": "PERMISSION_DENIED", "message": "...", "details": {}, "requestId": "...", "timestamp": "..." } Version: /api/v1 Backward compatibility: adding fields/endpoints is allowed breaking field removals/renames require a new API version The original error-contract principle is retained. --- 79. Core Error Codes VALIDATION_ERROR PERMISSION_DENIED TENANT_MISMATCH TENANT_SUSPENDED MAINTENANCE_MODE_ACTIVE ACCOUNT_SUSPENDED MEMBERSHIP_SUSPENDED MEMBERSHIP_EXITED MEMBERSHIP_COMPLETED ACTIVITY_FULL REGISTRATION_DEADLINE_PASSED DUPLICATE_SUBMISSION CONCURRENT_MODIFICATION RESOURCE_NOT_FOUND SESSION_REVOKED INVALID_TOKEN INVALID_STATE_TRANSITION ACTIVITY_NOT_APPROVED FEEDBACK_NOT_ELIGIBLE RATE_LIMIT_EXCEEDED EXIT_REASON_REQUIRED CANNOT_EXIT_THIS_ROLE ATTENDANCE_WINDOW_CLOSED ATTENDANCE_TOKEN_EXPIRED ATTENDANCE_ALREADY_MARKED --- 80. Health and Readiness GET /health checks application health. GET /ready reports: Mongo cache FCM configuration cron configuration maintenance state Do not mark the entire application unhealthy merely because optional Redis is unavailable. --- 81. Environment Configuration Required: MONGO_URI JWT_SECRET JWT_REFRESH_SECRET FCM_SERVICE_ACCOUNT CRON_SECRET Optional: REDIS_URL NODE_ENV LOG_LEVEL SENTRY_DSN REQUEST_TIMEOUT_MS DISPATCH_TIMEOUT_MS All environment access is centralized in: ConfigService --- 82. Secrets Never commit: JWT secrets FCM service account database URI cron secret Redis credentials storage credentials Use hosting environment variables/secrets management. --- 83. File Storage Not required for initial V1. When required: StorageService with: S3-compatible storage Cloudflare R2 or equivalent No large file blobs stored directly inside MongoDB. --- 84. Async Exports Don't build the entire generic job system in V1. But design exports as: POST /exports ↓ ExportJob ↓ worker/cron ↓ generate CSV/PDF/XLSX ↓ object storage ↓ notification Large exports should never block an HTTP request. The original async-export direction is retained. --- 85. Data Retention Suggested categories: Sessions → short retention after revocation NotificationOutbox SENT → short retention NotificationOutbox DEAD → longer retention Notifications → defined retention Security events → defined retention Audit logs → longer retention Attendance → indefinite Feedback → indefinite Form responses → indefinite or policy-defined Retention must be policy-driven and configurable. --- 86. Backup Strategy Development: free/development MongoDB tier Pilot: paid database tier Production: database tier with appropriate backup/restore capability Backup: scheduled encrypted off-site versioned Target workflow: MongoDB ↓ backup/export ↓ object storage Most important: periodic restore test A backup that has never been restored should not be considered verified. --- 87. Disaster Recovery Maintain: database backup environment configuration deployment instructions migration files seed files Recovery: restore MongoDB ↓ deploy backend ↓ run/verify migrations ↓ verify health ↓ resume cron --- 88. Database Transactions Use transactions for: registration + capacity activity approval + notification + outbox permission change + permissionsVersion bulk attendance membership exit + hoursAtExit + future registration handling account suspension + session revocation Do not automatically wrap every database read in a transaction. --- 89. Membership Exit On exit: Membership.status = EXITED hoursAtExit = calculated official hours future registrations = cancelled past attendance = retained past feedback = retained past forms = retained The exit itself is transactional. --- 90. Offline Architecture Flutter local storage: Isar Use it for: cached activities membership notifications preferences pending actions --- 91. Offline Reads Read flow: Isar ↓ immediate UI ↓ network refresh ↓ server response ↓ Isar update Show: STALE when cached content is old. --- 92. Offline Writes Do not pretend every write succeeded. Pending action states: PENDING SYNCING SYNCED FAILED_RETRYABLE FAILED_PERMANENT Record: id endpoint method payload idempotencyKey createdAt retryCount lastAttemptAt errorCode serverResponse Idempotency key is generated at the original write, not at retry. The original design already had the correct instinct to persist the idempotency key for offline retries. --- 93. Offline Write Flow User action ↓ generate idempotencyKey ↓ try network │ ├── success → SYNCED │ └── offline → PENDING ↓ reconnect ↓ SYNCING ↓ server response │ ┌──────┴──────┐ ↓ ↓ success failure ↓ ↓ SYNCED retryable/permanent Never silently discard a permanent failure. --- 94. Flutter Architecture Retain: Flutter ├── core ├── shared ├── features ├── gen └── test Feature architecture: feature/ data/ domain/ presentation/ feature.dart This was one of the strongest parts of the original plan. --- 95. Flutter Data Layer data/ datasources/ remote local dtos/ repositories/ implementation Remote datasource: API only Local datasource: Isar only Repository: combines remote/local maps DTO → Entity --- 96. Flutter Domain Layer domain/ entities/ repositories/ usecases/ Entities: pure Dart no JSON annotations Use cases are optional. Do not create: one use case class per trivial method Only introduce a use case where orchestration/logic genuinely benefits from isolation. --- 97. Flutter Presentation presentation/ providers/ screens/ widgets/ State management: Riverpod Prefer: AsyncNotifier Notifier Provider Use generated providers where appropriate. --- 98. Screen Rule Screens are coordinators. Normal screen: loads state routes actions assembles widgets Complex screen: screen ├── header ├── content ├── actions └── sections Do not enforce a rigid 200-line law. Use ~200 lines as a maintainability signal, not a compiler rule. --- 99. Feature Boundary Each feature has: feature.dart which is its public API. Other features should not depend directly on implementation internals. But don't create enormous barrel exports; export only intentionally public classes. --- 100. Core Flutter Structure lib/ main.dart app.dart core/ bootstrap/ di/ network/ storage/ observability/ connectivity/ config/ errors/ extensions/ hooks/ utils/ shared/ design_system/ dashboard_registry/ domain/ widgets/ router/ l10n/ contracts/ features/ auth/ membership/ activities/ attendance/ feedback/ forms/ notifications/ dashboard/ leaderboard/ members/ permissions/ announcements/ settings/ gen/ test/ --- 101. Bootstrap Sequential startup: INITIALIZING 1. RestoreSession 2. RestoreMembership 3. LoadAppConfig 4. LoadEnums 5. Initialize FCM 6. Initialize Crashlytics 7. Load Permissions ↓ READY Other states: LOGIN_REQUIRED MEMBERSHIP_REQUIRED MAINTENANCE SUSPENDED ERROR The ordered bootstrap concept should remain. --- 102. Authentication Bootstrap If JWT exists: validate ↓ expired? ↓ refresh If session is revoked: clear credentials → LOGIN_REQUIRED If account suspended: clear credentials → SUSPENDED --- 103. Membership Switching User may have multiple memberships. Example: College A / Batch 2026 College B / Batch 2027 Only one is active in the current app context. Selecting membership: update active membership ↓ refresh permissions ↓ update FCM topics ↓ update crash context ↓ refresh batch-scoped data --- 104. Permission Provider Everything in the Flutter UI uses: permissionsProvider and: PermissionKeys No widget should ask: roleName == "PO" for ordinary authorization decisions. The server remains the final authority. --- 105. Design System Keep: AppColors AppTypography AppSpacing AppRadius AppShadows Components: AppButton AppCard AppDialog AppTextField AppBadge AppBottomSheet AppSnackbar AppShimmer States: LoadingView ErrorView EmptyView OfflineView The original design-system principle remains strong. --- 106. Dashboard Registry DashboardWidgetDefinition id requiredPermission? priority builder Widgets: hoursProgress categoryChart approvalQueue feedbackInsights formResponses leaderboardPreview memberStatus Dashboard automatically assembles according to available permissions. --- 107. Networking Use Dio. Interceptor sequence: AuthInterceptor RefreshInterceptor IdempotencyInterceptor RetryInterceptor Remove the need for a heavy Dio cache interceptor if Isar is the authoritative client cache layer. --- 108. Request Headers Useful headers: Authorization X-Request-Id X-Membership-Id Idempotency-Key X-Membership-Id identifies the active membership context. The backend verifies that the membership belongs to the authenticated user. --- 109. Retry Interceptor Retry: network failures timeouts selected transient server failures Do not retry blindly: 400 401 403 422 Critical writes only retry when idempotency makes retry safe. --- 110. Local Database Isar models: LocalActivity LocalMembership LocalNotification LocalPreferences LocalPendingAction Potential later models: LocalProject LocalForm LocalLeaderboard Only cache what actually benefits from offline access. --- 111. FCM Flutter Integration FCM handles: foreground notification background notification notification tap token refresh Topic manager handles: membership topic role topic project topic When membership changes: unsubscribe old subscribe new invalidate permissions refresh batch-scoped providers --- 112. Crash Monitoring Flutter: Firebase Crashlytics Firebase Performance Backend: Sentry Pino Avoid duplicate error platforms unless a specific use case justifies them. Every backend error should carry: requestId to correlate with Flutter logs. --- 113. Navigation AutoRoute or equivalent declarative router. Guards: AuthGuard MembershipGuard PermissionGuard MaintenanceGuard Navigation should respond to permissions, not hardcoded role names. --- 114. Full UI Screen Set Authentication Splash Login Membership Picker Session Management Dashboard Volunteer Dashboard PO/UL Dashboard Activity Activity List Activity Detail Create Activity Draft Management Approval Flow Attendance QR Scanner Manual Attendance Attendance Session Feedback Feedback Screen Forms Dynamic Form Form Management Notifications Notification List Notification Preferences Management Member Management Permission Management Reports/system Leaderboard Announcement Management User Account Suspension Settings The original specification's overall 23-screen scope is retained. --- 115. Attendance UX QR: Open scanner ↓ scan ↓ validate ↓ confirm Manual: member list ↓ mark ↓ bulk submit Bluetooth: discover activity session ↓ select ↓ server validation ↓ confirm attendance --- 116. Metadata Endpoint Add: GET /api/v1/metadata or keep metadata inside /app-config. Return: activity categories roles statuses notification types attendance methods membership statuses Flutter can use these for presentation rather than hardcoding every backend enum. Shared contracts still remain authoritative for programmatic enums used by both sides. --- 117. App Config Endpoint GET /api/v1/app-config Response: features appConfig announcement enums minimumSupportedAppVersion? recommendedAppVersion? The version fields can be added later. --- 118. API Endpoints — Core POST /api/v1/auth/login POST /api/v1/auth/refresh POST /api/v1/auth/logout POST /api/v1/auth/logout-all Membership: GET /api/v1/me GET /api/v1/me/memberships GET /api/v1/me/permissions POST /api/v1/me/membership-switch --- 119. Activity Endpoints GET /api/v1/activities POST /api/v1/activities GET /api/v1/activities/:id PATCH /api/v1/activities/:id POST /api/v1/activities/:id/submit POST /api/v1/activities/:id/approve POST /api/v1/activities/:id/reject POST /api/v1/activities/:id/resubmit POST /api/v1/activities/:id/archive Registration: POST /api/v1/activities/:id/register DELETE /api/v1/activities/:id/register --- 120. Attendance Endpoints POST /api/v1/activities/:id/attendance/session POST /api/v1/attendance/qr/verify POST /api/v1/attendance/bluetooth/verify POST /api/v1/activities/:id/attendance/manual POST /api/v1/activities/:id/attendance/bulk GET /api/v1/activities/:id/attendance All writes are server-authoritative. --- 121. Feedback Endpoints POST /api/v1/activities/:id/feedback GET /api/v1/activities/:id/feedback --- 122. Forms Endpoints GET POST PATCH /api/v1/forms GET POST /api/v1/forms/:id/responses --- 123. Member Management GET /api/v1/memberships PATCH /api/v1/memberships/:id/suspend PATCH /api/v1/memberships/:id/unsuspend POST /api/v1/memberships/:id/exit PATCH /api/v1/memberships/:id/exit/reverse Account suspension: PATCH /api/v1/users/:id/account/suspend PATCH /api/v1/users/:id/account/unsuspend --- 124. Notifications GET /api/v1/notifications PATCH /api/v1/notifications/:id/read PATCH /api/v1/notifications/read-all GET /api/v1/notifications/preferences PATCH /api/v1/notifications/preferences FCM token: PUT /api/v1/me/fcm-token DELETE /api/v1/me/fcm-token --- 125. Admin GET/POST/PATCH /api/v1/admin/announcements GET /api/v1/admin/outbox GET /api/v1/admin/security-events GET/PATCH /api/v1/admin/system-config GET /api/v1/admin/users Outbox: POST /api/v1/admin/outbox/:id/retry --- 126. Internal Cron Protected by: X-Cron-Secret Endpoints: POST /internal/cron/run or separate endpoints: /internal/cron/outbox /internal/cron/reminders /internal/cron/retention /internal/cron/backup The single-runner model is preferred for simpler hosting. --- 127. Repository Layer Unlike the earlier plan, do not implement a gigantic generic repository abstraction. Use repositories where they help isolate persistence: ActivityRepository MembershipRepository NotificationRepository OutboxRepository but simple services may use focused Mongoose model operations directly when repository indirection provides no value. This keeps the codebase pragmatic. --- 128. Caching Rule Never write: if cache missing → business behavior changes Correct: if cache available → faster if cache unavailable → MongoDB Cache is never authoritative. --- 129. No Distributed Locks in V1 Avoid: Redlock distributed locking Use MongoDB atomic claims. Example: findOneAndUpdate( { status: PENDING, nextAttemptAt <= now }, { status: PROCESSING, claimedAt: now } ) Only one dispatcher claims a row. --- 130. Exactly-Once vs At-Least-Once — Final Semantics The architecture promises: Database transaction: exactly-once logical state transition Notification creation: exactly-once logical notification intent Outbox: unique logical work item Dispatch: at-least-once attempts FCM: delivery is external and not treated as exactly-once Client: notificationId deduplication This is the correct reliability model. --- 131. Security Baseline Use: helmet CORS policy input size limits Zod Mongo injection sanitization HPP JWT validation refresh-token hashing rate limiting secure secrets audit logging security event logging Passwords: bcrypt or another strong password hashing implementation. Never log: password JWT refresh token FCM service-account credentials --- 132. Tenant Isolation Test Requirement Every tenant-owned endpoint must have tests for: same college/same batch → allowed same college/different batch → blocked different college → blocked SUPER_ADMIN → explicitly allowed where appropriate This should be treated as a security invariant, not just a normal unit test. --- 133. Audit vs Security Audit: who performed a valid business action Security: who attempted something suspicious/invalid Never merge them into one generic log. --- 134. Soft Delete / Retention User: never delete Membership: state machine Activity: archive Project: active=false Form: active=false College: suspend/archive Session: revoke → later delete Notification: retain → retention policy Attendance: immutable Feedback: immutable Audit: immutable Security: immutable --- 135. Monetization Keep future-ready support: BatchSubscription plan features adsEnabled status But V1: all features enabled no payment dependency Feature gates should exist only where they are actually needed. Don't build payment infrastructure yet. --- 136. Feature Registry Initial features: FORMS FEEDBACK LEADERBOARD REPORTS CERTIFICATES AI_INSIGHTS CUSTOM_BRANDING V1 can have these enabled. Later subscription logic can turn features on/off. --- 137. Search Expansion Later When MongoDB search becomes inadequate: SearchService ↓ Typesense/OpenSearch/Elasticsearch Only the implementation changes. The application does not directly depend on the external search provider. --- 138. Exports Later Phase 2: ExportJob Types: CSV Excel PDF attendance report volunteer report hours report activity report Large jobs: generate asynchronously upload notify --- 139. Certificates Later Potential future architecture: CertificateTemplate CertificateJob GeneratedCertificate Storage object Do not make the V1 Activity schema responsible for certificate generation. --- 140. Future Features Deferred: geo-fenced attendance attendance fraud scoring waitlist conditional form fields email notifications email digest certificates bulk import bulk export webhooks university portal AI insights white-label branding advanced metrics The original deferred feature list can remain largely unchanged. --- 141. Testing Architecture Layer 1 — Unit Test: all Rules state machines permission resolution error hierarchy event validation hour calculations attendance validation registration rules Aim for very high coverage on business rules. --- 142. Layer 2 — Integration Use a real Mongo test environment/replica-set-compatible test setup. Test: transactions unique constraints outbox idempotency permission versions membership suspension membership exit tenant isolation attendance activity transitions The original integration-testing emphasis should remain. --- 143. Layer 3 — API Test: authentication authorization tenant isolation error codes pagination validation idempotency version conflicts Especially: ACCOUNT_SUSPENDED MEMBERSHIP_SUSPENDED MEMBERSHIP_EXITED TENANT_MISMATCH CONCURRENT_MODIFICATION INVALID_STATE_TRANSITION --- 144. Layer 4 — E2E Critical journeys: College creation Batch creation User enrollment Membership assignment Login Membership selection Activity creation Activity submission Activity approval Volunteer registration QR attendance Manual attendance Feedback Leaderboard Membership suspension Membership exit Account suspension Notification delivery Offline write synchronization --- 145. Security E2E Scenarios Must specifically test: user from College A attempting College B activity user from Batch A attempting Batch B member suspended account attempting refresh revoked session attempting API request suspended membership attempting attendance exited membership attempting feedback permission escalation attempt forged tenant IDs forged membership ID duplicate idempotency key --- 146. Migration System Keep simple custom migration runner: _migrations filename checksum appliedAt Migrations must be: idempotent ordered checksum tracked Never edit an already-applied migration. Create a new migration. --- 147. Seed System _seeds Initial: permission registry roles super admin notification templates feature registry system config app config keys Seeds must be idempotent. --- 148. ADRs Retain ADRs but update them. Recommended: ADR-001 Membership RBAC ADR-002 Transactional Outbox ADR-003 Public IDs ADR-004 Cron-first dispatch ADR-005 In-process events are non-critical ADR-006 Hosting strategy ADR-007 MongoDB deployment tiers ADR-008 Version-keyed permission cache ADR-009 RequestContext ADR-010 Activity state machine ADR-011 Shared contract package ADR-012 Async exports ADR-013 Search abstraction ADR-014 Suspension model ADR-015 hoursAtExit ADR-016 Flutter feature architecture ADR-017 Feature public boundaries ADR-018 Screen decomposition ADR-019 Offline write queue ADR-020 Attendance session architecture ADR-021 Notification delivery semantics ADR-022 Cache strategy The original ADR-driven approach is worth keeping. --- 149. Build Order — Final Phase 0 — Architecture & Contracts Shared contracts Environment configuration Error codes Permission keys Enums Event schemas Notification types Audit/security catalogs ADR documents --- 150. Phase 1 — Backend Foundation Express ConfigService MongoDB Mongoose MigrationRunner SeedRunner Pino Request IDs Error hierarchy Global error handler Users Sessions Roles Permissions Memberships Auth Login Refresh Logout Session management RequestContext Tenant resolution Permission resolution Health Readiness App config Maintenance mode Tenant suspension Do not start notifications yet. --- 151. Phase 2 — Core NSS Domain Colleges Batches Projects Activities ActivityRules ActivityLifecycleService State machine Activity API Activity queries Activity approval Activity rejection Resubmission Archive At the end of Phase 2, you should be able to perform the basic NSS activity lifecycle without notifications. --- 152. Phase 3 — Transactional Outbox + Notifications Notification model NotificationOutbox model NotificationService OutboxService FCM integration Cron dispatcher Retry Dead-letter handling Notification preferences Notification templates This is now independent of the HTTP request lifecycle. --- 153. Phase 4 — Registration & Attendance Registration Capacity transactions ActivitySession AttendanceAttempt Attendance QR attendance Manual attendance Bluetooth attendance only after QR/manual are stable This order reduces complexity. --- 154. Phase 5 — Feedback & Forms Feedback Feedback eligibility Dynamic forms Form responses Validation Multiple submission behavior --- 155. Phase 6 — Member Management Suspend Unsuspend Exit Reverse exit Account suspension Permissions management FCM topic lifecycle --- 156. Phase 7 — Flutter Foundation Flutter project shared contracts design system Dio secure storage Isar Riverpod routing bootstrap error mapping connectivity FCM Crashlytics --- 157. Phase 8 — Flutter Features Order: Auth Membership Dashboard Activities Registration Attendance Feedback Notifications Forms Leaderboard Members Permissions Announcements Settings Admin --- 158. Phase 9 — Offline Only after online flows are stable: Isar read cache stale indicators connectivity state pending write queue sync engine retry permanent failure UI Don't attempt full offline-first behavior before server flows work correctly. --- 159. Phase 10 — Dashboard & Reporting aggregation pipelines volunteer dashboard PO dashboard UL dashboard leaderboard report endpoints --- 160. Phase 11 — Reliability & Operations cron runner outbox sweeps reminder sweeps retention backup restore testing Sentry rate limits security events admin tools --- 161. Phase 12 — Production Hardening Before real college data: tenant-isolation audit permission audit load testing backup restore test FCM failure testing offline sync testing concurrency testing rate-limit testing security testing session revocation testing --- 162. Phase 13 — Infrastructure Upgrade Only when usage requires it: Managed Redis/Valkey BullMQ Dedicated worker Better MongoDB tier Object storage PM2/Docker Advanced monitoring Application/domain code should not change. Only infrastructure adapters change. --- 163. Later VPS Architecture Flutter ↓ Node API ↓ MongoDB Redis │ ├── cache └── BullMQ ↓ Worker ↓ Outbox ↓ FCM This is the final target architecture without requiring microservices. --- 164. Final Backend Folder Structure backend/ src/ app.js config/ config.service.js env.schema.js middleware/ request-id.js authenticate.js session-guard.js membership-context.js maintenance-guard.js tenant-suspension-guard.js authorize.js validate.js scope-guard.js ownership-guard.js lifecycle-guard.js idempotency.js optimistic-lock.js rate-limit.js feature-gate.js controllers/ routes/ services/ auth/ session/ college/ batch/ membership/ permission/ project/ activity/ registration/ attendance/ feedback/ forms/ notifications/ dashboard/ leaderboard/ search/ system/ rules/ activity.rules.js registration.rules.js attendance.rules.js feedback.rules.js membership.rules.js permission.rules.js notification.rules.js form.rules.js models/ repositories/ only where abstraction is useful events/ event-bus.js catalog.js schemas/ listeners/ outbox/ outbox.service.js outbox.dispatcher.js outbox.sweeper.js notifications/ templates.js fcm.service.js cron/ cron-runner.js outbox-job.js reminder-job.js retention-job.js backup-job.js security/ security-event.service.js audit/ audit.service.js search/ search.service.js errors/ utils/ health/ docs/ adr/ migrations/ seeds/ tests/ --- 165. Final Flutter Folder Structure lib/ main.dart app.dart core/ bootstrap/ di/ network/ storage/ connectivity/ observability/ config/ errors/ extensions/ hooks/ utils/ shared/ design_system/ tokens/ components/ states/ dashboard_registry/ domain/ membership_context.dart permission_checker.dart widgets/ router/ l10n/ contracts/ features/ auth/ membership/ activities/ attendance/ feedback/ forms/ notifications/ dashboard/ leaderboard/ members/ permissions/ announcements/ settings/ gen/ test/ The original three-layer structure remains the foundation. --- 166. Flutter Feature Template Every substantial feature: feature/ data/ datasources/ feature_remote_datasource.dart feature_local_datasource.dart dtos/ feature_dto.dart repositories/ feature_repository_impl.dart domain/ entities/ feature.dart repositories/ feature_repository.dart usecases/ optional presentation/ providers/ feature_provider.dart screens/ feature_screen.dart widgets/ feature.dart --- 167. Flutter Shared State Cross-feature state: membershipContext permissionChecker appConfig connectivity announcement Features should not directly import another feature's internal repository or datasource. --- 168. Flutter Dependency Injection Central: core/di/providers.dart Test overrides: core/di/overrides.dart Providers should not construct their own deep dependencies inline. --- 169. Flutter Error Handling API: HTTP error ↓ Failure(errorCode) ↓ UI mapping Never: if (message == "You are suspended") Use: MEMBERSHIP_SUSPENDED instead. --- 170. Flutter Cache Authority For normal read data: Isar = local cache Server = authority For critical writes: Server = authority Isar = pending/local state This is the final offline consistency model. --- 171. Final Guarantees Backend guarantees Multi-tenant isolation Membership-based authorization Centralized business rules Explicit state machines Transactional critical operations Idempotent critical writes Durable notification intent Outbox retry At-least-once dispatch attempts Client notification deduplication Audit/security separation Server-authoritative permissions Server-authoritative attendance No critical reliance on Redis No critical reliance on EventEmitter2 No critical reliance on FCM availability No worker required for V1 Hosting migration without domain rewrite --- 172. Flutter Guarantees Layered architecture Feature isolation Riverpod state management Shared contract constants Server-authoritative writes Isar read caching Offline write queue Idempotent retries Typed error handling Permission-driven UI Ordered bootstrap Reusable design system Crash reporting Performance tracing --- 173. What Is Explicitly NOT in V1 Do not build: Microservices Kafka RabbitMQ GraphQL Kubernetes Generic repository framework Generic job framework Dedicated search engine Distributed locks Permanent worker requirement Full event-sourcing Complex CQRS UUIDv7 database migration AI analytics Geo-fencing Webhooks Certificate engine White-label engine Payment system The architecture should remain deliberately boring until actual scale demands complexity. --- 174. Final Technology Decision Backend Node.js Express Mongoose MongoDB Zod JWT bcrypt Pino Firebase Admin SDK Redis-compatible cache — optional Background MongoDB Transactional Outbox + Cron Later: BullMQ + Worker Flutter Flutter Riverpod Dio Freezed JSON Serializable Isar Flutter Secure Storage Firebase Messaging Firebase Crashlytics Firebase Performance AutoRoute or equivalent Reactive Forms or equivalent Storage later S3-compatible object storage --- 175. Final Architecture Diagram ┌─────────────────────────┐ │ Flutter │ │ │ │ Riverpod │ │ Isar │ │ Secure Storage │ │ FCM │ │ Crashlytics │ └────────────┬────────────┘ │ HTTPS │ ┌────────────▼────────────┐ │ Express API │ │ │ │ Auth │ │ Tenant Context │ │ RBAC │ │ Validation │ │ Controllers │ └────────────┬────────────┘ │ Domain Services │ ┌────────────▼────────────┐ │ Business Rules │ │ │ │ Activity │ │ Membership │ │ Attendance │ │ Registration │ │ Feedback │ └────────────┬────────────┘ │ MongoDB Transaction │ ┌─────────────────┼─────────────────┐ │ │ │ ▼ ▼ ▼ Domain Notification Outbox Data Data Row │ │ │ └─────────────────┴─────────────────┘ │ COMMIT │ ▼ Cron / Dispatcher │ ┌────────────┴────────────┐ │ │ ▼ ▼ FCM Future BullMQ Worker --- 176. Final Verdict This is the architecture I would actually build. The original v12.4 foundation was already strong, especially around memberships, RBAC, state machines, shared contracts, testing, and Flutter separation. The important changes in v13.0 are: v12.4 EventEmitter2 → critical listener → notification ↓ FCM inline becomes: v13.0 Domain Service ↓ Mongo Transaction ├── domain state ├── notification └── outbox ↓ COMMIT ↓ Cron/Worker ↓ FCM And: "exactly-once FCM" is replaced with: exactly-once logical intent + at-least-once dispatch + notificationId deduplication The other major simplification is: V1: MongoDB + Outbox + Cron V2: MongoDB + Redis + Outbox + BullMQ + Worker rather than building infrastructure in advance. That gives you a production-capable modular monolith, strong tenant isolation, reliable business transactions, a proper NSS attendance model, offline capability, and a clean migration path to VPS infrastructure without prematurely turning the project into an enterprise distributed system.

Make My PRD

Design by The Resonance | Powered by GPC – The AI Transformation Company

    PRD: NSS SaaS Platform — Architecture Specification v13